Merge remote-tracking branch 'shyotl/future' into AltCompilers

Conflicts:
	indra/llrender/llrendertarget.cpp
	indra/newview/llvovolume.cpp
This commit is contained in:
Drake Arconis
2012-08-08 18:54:04 -04:00
82 changed files with 2312 additions and 1578 deletions

View File

@@ -2001,7 +2001,6 @@ BOOL LLImageGL::getMask(const LLVector2 &tc)
void LLImageGL::setCategory(S32 category)
{
#if 0 //turn this off temporarily because it is not in use now.
if(!gAuditTexture)
{
return ;
@@ -2022,7 +2021,6 @@ void LLImageGL::setCategory(S32 category)
mCategory = -1 ;
}
}
#endif
}
//for debug use
@@ -2053,14 +2051,16 @@ S32 LLImageGL::getTextureCounterIndex(U32 val)
void LLImageGL::incTextureCounter(U32 val, S32 ncomponents, S32 category)
{
sTextureLoadedCounter[getTextureCounterIndex(val)]++ ;
sTextureMemByCategory[category] += (S32)val * ncomponents ;
if(category > -1)
sTextureMemByCategory[category] += (S32)val * ncomponents ;
}
//static
void LLImageGL::decTextureCounter(U32 val, S32 ncomponents, S32 category)
{
sTextureLoadedCounter[getTextureCounterIndex(val)]-- ;
sTextureMemByCategory[category] += (S32)val * ncomponents ;
if(category > -1)
sTextureMemByCategory[category] -= (S32)val * ncomponents ;
}
void LLImageGL::setCurTexSizebar(S32 index, BOOL set_pick_size)

View File

@@ -33,34 +33,247 @@
#include "linden_common.h"
#include "llpostprocess.h"
#include "llglslshader.h"
#include "llsdserialize.h"
#include "llrender.h"
#include "llvertexbuffer.h"
#include "lldir.h"
#include "llgl.h"
#include "llglslshader.h"
#include "llrender.h"
#include "llsdserialize.h"
#include "llsdutil.h"
#include "llsdutil_math.h"
#include "llvertexbuffer.h"
#include "llfasttimer.h"
extern LLGLSLShader gPostColorFilterProgram;
extern LLGLSLShader gPostNightVisionProgram;
extern LLGLSLShader gPostGaussianBlurProgram;
extern LLGLSLShader gPostPosterizeProgram;
static const unsigned int NOISE_SIZE = 512;
/// CALCULATING LUMINANCE (Using NTSC lum weights)
/// http://en.wikipedia.org/wiki/Luma_%28video%29
static const float LUMINANCE_R = 0.299f;
static const float LUMINANCE_G = 0.587f;
static const float LUMINANCE_B = 0.114f;
static const char * const XML_FILENAME = "postprocesseffects.xml";
LLPostProcess::LLPostProcess(void) :
mVBO(NULL),
mAllEffects(LLSD::emptyMap()),
mScreenWidth(1), mScreenHeight(1)
template<> LLSD LLPostProcessShader::LLShaderSetting<LLVector4>::getDefaultValue()
{
mSceneRenderTexture = NULL ;
mNoiseTexture = NULL ;
return mDefault.getValue();
}
template<> void LLPostProcessShader::LLShaderSetting<LLVector4>::setValue(const LLSD& value)
{
mValue = ll_vector4_from_sd(value);
}
LLSD LLPostProcessShader::getDefaults()
{
LLSD defaults;
for(std::vector<LLShaderSettingBase*>::iterator it=mSettings.begin();it!=mSettings.end();++it)
{
defaults[(*it)->mSettingName]=(*it)->getDefaultValue();
}
return defaults;
}
void LLPostProcessShader::loadSettings(const LLSD& settings)
{
for(std::vector<LLShaderSettingBase*>::iterator it=mSettings.begin();it!=mSettings.end();++it)
{
LLSD value = settings[(*it)->mSettingName];
(*it)->setValue(value);
}
}
class LLColorFilterShader : public LLPostProcessShader
{
private:
LLShaderSetting<bool> mEnabled;
LLShaderSetting<F32> mGamma, mBrightness, mContrast, mSaturation;
LLShaderSetting<LLVector4> mContrastBase;
public:
LLColorFilterShader() :
mEnabled("enable_color_filter",false),
mGamma("gamma",1.f),
mBrightness("brightness",1.f),
mContrast("contrast",1.f),
mSaturation("saturation",1.f),
mContrastBase("contrast_base",LLVector4(1.f,1.f,1.f,0.5f))
{
mSettings.push_back(&mEnabled);
mSettings.push_back(&mGamma);
mSettings.push_back(&mBrightness);
mSettings.push_back(&mContrast);
mSettings.push_back(&mSaturation);
mSettings.push_back(&mContrastBase);
}
bool isEnabled() { return mEnabled && gPostColorFilterProgram.mProgramObject; }
S32 getColorChannel() { return 0; }
S32 getDepthChannel() { return -1; }
QuadType bind()
{
if(!isEnabled())
return QUAD_NONE;
/// CALCULATING LUMINANCE (Using NTSC lum weights)
/// http://en.wikipedia.org/wiki/Luma_%28video%29
static const float LUMINANCE_R = 0.299f;
static const float LUMINANCE_G = 0.587f;
static const float LUMINANCE_B = 0.114f;
gPostColorFilterProgram.bind();
gPostColorFilterProgram.uniform1f("gamma", mGamma);
gPostColorFilterProgram.uniform1f("brightness", mBrightness);
gPostColorFilterProgram.uniform1f("contrast", mContrast);
float baseI = (mContrastBase.mValue[VX] + mContrastBase.mValue[VY] + mContrastBase.mValue[VZ]) / 3.0f;
baseI = mContrastBase.mValue[VW] / ((baseI < 0.001f) ? 0.001f : baseI);
float baseR = mContrastBase.mValue[VX] * baseI;
float baseG = mContrastBase.mValue[VY] * baseI;
float baseB = mContrastBase.mValue[VZ] * baseI;
gPostColorFilterProgram.uniform3fv("contrastBase", 1, LLVector3(baseR, baseG, baseB).mV);
gPostColorFilterProgram.uniform1f("saturation", mSaturation);
gPostColorFilterProgram.uniform3fv("lumWeights", 1, LLVector3(LUMINANCE_R, LUMINANCE_G, LUMINANCE_B).mV);
return QUAD_NORMAL;
}
bool draw(U32 pass) {return pass == 1;}
void unbind()
{
gPostColorFilterProgram.unbind();
}
};
class LLNightVisionShader : public LLPostProcessShader
{
private:
LLShaderSetting<bool> mEnabled;
LLShaderSetting<F32> mBrightnessMult, mNoiseStrength;
public:
LLNightVisionShader() :
mEnabled("enable_night_vision",false),
mBrightnessMult("brightness_multiplier",3.f),
mNoiseStrength("noise_strength",.4f)
{
mSettings.push_back(&mEnabled);
mSettings.push_back(&mBrightnessMult);
mSettings.push_back(&mNoiseStrength);
}
bool isEnabled() { return mEnabled && gPostNightVisionProgram.mProgramObject; }
S32 getColorChannel() { return 0; }
S32 getDepthChannel() { return -1; }
QuadType bind()
{
if(!isEnabled())
return QUAD_NONE;
gPostNightVisionProgram.bind();
LLPostProcess::getInstance()->bindNoise(1);
gPostNightVisionProgram.uniform1f("brightMult", mBrightnessMult);
gPostNightVisionProgram.uniform1f("noiseStrength", mNoiseStrength);
return QUAD_NOISE;
}
bool draw(U32 pass) {return pass == 1;}
void unbind()
{
gPostNightVisionProgram.unbind();
}
};
class LLGaussBlurShader : public LLPostProcessShader
{
private:
LLShaderSetting<bool> mEnabled;
LLShaderSetting<S32> mNumPasses;
GLint mPassLoc;
public:
LLGaussBlurShader() :
mEnabled("enable_gauss_blur",false),
mNumPasses("gauss_blur_passes",2),
mPassLoc(0)
{
mSettings.push_back(&mEnabled);
mSettings.push_back(&mNumPasses);
}
bool isEnabled() { return mEnabled && mNumPasses && gPostGaussianBlurProgram.mProgramObject; }
S32 getColorChannel() { return 0; }
S32 getDepthChannel() { return -1; }
QuadType bind()
{
if(!isEnabled())
return QUAD_NONE;
gPostGaussianBlurProgram.bind();
mPassLoc = gPostGaussianBlurProgram.getUniformLocation("horizontalPass");
return QUAD_NORMAL;
}
bool draw(U32 pass)
{
if((S32)pass > mNumPasses*2)
return false;
glUniform1iARB(mPassLoc, (pass-1) % 2);
return true;
}
void unbind()
{
gPostGaussianBlurProgram.unbind();
}
};
class LLPosterizeShader : public LLPostProcessShader
{
private:
LLShaderSetting<bool> mEnabled;
LLShaderSetting<S32> mNumLayers;
public:
LLPosterizeShader() :
mEnabled("enable_posterize",false),
mNumLayers("posterize_layers",2)
{
mSettings.push_back(&mEnabled);
mSettings.push_back(&mNumLayers);
}
bool isEnabled() { return mEnabled && gPostPosterizeProgram.mProgramObject; }
S32 getColorChannel() { return 0; }
S32 getDepthChannel() { return -1; }
QuadType bind()
{
if(!isEnabled())
return QUAD_NONE;
gPostPosterizeProgram.bind();
gPostPosterizeProgram.uniform1i("layerCount", mNumLayers);
return QUAD_NORMAL;
}
bool draw(U32 pass)
{
return pass == 1;
}
void unbind()
{
gPostPosterizeProgram.unbind();
}
};
LLPostProcess::LLPostProcess(void) :
mVBO(NULL),
mDepthTexture(0),
mNoiseTexture(NULL),
mScreenWidth(0),
mScreenHeight(0),
mNoiseTextureScale(0.f),
mSelectedEffectInfo(LLSD::emptyMap()),
mAllEffectInfo(LLSD::emptyMap())
{
mShaders.push_back(new LLColorFilterShader());
mShaders.push_back(new LLNightVisionShader());
mShaders.push_back(new LLGaussBlurShader());
mShaders.push_back(new LLPosterizeShader());
/* Do nothing. Needs to be updated to use our current shader system, and to work with the move into llrender.*/
std::string pathName(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight", XML_FILENAME));
LL_DEBUGS2("AppInit", "Shaders") << "Loading PostProcess Effects settings from " << pathName << LL_ENDL;
@@ -71,99 +284,43 @@ LLPostProcess::LLPostProcess(void) :
{
LLPointer<LLSDParser> parser = new LLSDXMLParser();
parser->parse(effectsXML, mAllEffects, LLSDSerialize::SIZE_UNLIMITED);
parser->parse(effectsXML, mAllEffectInfo, LLSDSerialize::SIZE_UNLIMITED);
}
if (!mAllEffects.has("default"))
if (!mAllEffectInfo.has("default"))
mAllEffectInfo["default"] = LLSD::emptyMap();
LLSD& defaults = mAllEffectInfo["default"];
for(std::list<LLPointer<LLPostProcessShader> >::iterator it=mShaders.begin();it!=mShaders.end();++it)
{
LLSD & defaultEffect = (mAllEffects["default"] = LLSD::emptyMap());
/*defaultEffect["enable_night_vision"] = LLSD::Boolean(false);
defaultEffect["enable_color_filter"] = LLSD::Boolean(false);*/
/// NVG Defaults
defaultEffect["brightness_multiplier"] = 3.0;
defaultEffect["noise_size"] = 25.0;
defaultEffect["noise_strength"] = 0.4;
// TODO BTest potentially add this to tweaks?
mNoiseTextureScale = 1.0f;
/// Color Filter Defaults
defaultEffect["gamma"] = 1.0;
defaultEffect["brightness"] = 1.0;
defaultEffect["contrast"] = 1.0;
defaultEffect["saturation"] = 1.0;
LLSD& contrastBase = (defaultEffect["contrast_base"] = LLSD::emptyArray());
contrastBase.append(1.0);
contrastBase.append(1.0);
contrastBase.append(1.0);
contrastBase.append(0.5);
defaultEffect["gauss_blur_passes"] = 2;
LLSD shader_defaults = (*it)->getDefaults();
for (LLSD::map_const_iterator it2 = defaults.beginMap();it2 != defaults.endMap();++it2)
{
if(!defaults.has(it2->first))
defaults[it2->first]=it2->second;
}
}
for(std::list<LLPointer<LLPostProcessShader> >::iterator it=mShaders.begin();it!=mShaders.end();++it)
{
(*it)->loadSettings(defaults);
}
setSelectedEffect("default");
// */
}
LLPostProcess::~LLPostProcess(void)
{
invalidate() ;
}
/*static*/void LLPostProcess::cleanupClass()
{
if(instanceExists())
getInstance()->invalidate() ;
}
void LLPostProcess::setSelectedEffect(std::string const & effectName)
{
mSelectedEffectName = effectName;
static_cast<LLSD &>(tweaks) = mAllEffects[effectName];
}
void LLPostProcess::saveEffect(std::string const & effectName)
{
mAllEffects[effectName] = tweaks;
std::string pathName(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight", XML_FILENAME));
//llinfos << "Saving PostProcess Effects settings to " << pathName << llendl;
llofstream effectsXML(pathName);
LLPointer<LLSDFormatter> formatter = new LLSDXMLFormatter();
formatter->format(mAllEffects, effectsXML);
}
void LLPostProcess::invalidate()
{
mSceneRenderTexture = NULL ;
mNoiseTexture = NULL ;
mVBO = NULL ;
}
void LLPostProcess::apply(unsigned int width, unsigned int height)
{
if(shadersEnabled())
{
if (mVBO.isNull() || width != mScreenWidth || height != mScreenHeight)
{
initialize(width, height);
}
doEffects();
}
destroyGL() ;
}
void LLPostProcess::initialize(unsigned int width, unsigned int height)
{
invalidate();
destroyGL();
mScreenWidth = width;
mScreenHeight = height;
createScreenTexture();
createScreenTextures();
createNoiseTexture();
//Setup our VBO.
{
@@ -185,127 +342,129 @@ void LLPostProcess::initialize(unsigned int width, unsigned int height)
mVBO->flush();
}
checkError();
createNoiseTexture();
checkError();
stop_glerror();
}
inline bool LLPostProcess::shadersEnabled(void)
void LLPostProcess::createScreenTextures()
{
return (tweaks.useColorFilter().asBoolean() ||
tweaks.useNightVisionShader().asBoolean() ||
tweaks.useGaussBlurFilter().asBoolean() );
}
const LLTexUnit::eTextureType type = LLTexUnit::TT_RECT_TEXTURE;
void LLPostProcess::applyShaders(void)
{
bool copy_buffer = false;
if (tweaks.useColorFilter())
mRenderTarget[0].allocate(mScreenWidth,mScreenHeight,GL_RGBA,FALSE,FALSE,type,FALSE);
if(mRenderTarget[0].getFBO())//Only need pingpong between two rendertargets if FBOs are supported.
mRenderTarget[1].allocate(mScreenWidth,mScreenHeight,GL_RGBA,FALSE,FALSE,type,FALSE);
stop_glerror();
if(mDepthTexture)
LLImageGL::deleteTextures(type, 0, 0, 1, &mDepthTexture, true);
for(std::list<LLPointer<LLPostProcessShader> >::iterator it=mShaders.begin();it!=mShaders.end();++it)
{
applyColorFilterShader();
checkError();
copy_buffer = true;
}
if (tweaks.useGaussBlurFilter())
{
/// If any of the above shaders have been called update the frame buffer;
if (copy_buffer)
copyFrameBuffer();
applyGaussBlurShader();
checkError();
copy_buffer = true;
}
if (tweaks.useNightVisionShader())
{
/// If any of the above shaders have been called update the frame buffer;
if (copy_buffer)
copyFrameBuffer();
applyNightVisionShader();
checkError();
copy_buffer = true;
}
}
void LLPostProcess::applyColorFilterShader(void)
{
if(gPostColorFilterProgram.mProgramObject == 0)
return;
gPostColorFilterProgram.bind();
gGL.getTexUnit(0)->bind(mSceneRenderTexture);
gPostColorFilterProgram.uniform1f("gamma", tweaks.getGamma());
gPostColorFilterProgram.uniform1f("brightness", tweaks.getBrightness());
gPostColorFilterProgram.uniform1f("contrast", tweaks.getContrast());
float baseI = (tweaks.getContrastBaseR() + tweaks.getContrastBaseG() + tweaks.getContrastBaseB()) / 3.0f;
baseI = tweaks.getContrastBaseIntensity() / ((baseI < 0.001f) ? 0.001f : baseI);
float baseR = tweaks.getContrastBaseR() * baseI;
float baseG = tweaks.getContrastBaseG() * baseI;
float baseB = tweaks.getContrastBaseB() * baseI;
gPostColorFilterProgram.uniform3fv("contrastBase", 1, LLVector3(baseR, baseG, baseB).mV);
gPostColorFilterProgram.uniform1f("saturation", tweaks.getSaturation());
gPostColorFilterProgram.uniform3fv("lumWeights", 1, LLVector3(LUMINANCE_R, LUMINANCE_G, LUMINANCE_B).mV);
/// Draw a screen space quad
drawOrthoQuad(QUAD_NORMAL);
gPostColorFilterProgram.unbind();
}
void LLPostProcess::applyNightVisionShader(void)
{
if(gPostNightVisionProgram.mProgramObject == 0)
return;
gPostNightVisionProgram.bind();
gGL.getTexUnit(0)->bind(mSceneRenderTexture);
gGL.getTexUnit(1)->bind(mNoiseTexture);
gPostNightVisionProgram.uniform1f("brightMult", tweaks.getBrightMult());
gPostNightVisionProgram.uniform1f("noiseStrength", tweaks.getNoiseStrength());
mNoiseTextureScale = 0.001f + ((100.f - tweaks.getNoiseSize()) / 100.f);
mNoiseTextureScale *= (mScreenHeight / NOISE_SIZE);
/// Draw a screen space quad
drawOrthoQuad(QUAD_NOISE);
gPostNightVisionProgram.unbind();
}
void LLPostProcess::applyGaussBlurShader(void)
{
int pass_count = tweaks.getGaussBlurPasses();
if(!pass_count || gPostGaussianBlurProgram.mProgramObject == 0)
return;
gPostGaussianBlurProgram.bind();
gGL.getTexUnit(0)->bind(mSceneRenderTexture);
GLint horiz_pass = gPostGaussianBlurProgram.getUniformLocation("horizontalPass");
for(int i = 0;i<pass_count;++i)
{
for(int j = 0;j<2;++j)
if((*it)->getDepthChannel()>=0)
{
if(i || j)
copyFrameBuffer();
glUniform1iARB(horiz_pass, j);
drawOrthoQuad(QUAD_NORMAL);
LLImageGL::generateTextures(type, GL_DEPTH_COMPONENT24, 1, &mDepthTexture);
gGL.getTexUnit(0)->bindManual(type, mDepthTexture);
LLImageGL::setManualImage(LLTexUnit::getInternalType(type), 0, GL_DEPTH_COMPONENT24, mScreenWidth, mScreenHeight, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL, false);
stop_glerror();
gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
stop_glerror();
break;
}
}
}
void LLPostProcess::createNoiseTexture()
{
std::vector<GLubyte> buffer(NOISE_SIZE * NOISE_SIZE);
for (unsigned int i = 0; i < NOISE_SIZE; i++){
for (unsigned int k = 0; k < NOISE_SIZE; k++){
buffer[(i * NOISE_SIZE) + k] = (GLubyte)((double) rand() / ((double) RAND_MAX + 1.f) * 255.f);
}
}
mNoiseTexture = new LLImageGL(FALSE) ;
if(mNoiseTexture->createGLTexture())
{
gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mNoiseTexture->getTexName());
LLImageGL::setManualImage(GL_TEXTURE_2D, 0, GL_LUMINANCE, NOISE_SIZE, NOISE_SIZE, GL_LUMINANCE, GL_UNSIGNED_BYTE, &buffer[0]);
stop_glerror();
gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_WRAP);
stop_glerror();
}
}
void LLPostProcess::destroyGL()
{
mRenderTarget[0].release();
mRenderTarget[1].release();
if(mDepthTexture)
LLImageGL::deleteTextures(LLTexUnit::TT_RECT_TEXTURE, 0, 0, 1, &mDepthTexture, true);
mDepthTexture=0;
mNoiseTexture = NULL ;
mVBO = NULL ;
}
/*static*/void LLPostProcess::cleanupClass()
{
if(instanceExists())
getInstance()->destroyGL() ;
}
void LLPostProcess::copyFrameBuffer()
{
mRenderTarget[!!mRenderTarget[0].getFBO()].bindTexture(0,0);
glCopyTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB,0,0,0,0,0,mScreenWidth, mScreenHeight);
if(mDepthTexture)
{
for(std::list<LLPointer<LLPostProcessShader> >::iterator it=mShaders.begin();it!=mShaders.end();++it)
{
if((*it)->isEnabled() && (*it)->getDepthChannel()>=0)
{
gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_RECT_TEXTURE, mDepthTexture);
glCopyTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB,0,0,0,0,0,mScreenWidth, mScreenHeight);
break;
}
}
}
}
void LLPostProcess::bindNoise(U32 channel)
{
gGL.getTexUnit(channel)->bind(mNoiseTexture);
}
void LLPostProcess::renderEffects(unsigned int width, unsigned int height)
{
for(std::list<LLPointer<LLPostProcessShader> >::iterator it=mShaders.begin();it!=mShaders.end();++it)
{
if((*it)->isEnabled())
{
if (mVBO.isNull() || width != mScreenWidth || height != mScreenHeight)
{
initialize(width, height);
}
doEffects();
return;
}
}
gPostGaussianBlurProgram.unbind();
}
void LLPostProcess::doEffects(void)
{
LLVertexBuffer::unbind();
mNoiseTextureScale = 0.001f + ((100.f - mSelectedEffectInfo["noise_size"].asFloat()) / 100.f);
mNoiseTextureScale *= (mScreenHeight / NOISE_SIZE);
/// Copy the screen buffer to the render texture
copyFrameBuffer();
stop_glerror();
//Disable depth. Set blendmode to replace.
LLGLDepthTest depth(GL_FALSE);
LLGLDepthTest depth(GL_FALSE,GL_FALSE);
LLGLEnable blend(GL_BLEND);
gGL.setSceneBlendType(LLRender::BT_REPLACE);
@@ -319,7 +478,6 @@ void LLPostProcess::doEffects(void)
gGL.loadIdentity();
applyShaders();
checkError();
LLGLSLShader::bindNoShader();
@@ -333,13 +491,46 @@ void LLPostProcess::doEffects(void)
gGL.setSceneBlendType(LLRender::BT_ALPHA); //Restore blendstate. Alpha is ASSUMED for hud/ui render, etc.
gGL.getTexUnit(1)->disable();
checkError();
}
void LLPostProcess::copyFrameBuffer()
void LLPostProcess::applyShaders(void)
{
gGL.getTexUnit(0)->bindManual(mSceneRenderTexture->getTarget(), mSceneRenderTexture->getTexName());
glCopyTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, 0, 0, mScreenWidth, mScreenHeight, 0);
QuadType quad;
bool primary_rendertarget = 1;
for(std::list<LLPointer<LLPostProcessShader> >::iterator it=mShaders.begin();it!=mShaders.end();++it)
{
if((quad = (*it)->bind()) != QUAD_NONE)
{
S32 color_channel = (*it)->getColorChannel();
S32 depth_channel = (*it)->getDepthChannel();
if(depth_channel >= 0)
gGL.getTexUnit(depth_channel)->bindManual(LLTexUnit::TT_RECT_TEXTURE, mDepthTexture);
U32 pass = 1;
while((*it)->draw(pass++))
{
mRenderTarget[!primary_rendertarget].bindTarget();
if(color_channel >= 0)
mRenderTarget[mRenderTarget[0].getFBO() ? primary_rendertarget : !primary_rendertarget].bindTexture(0,color_channel);
drawOrthoQuad(quad);
mRenderTarget[!primary_rendertarget].flush();
if(mRenderTarget[0].getFBO())
primary_rendertarget = !primary_rendertarget;
}
(*it)->unbind();
}
}
//Only need to copy to framebuffer if FBOs are supported, else we've already been drawing to the framebuffer to begin with.
if(mRenderTarget[0].getFBO())
{
//copyContentsToFramebuffer also binds the main framebuffer.
LLRenderTarget::copyContentsToFramebuffer(mRenderTarget[primary_rendertarget],0,0,mScreenWidth,mScreenHeight,0,0,mScreenWidth,mScreenHeight,GL_COLOR_BUFFER_BIT, GL_NEAREST);
}
stop_glerror();
}
void LLPostProcess::drawOrthoQuad(QuadType type)
@@ -364,64 +555,59 @@ void LLPostProcess::drawOrthoQuad(QuadType type)
mVBO->drawArrays(LLRender::TRIANGLE_STRIP, 0, 4);
}
void LLPostProcess::createScreenTexture()
void LLPostProcess::setSelectedEffect(std::string const & effectName)
{
std::vector<GLubyte> data(mScreenWidth * mScreenHeight * 3, 0) ;
mSceneRenderTexture = new LLImageGL(FALSE) ;
if(mSceneRenderTexture->createGLTexture())
mSelectedEffectName = effectName;
mSelectedEffectInfo = mAllEffectInfo[effectName];
for(std::list<LLPointer<LLPostProcessShader> >::iterator it=mShaders.begin();it!=mShaders.end();++it)
{
gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_RECT_TEXTURE, mSceneRenderTexture->getTexName());
LLImageGL::setManualImage(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGB, mScreenWidth, mScreenHeight, GL_RGB, GL_UNSIGNED_BYTE, &data[0]);
gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
(*it)->loadSettings(mSelectedEffectInfo);
}
}
void LLPostProcess::createNoiseTexture()
{
std::vector<GLubyte> buffer(NOISE_SIZE * NOISE_SIZE);
for (unsigned int i = 0; i < NOISE_SIZE; i++){
for (unsigned int k = 0; k < NOISE_SIZE; k++){
buffer[(i * NOISE_SIZE) + k] = (GLubyte)((double) rand() / ((double) RAND_MAX + 1.f) * 255.f);
}
}
mNoiseTexture = new LLImageGL(FALSE) ;
if(mNoiseTexture->createGLTexture())
{
gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mNoiseTexture->getTexName());
LLImageGL::setManualImage(GL_TEXTURE_2D, 0, GL_LUMINANCE, NOISE_SIZE, NOISE_SIZE, GL_LUMINANCE, GL_UNSIGNED_BYTE, &buffer[0]);
gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_WRAP);
}
}
bool LLPostProcess::checkError(void)
void LLPostProcess::setSelectedEffectValue(std::string const & setting, LLSD& value)
{
GLenum glErr;
bool retCode = false;
glErr = glGetError();
while (glErr != GL_NO_ERROR)
{
// shaderErrorLog << (const char *) gluErrorString(glErr) << std::endl;
char const * err_str_raw = (const char *) gluErrorString(glErr);
if(err_str_raw == NULL)
{
std::ostringstream err_builder;
err_builder << "unknown error number " << glErr;
mShaderErrorString = err_builder.str();
}
else
{
mShaderErrorString = err_str_raw;
}
retCode = true;
glErr = glGetError();
}
return retCode;
char buf[256];
S32 elem=0;
if(sscanf(setting.c_str(),"%255[^[][%d]", buf, &elem) == 2)
{
mSelectedEffectInfo[buf][elem] = value;
}
else
{
mSelectedEffectInfo[setting] = value;
}
for(std::list<LLPointer<LLPostProcessShader> >::iterator it=mShaders.begin();it!=mShaders.end();++it)
{
(*it)->loadSettings(mSelectedEffectInfo);
}
}
void LLPostProcess::resetSelectedEffect()
{
if(!llsd_equals(mAllEffectInfo[mSelectedEffectName], mSelectedEffectInfo))
{
mSelectedEffectInfo = mAllEffectInfo[mSelectedEffectName];
for(std::list<LLPointer<LLPostProcessShader> >::iterator it=mShaders.begin();it!=mShaders.end();++it)
{
(*it)->loadSettings(mSelectedEffectInfo);
}
}
}
void LLPostProcess::saveEffectAs(std::string const & effectName)
{
mAllEffectInfo[effectName] = mSelectedEffectInfo;
std::string pathName(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight", XML_FILENAME));
//llinfos << "Saving PostProcess Effects settings to " << pathName << llendl;
llofstream effectsXML(pathName);
LLPointer<LLSDFormatter> formatter = new LLSDXMLFormatter();
formatter->format(mAllEffectInfo, effectsXML);
}

View File

@@ -34,189 +34,123 @@
#define LL_POSTPROCESS_H
#include <map>
#include <fstream>
#include "llgl.h"
#include "llglheaders.h"
#include "llsd.h"
#include "llrendertarget.h"
class LLSD;
typedef enum _QuadType {
QUAD_NONE,
QUAD_NORMAL,
QUAD_NOISE
} QuadType;
//LLPostProcessShader is an attempt to encapsulate the shaders a little better.
class LLPostProcessShader : public LLRefCount //Abstract. PostProcess shaders derive off of this common base.
{
protected:
//LLShaderSetting is used to associate key names to member variables to avoid LLSD lookups when drawing.
//It also facilitates automating the assigning of defaults to, as well as parsing from, the effects LLSD list.
//This replaces the entire old PostProcessTweaks structure. More will be done in the future to move into a more
//xml-driven configuration.
struct LLShaderSettingBase
{
LLShaderSettingBase(const char* name) : mSettingName(name) {}
const char* mSettingName; //LLSD key names as found in postprocesseffects.xml. eg 'contrast_base'
virtual LLSD getDefaultValue() = 0; //Converts the member variable as an LLSD. Used to set defaults absent in postprocesseffects.xml
virtual void setValue(const LLSD& value) = 0; //Connects the LLSD element to the member variable. Used when loading effects (such as default)
};
template<typename T>
struct LLShaderSetting : public LLShaderSettingBase
{
LLShaderSetting(const char* setting_name, T def) : LLShaderSettingBase(setting_name), mValue(def), mDefault(def) {}
T mValue; //The member variable mentioned above.
T mDefault; //Set via ctor. Value is inserted into the defaults LLSD list if absent from postprocesseffects.xml
LLSD getDefaultValue() { return mDefault; } //See LLShaderSettingBase::getDefaultValue
void setValue(const LLSD& value) { mValue = value; } //See LLShaderSettingBase::setValue
operator T() { return mValue; } //Typecast operator overload so this object can be handled as if it was whatever T represents.
};
std::vector<LLShaderSettingBase*> mSettings; //Contains a list of all the 'settings' this shader uses. Manually add via push_back in ctor.
public:
virtual ~LLPostProcessShader() {};
virtual bool isEnabled() = 0; //Returning false avoids bind/draw/unbind calls. If no shaders are enabled, framebuffer copying is skipped.
virtual S32 getColorChannel() = 0; //If color buffer is used in this shader returns > -1 to cue LLPostProcess on copying it from the framebuffer.
virtual S32 getDepthChannel() = 0; //If depth buffer is used in this shader returns > -1 to cue LLPostProcess on copying it from the framebuffer.
virtual QuadType bind() = 0; //Bind shader and textures, set up attribs. Returns the 'type' of quad to be drawn.
virtual bool draw(U32 pass) = 0; //returning false means finished. Used to update per-pass attributes and such. LLPostProcess will call
//drawOrthoQuad when this returns true, increment pass, then call this again, and keep repeating this until false is returned.
virtual void unbind() = 0; //Unbind shader and textures.
LLSD getDefaults(); //Returns a full LLSD kvp list filled with default values.
void loadSettings(const LLSD& settings); //Parses the effects LLSD list and sets the member variables linked to them (via LLShaderSetting::setValue())
};
//LLVector4 does not implicitly convert to and from LLSD, so template specilizations are necessary.
template<> LLSD LLPostProcessShader::LLShaderSetting<LLVector4>::getDefaultValue();
template<> void LLPostProcessShader::LLShaderSetting<LLVector4>::setValue(const LLSD& value);
class LLPostProcess : public LLSingleton<LLPostProcess>
{
public:
typedef enum _QuadType {
QUAD_NORMAL,
QUAD_NOISE
} QuadType;
/// GLSL Shader Encapsulation Struct
//typedef std::map<const char *, GLuint> glslUniforms;
struct PostProcessTweaks : public LLSD {
inline PostProcessTweaks() : LLSD(LLSD::emptyMap())
{
}
inline LLSD & brightMult() {
return (*this)["brightness_multiplier"];
}
inline LLSD & noiseStrength() {
return (*this)["noise_strength"];
}
inline LLSD & noiseSize() {
return (*this)["noise_size"];
}
inline LLSD & brightness() {
return (*this)["brightness"];
}
inline LLSD & contrast() {
return (*this)["contrast"];
}
inline LLSD & contrastBaseR() {
return (*this)["contrast_base"][0];
}
inline LLSD & contrastBaseG() {
return (*this)["contrast_base"][1];
}
inline LLSD & contrastBaseB() {
return (*this)["contrast_base"][2];
}
inline LLSD & contrastBaseIntensity() {
return (*this)["contrast_base"][3];
}
inline LLSD & saturation() {
return (*this)["saturation"];
}
inline LLSD & useNightVisionShader() {
return (*this)["enable_night_vision"];
}
inline LLSD & useColorFilter() {
return (*this)["enable_color_filter"];
}
inline LLSD & useGaussBlurFilter() {
return (*this)["enable_gauss_blur"];
}
inline F32 getBrightMult() const {
return F32((*this)["brightness_multiplier"].asReal());
}
inline F32 getNoiseStrength() const {
return F32((*this)["noise_strength"].asReal());
}
inline F32 getNoiseSize() const {
return F32((*this)["noise_size"].asReal());
}
inline F32 getGamma() const {
return F32((*this)["gamma"].asReal());
}
inline F32 getBrightness() const {
return F32((*this)["brightness"].asReal());
}
inline F32 getContrast() const {
return F32((*this)["contrast"].asReal());
}
inline F32 getContrastBaseR() const {
return F32((*this)["contrast_base"][0].asReal());
}
inline F32 getContrastBaseG() const {
return F32((*this)["contrast_base"][1].asReal());
}
inline F32 getContrastBaseB() const {
return F32((*this)["contrast_base"][2].asReal());
}
inline F32 getContrastBaseIntensity() const {
return F32((*this)["contrast_base"][3].asReal());
}
inline F32 getSaturation() const {
return F32((*this)["saturation"].asReal());
}
inline LLSD & getGaussBlurPasses() {
return (*this)["gauss_blur_passes"];
}
};
PostProcessTweaks tweaks;
// the map of all availible effects
LLSD mAllEffects;
private:
std::list<LLPointer<LLPostProcessShader> > mShaders; //List of all registered LLPostProcessShader instances.
LLPointer<LLVertexBuffer> mVBO;
LLPointer<LLImageGL> mSceneRenderTexture ;
U32 mNextDrawTarget; //Need to pingpong between two rendertargets. Cannot sample target texture of currently bound FBO.
// However this is ONLY the case if fbos are actually supported, else swapping isn't needed.
LLRenderTarget mRenderTarget[2];
U32 mDepthTexture;
LLPointer<LLImageGL> mNoiseTexture ;
U32 mScreenWidth;
U32 mScreenHeight;
F32 mNoiseTextureScale;
// The name of currently selected effect in mAllEffectInfo
std::string mSelectedEffectName;
// The map of settings for currently selected effect.
LLSD mSelectedEffectInfo;
// The map of all availible effects
LLSD mAllEffectInfo;
public:
LLPostProcess(void);
~LLPostProcess(void);
private:
// OpenGL initialization
void initialize(unsigned int width, unsigned int height); //Sets mScreenWidth and mScreenHeight
// calls createScreenTextures and createNoiseTexture
// creates VBO
void createScreenTextures(); //Creates color texture and depth texture(if needed).
void createNoiseTexture(); //Creates 'random' noise texture.
void apply(unsigned int width, unsigned int height);
void invalidate() ;
// Cleanup of global data that's only inited once per class.
public:
// Teardown
// Called on destroyGL or cleanupClass. Releases VBOs, rendertargets and textures.
void destroyGL();
// Cleanup of global data that's only inited once per class.
static void cleanupClass();
void setSelectedEffect(std::string const & effectName);
inline std::string const & getSelectedEffect(void) const {
return mSelectedEffectName;
}
void saveEffect(std::string const & effectName);
private:
/// read in from file
std::string mShaderErrorString;
unsigned int mScreenWidth;
unsigned int mScreenHeight;
float mNoiseTextureScale;
// the name of currently selected effect in mAllEffects
// invariant: tweaks == mAllEffects[mSelectedEffectName]
std::string mSelectedEffectName;
/// General functions
void initialize(unsigned int width, unsigned int height);
void doEffects(void);
void applyShaders(void);
bool shadersEnabled(void);
/// Night Vision Functions
void applyNightVisionShader(void);
/// Color Filter Functions
void applyColorFilterShader(void);
/// Gaussian blur Filter Functions
void applyGaussBlurShader(void);
/// OpenGL Helper Functions
// Setup for draw.
void copyFrameBuffer();
void createScreenTexture();
void createNoiseTexture();
bool checkError(void);
void drawOrthoQuad(QuadType type);
void bindNoise(U32 channel);
// Draw
void renderEffects(unsigned int width, unsigned int height); //Entry point for newview.
private:
void doEffects(void); //Sets up viewmatrix, blits the framebuffer, then calls applyShaders.
void applyShaders(void); //Iterates over all active post shaders, manages binding, calls drawOrthoQuad for render.
void drawOrthoQuad(QuadType type); //Finally draws fullscreen quad with the shader currently bound.
public:
// UI interaction
// Getters
inline LLSD const & getAllEffectInfo(void) const { return mAllEffectInfo; }
inline std::string const & getSelectedEffectName(void) const { return mSelectedEffectName; }
inline LLSD const & getSelectedEffectInfo(void) const { return mSelectedEffectInfo; }
// Setters
void setSelectedEffect(std::string const & effectName);
void setSelectedEffectValue(std::string const & setting, LLSD& value);
void resetSelectedEffect();
void saveEffectAs(std::string const & effectName);
};
#endif // LL_POSTPROCESS_H

View File

@@ -1480,9 +1480,8 @@ void LLRender::translateUI(F32 x, F32 y, F32 z)
llerrs << "Need to push a UI translation frame before offsetting" << llendl;
}
mUIOffset.back().mV[0] += x;
mUIOffset.back().mV[1] += y;
mUIOffset.back().mV[2] += z;
LLVector4a add(x,y,x);
mUIOffset.back()->add(add);
}
void LLRender::scaleUI(F32 x, F32 y, F32 z)
@@ -1492,27 +1491,28 @@ void LLRender::scaleUI(F32 x, F32 y, F32 z)
llerrs << "Need to push a UI transformation frame before scaling." << llendl;
}
mUIScale.back().scaleVec(LLVector3(x,y,z));
LLVector4a scale(x,y,z);
mUIScale.back()->mul(scale);
}
void LLRender::pushUIMatrix()
{
if (mUIOffset.empty())
{
mUIOffset.push_back(LLVector3(0,0,0));
mUIOffset.push_back(new LLVector4a(0.f));
}
else
{
mUIOffset.push_back(mUIOffset.back());
mUIOffset.push_back(new LLVector4a(*mUIOffset.back()));
}
if (mUIScale.empty())
{
mUIScale.push_back(LLVector3(1,1,1));
mUIScale.push_back(new LLVector4a(1.f));
}
else
{
mUIScale.push_back(mUIScale.back());
mUIScale.push_back(new LLVector4a(*mUIScale.back()));
}
}
@@ -1522,7 +1522,9 @@ void LLRender::popUIMatrix()
{
llerrs << "UI offset stack blown." << llendl;
}
delete mUIOffset.back();
mUIOffset.pop_back();
delete mUIScale.back();
mUIScale.pop_back();
}
@@ -1532,7 +1534,7 @@ LLVector3 LLRender::getUITranslation()
{
return LLVector3(0,0,0);
}
return mUIOffset.back();
return LLVector3(mUIOffset.back()->getF32ptr());
}
LLVector3 LLRender::getUIScale()
@@ -1541,7 +1543,7 @@ LLVector3 LLRender::getUIScale()
{
return LLVector3(1,1,1);
}
return mUIScale.back();
return LLVector3(mUIOffset.back()->getF32ptr());
}
@@ -1551,8 +1553,8 @@ void LLRender::loadUIIdentity()
{
llerrs << "Need to push UI translation frame before clearing offset." << llendl;
}
mUIOffset.back().setVec(0,0,0);
mUIScale.back().setVec(1,1,1);
mUIOffset.back()->splat(0.f);
mUIScale.back()->splat(1.f);
}
void LLRender::setColorMask(bool writeColor, bool writeAlpha)
@@ -1913,7 +1915,7 @@ void LLRender::flush()
}
}
void LLRender::vertex3f(const GLfloat& x, const GLfloat& y, const GLfloat& z)
void LLRender::vertex4a(const LLVector4a& vertex)
{
//the range of mVerticesp, mColorsp and mTexcoordsp is [0, 4095]
if (mCount > 2048)
@@ -1935,12 +1937,13 @@ void LLRender::vertex3f(const GLfloat& x, const GLfloat& y, const GLfloat& z)
if (mUIOffset.empty())
{
mVerticesp[mCount] = LLVector3(x,y,z);
mVerticesp[mCount]=vertex;
}
else
{
LLVector3 vert = (LLVector3(x,y,z)+mUIOffset.back()).scaledVec(mUIScale.back());
mVerticesp[mCount] = vert;
//LLVector3 vert = (LLVector3(x,y,z)+mUIOffset.back()).scaledVec(mUIScale.back());
mVerticesp[mCount].setAdd(vertex,*mUIOffset.back());
mVerticesp[mCount].mul(*mUIScale.back());
}
if (mMode == LLRender::QUADS && LLRender::sGLCoreProfile)
@@ -1968,7 +1971,7 @@ void LLRender::vertex3f(const GLfloat& x, const GLfloat& y, const GLfloat& z)
mTexcoordsp[mCount] = mTexcoordsp[mCount-1];
}
void LLRender::vertexBatchPreTransformed(LLVector3* verts, S32 vert_count)
void LLRender::vertexBatchPreTransformed(LLVector4a* verts, S32 vert_count)
{
if (mCount + vert_count > 4094)
{
@@ -2025,7 +2028,7 @@ void LLRender::vertexBatchPreTransformed(LLVector3* verts, S32 vert_count)
mVerticesp[mCount] = mVerticesp[mCount-1];
}
void LLRender::vertexBatchPreTransformed(LLVector3* verts, LLVector2* uvs, S32 vert_count)
void LLRender::vertexBatchPreTransformed(LLVector4a* verts, LLVector2* uvs, S32 vert_count)
{
if (mCount + vert_count > 4094)
{
@@ -2083,7 +2086,7 @@ void LLRender::vertexBatchPreTransformed(LLVector3* verts, LLVector2* uvs, S32 v
mTexcoordsp[mCount] = mTexcoordsp[mCount-1];
}
void LLRender::vertexBatchPreTransformed(LLVector3* verts, LLVector2* uvs, LLColor4U* colors, S32 vert_count)
void LLRender::vertexBatchPreTransformed(LLVector4a* verts, LLVector2* uvs, LLColor4U* colors, S32 vert_count)
{
if (mCount + vert_count > 4094)
{
@@ -2143,26 +2146,6 @@ void LLRender::vertexBatchPreTransformed(LLVector3* verts, LLVector2* uvs, LLCol
mColorsp[mCount] = mColorsp[mCount-1];
}
void LLRender::vertex2i(const GLint& x, const GLint& y)
{
vertex3f((GLfloat) x, (GLfloat) y, 0);
}
void LLRender::vertex2f(const GLfloat& x, const GLfloat& y)
{
vertex3f(x,y,0);
}
void LLRender::vertex2fv(const GLfloat* v)
{
vertex3f(v[0], v[1], 0);
}
void LLRender::vertex3fv(const GLfloat* v)
{
vertex3f(v[0], v[1], v[2]);
}
void LLRender::texCoord2f(const GLfloat& x, const GLfloat& y)
{
mTexcoordsp[mCount] = LLVector2(x,y);

View File

@@ -364,12 +364,14 @@ public:
void begin(const GLuint& mode);
void end();
void vertex2i(const GLint& x, const GLint& y);
void vertex2f(const GLfloat& x, const GLfloat& y);
void vertex3f(const GLfloat& x, const GLfloat& y, const GLfloat& z);
void vertex2fv(const GLfloat* v);
void vertex3fv(const GLfloat* v);
LL_FORCE_INLINE void vertex2i(const GLint& x, const GLint& y) { vertex4a(LLVector4a((GLfloat)x,(GLfloat)y,0.f)); }
LL_FORCE_INLINE void vertex2f(const GLfloat& x, const GLfloat& y) { vertex4a(LLVector4a(x,y,0.f)); }
LL_FORCE_INLINE void vertex3f(const GLfloat& x, const GLfloat& y, const GLfloat& z) { vertex4a(LLVector4a(x,y,z)); }
LL_FORCE_INLINE void vertex2fv(const GLfloat* v) { vertex4a(LLVector4a(v[0],v[1],0.f)); }
LL_FORCE_INLINE void vertex3fv(const GLfloat* v) { vertex4a(LLVector4a(v[0],v[1],v[2])); }
void vertex4a(const LLVector4a& v);
void texCoord2i(const GLint& x, const GLint& y);
void texCoord2f(const GLfloat& x, const GLfloat& y);
void texCoord2fv(const GLfloat* tc);
@@ -387,9 +389,9 @@ public:
void diffuseColor4fv(const F32* c);
void diffuseColor4ubv(const U8* c);
void vertexBatchPreTransformed(LLVector3* verts, S32 vert_count);
void vertexBatchPreTransformed(LLVector3* verts, LLVector2* uvs, S32 vert_count);
void vertexBatchPreTransformed(LLVector3* verts, LLVector2* uvs, LLColor4U*, S32 vert_count);
void vertexBatchPreTransformed(LLVector4a* verts, S32 vert_count);
void vertexBatchPreTransformed(LLVector4a* verts, LLVector2* uvs, S32 vert_count);
void vertexBatchPreTransformed(LLVector4a* verts, LLVector2* uvs, LLColor4U*, S32 vert_count);
void setColorMask(bool writeColor, bool writeAlpha);
void setColorMask(bool writeColorR, bool writeColorG, bool writeColorB, bool writeAlpha);
@@ -449,7 +451,7 @@ private:
F32 mCurrAlphaFuncVal;
LLPointer<LLVertexBuffer> mBuffer;
LLStrider<LLVector3> mVerticesp;
LLStrider<LLVector4a> mVerticesp;
LLStrider<LLVector2> mTexcoordsp;
LLStrider<LLColor4U> mColorsp;
std::vector<LLTexUnit*> mTexUnits;
@@ -463,8 +465,8 @@ private:
F32 mMaxAnisotropy;
std::vector<LLVector3> mUIOffset;
std::vector<LLVector3> mUIScale;
std::vector<LLVector4a*> mUIOffset;
std::vector<LLVector4a*> mUIScale;
};

View File

@@ -76,6 +76,45 @@ LLRenderTarget::~LLRenderTarget()
release();
}
void LLRenderTarget::resize(U32 resx, U32 resy, U32 color_fmt)
{
//for accounting, get the number of pixels added/subtracted
S32 pix_diff = (resx*resy)-(mResX*mResY);
mResX = resx;
mResY = resy;
for (U32 i = 0; i < mTex.size(); ++i)
{ //resize color attachments
gGL.getTexUnit(0)->bindManual(mUsage, mTex[i]);
LLImageGL::setManualImage(LLTexUnit::getInternalType(mUsage), 0, color_fmt, mResX, mResY, GL_RGBA, GL_UNSIGNED_BYTE, NULL, false);
sBytesAllocated += pix_diff*4;
}
if (mDepth)
{ //resize depth attachment
if (mStencil && mFBO)
{
//use render buffers where stencil buffers are in play
glBindRenderbuffer(GL_RENDERBUFFER, mDepth);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, mResX, mResY);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
}
else
{
gGL.getTexUnit(0)->bindManual(mUsage, mDepth);
U32 internal_type = LLTexUnit::getInternalType(mUsage);
if(!mStencil)
LLImageGL::setManualImage(internal_type, 0, GL_DEPTH_COMPONENT24, mResX, mResY, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL, false);
else
LLImageGL::setManualImage(internal_type, 0, GL_DEPTH24_STENCIL8, mResX, mResY, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, NULL, false);
}
sBytesAllocated += pix_diff*4;
}
if(mSampleBuffer)
mSampleBuffer->resize(resx,resy);
}
void LLRenderTarget::setSampleBuffer(LLMultisampleBuffer* buffer)
{
@@ -95,9 +134,10 @@ bool LLRenderTarget::allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, boo
mUsage = usage;
mUseDepth = depth;
if ((sUseFBO || use_fbo) && gGLManager.mHasFramebufferObject)
{
glGenFramebuffers(1, (GLuint *) &mFBO);
if (depth)
{
if (!allocateDepth())
@@ -107,8 +147,6 @@ bool LLRenderTarget::allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, boo
}
}
glGenFramebuffers(1, (GLuint *) &mFBO);
if (mDepth)
{
glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
@@ -126,7 +164,7 @@ bool LLRenderTarget::allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, boo
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
stop_glerror();
}
@@ -219,7 +257,7 @@ bool LLRenderTarget::addColorAttachment(U32 color_fmt)
bool LLRenderTarget::allocateDepth()
{
if (mStencil)
if (mStencil && mFBO)
{
//use render buffers where stencil buffers are in play
glGenRenderbuffers(1, (GLuint *) &mDepth);
@@ -231,24 +269,30 @@ bool LLRenderTarget::allocateDepth()
}
else
{
LLImageGL::generateTextures(mUsage, GL_DEPTH_COMPONENT24, 1, &mDepth);
if(!mStencil)
LLImageGL::generateTextures(mUsage, GL_DEPTH_COMPONENT24, 1, &mDepth);
else
LLImageGL::generateTextures(mUsage, GL_DEPTH24_STENCIL8, 1, &mDepth);
gGL.getTexUnit(0)->bindManual(mUsage, mDepth);
U32 internal_type = LLTexUnit::getInternalType(mUsage);
stop_glerror();
clear_glerror();
LLImageGL::setManualImage(internal_type, 0, GL_DEPTH_COMPONENT24, mResX, mResY, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL, false);
if(!mStencil)
LLImageGL::setManualImage(internal_type, 0, GL_DEPTH_COMPONENT24, mResX, mResY, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL, false);
else
LLImageGL::setManualImage(internal_type, 0, GL_DEPTH24_STENCIL8, mResX, mResY, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, NULL, false);
gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
}
sBytesAllocated += mResX*mResY*4;
if (glGetError() != GL_NO_ERROR)
{
llwarns << "Unable to allocate depth buffer for render target." << llendl;
return false;
}
sBytesAllocated += mResX*mResY*4;
return true;
}
@@ -301,7 +345,7 @@ void LLRenderTarget::release()
{
if (mDepth)
{
if (mStencil)
if (mStencil && mFBO)
{
glDeleteRenderbuffers(1, (GLuint*) &mDepth);
stop_glerror();
@@ -309,7 +353,11 @@ void LLRenderTarget::release()
else
{
//Release before delete.
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, LLTexUnit::getInternalType(mUsage), 0, 0);
if(mFBO)
{
glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, LLTexUnit::getInternalType(mUsage), 0, 0);
}
LLImageGL::deleteTextures(mUsage, 0, 0, 1, &mDepth, true);
stop_glerror();
}
@@ -453,6 +501,7 @@ void LLRenderTarget::flush(bool fetch_depth)
{
gGL.getTexUnit(0)->bind(this);
glCopyTexSubImage2D(LLTexUnit::getInternalType(mUsage), 0, 0, 0, 0, 0, mResX, mResY);
stop_glerror();
if (fetch_depth)
{
@@ -461,8 +510,10 @@ void LLRenderTarget::flush(bool fetch_depth)
allocateDepth();
}
gGL.getTexUnit(0)->bind(this);
glCopyTexImage2D(LLTexUnit::getInternalType(mUsage), 0, GL_DEPTH24_STENCIL8, 0, 0, mResX, mResY, 0);
gGL.getTexUnit(0)->bind(this,true);
glCopyTexSubImage2D(LLTexUnit::getInternalType(mUsage), 0, 0, 0, 0, 0, mResX, mResY);
stop_glerror();
//glCopyTexImage2D(LLTexUnit::getInternalType(mUsage), 0, GL_DEPTH24_STENCIL8, 0, 0, mResX, mResY, 0);
}
gGL.getTexUnit(0)->disable();
@@ -472,7 +523,7 @@ void LLRenderTarget::flush(bool fetch_depth)
stop_glerror();
glBindFramebuffer(GL_FRAMEBUFFER, 0);
stop_glerror();
if (mSampleBuffer)
{
LLGLEnable multisample(GL_MULTISAMPLE);
@@ -482,7 +533,7 @@ void LLRenderTarget::flush(bool fetch_depth)
check_framebuffer_status();
glBindFramebuffer(GL_READ_FRAMEBUFFER, mSampleBuffer->mFBO);
check_framebuffer_status();
stop_glerror();
if(gGLManager.mIsATI)
{
@@ -532,7 +583,6 @@ void LLRenderTarget::flush(bool fetch_depth)
}
}
}
void LLRenderTarget::copyContents(LLRenderTarget& source, S32 srcX0, S32 srcY0, S32 srcX1, S32 srcY1,
S32 dstX0, S32 dstY0, S32 dstX1, S32 dstY1, U32 mask, U32 filter)
{
@@ -553,7 +603,7 @@ void LLRenderTarget::copyContents(LLRenderTarget& source, S32 srcX0, S32 srcY0,
}
else
{
if (mask == GL_DEPTH_BUFFER_BIT && source.mStencil != mStencil)
if (mask == GL_DEPTH_BUFFER_BIT && !mStencil && source.mStencil != mStencil)
{
stop_glerror();
@@ -642,7 +692,8 @@ void LLRenderTarget::getViewport(S32* viewport)
// LLMultisampleBuffer implementation
//==================================================
LLMultisampleBuffer::LLMultisampleBuffer() :
mSamples(0)
mSamples(0),
mColorFormat(0)
{
}
@@ -743,6 +794,7 @@ bool LLMultisampleBuffer::allocate(U32 resx, U32 resy, U32 color_fmt, bool depth
mUsage = usage;
mUseDepth = depth;
mStencil = stencil;
mColorFormat = color_fmt;
{
@@ -780,6 +832,42 @@ bool LLMultisampleBuffer::allocate(U32 resx, U32 resy, U32 color_fmt, bool depth
return addColorAttachment(color_fmt);
}
void LLMultisampleBuffer::resize(U32 resx, U32 resy)
{
//for accounting, get the number of pixels added/subtracted
S32 pix_diff = (resx*resy)-(mResX*mResY);
mResX = resx;
mResY = resy;
for (U32 i = 0; i < mTex.size(); ++i)
{ //resize color attachments
glBindRenderbuffer(GL_RENDERBUFFER, mTex[i]);
glRenderbufferStorageMultisample(GL_RENDERBUFFER, mSamples, mColorFormat, mResX, mResY);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
sBytesAllocated += pix_diff*4;
}
if (mDepth)
{ //resize depth attachment
if (mStencil)
{
//use render buffers where stencil buffers are in play
glBindRenderbuffer(GL_RENDERBUFFER, mDepth);
glRenderbufferStorageMultisample(GL_RENDERBUFFER, mSamples, GL_DEPTH24_STENCIL8, mResX, mResY);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
}
else
{
glBindRenderbuffer(GL_RENDERBUFFER, mDepth);
glRenderbufferStorageMultisample(GL_RENDERBUFFER, mSamples, GL_DEPTH_COMPONENT24, mResX, mResY);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
}
sBytesAllocated += pix_diff*4;
}
}
bool LLMultisampleBuffer::addColorAttachment(U32 color_fmt)
{
if (color_fmt == 0)
@@ -829,12 +917,13 @@ bool LLMultisampleBuffer::allocateDepth()
clear_glerror();
if (mStencil)
{
glRenderbufferStorageMultisample(GL_RENDERBUFFER, mSamples, GL_DEPTH24_STENCIL8, mResX, mResY);
glRenderbufferStorageMultisample(GL_RENDERBUFFER, mSamples, GL_DEPTH24_STENCIL8, mResX, mResY);
}
else
{
glRenderbufferStorageMultisample(GL_RENDERBUFFER, mSamples, GL_DEPTH_COMPONENT16_ARB, mResX, mResY);
glRenderbufferStorageMultisample(GL_RENDERBUFFER, mSamples, GL_DEPTH_COMPONENT24, mResX, mResY);
}
if (glGetError() != GL_NO_ERROR)
{
llwarns << "Unable to allocate depth buffer for multisample render target." << llendl;
@@ -845,4 +934,3 @@ bool LLMultisampleBuffer::allocateDepth()
return true;
}

View File

@@ -80,6 +80,12 @@ public:
//multiple calls will release previously allocated resources
bool allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, bool stencil, LLTexUnit::eTextureType usage = LLTexUnit::TT_TEXTURE, bool use_fbo = FALSE);
//resize existing attachments to use new resolution and color format
// CAUTION: if the GL runs out of memory attempting to resize, this render target will be undefined
// DO NOT use for screen space buffers or for scratch space for an image that might be uploaded
// DO use for render targets that resize often and aren't likely to ruin someone's day if they break
void resize(U32 resx, U32 resy, U32 color_fmt);
//provide this render target with a multisample resource.
void setSampleBuffer(LLMultisampleBuffer* buffer);
@@ -145,6 +151,8 @@ public:
//one renderable attachment (i.e. color buffer, depth buffer).
bool isComplete() const;
U32 getFBO() const {return mFBO;}
static LLRenderTarget* getCurrentBoundTarget() { return sBoundTarget; }
protected:
@@ -168,6 +176,7 @@ protected:
class LLMultisampleBuffer : public LLRenderTarget
{
U32 mSamples;
U32 mColorFormat;
public:
LLMultisampleBuffer();
virtual ~LLMultisampleBuffer();
@@ -180,6 +189,7 @@ public:
bool allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, bool stencil, LLTexUnit::eTextureType usage, bool use_fbo, U32 samples);
virtual bool addColorAttachment(U32 color_fmt);
virtual bool allocateDepth();
void resize(U32 resx, U32 resy);
};
#endif //!LL_MESA_HEADLESS

View File

@@ -679,7 +679,7 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
vec4 diffuseLookup(vec2 texcoord)
{
switch (vary_texture_index.r))
switch (vary_texture_index))
{
case 0: ret = texture2D(tex0, texcoord); break;
case 1: ret = texture2D(tex1, texcoord); break;
@@ -703,7 +703,7 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
if (texture_index_channels > 1)
{
text[count++] = strdup("VARYING_FLAT ivec4 vary_texture_index;\n");
text[count++] = strdup("VARYING_FLAT int vary_texture_index;\n");
}
text[count++] = strdup("vec4 diffuseLookup(vec2 texcoord)\n");
@@ -721,7 +721,7 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
{ //switches are unreliable on some NVIDIA drivers
for (S32 i = 0; i < texture_index_channels; ++i)
{
std::string if_string = llformat("\t%sif (vary_texture_index.r == %d) { return texture2D(tex%d, texcoord); }\n", i > 0 ? "else " : "", i, i);
std::string if_string = llformat("\t%sif (vary_texture_index == %d) { return texture2D(tex%d, texcoord); }\n", i > 0 ? "else " : "", i, i);
text[count++] = strdup(if_string.c_str());
}
text[count++] = strdup("\treturn vec4(1,0,1,1);\n");
@@ -730,13 +730,13 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
else
{
text[count++] = strdup("\tvec4 ret = vec4(1,0,1,1);\n");
text[count++] = strdup("\tswitch (vary_texture_index.r)\n");
text[count++] = strdup("\tswitch (vary_texture_index)\n");
text[count++] = strdup("\t{\n");
//switch body
for (S32 i = 0; i < texture_index_channels; ++i)
{
std::string case_str = llformat("\t\tcase %d: ret = texture2D(tex%d, texcoord); break;\n", i, i);
std::string case_str = llformat("\t\tcase %d: return texture2D(tex%d, texcoord);\n", i, i);
text[count++] = strdup(case_str.c_str());
}

View File

@@ -1249,7 +1249,7 @@ void LLVertexBuffer::setupVertexArray()
1, //TYPE_WEIGHT,
4, //TYPE_WEIGHT4,
4, //TYPE_CLOTHWEIGHT,
4, //TYPE_TEXTURE_INDEX
1, //TYPE_TEXTURE_INDEX
};
U32 attrib_type[] =
@@ -1266,7 +1266,7 @@ void LLVertexBuffer::setupVertexArray()
GL_FLOAT, //TYPE_WEIGHT,
GL_FLOAT, //TYPE_WEIGHT4,
GL_FLOAT, //TYPE_CLOTHWEIGHT,
GL_UNSIGNED_BYTE, //TYPE_TEXTURE_INDEX
GL_UNSIGNED_INT, //TYPE_TEXTURE_INDEX
};
bool attrib_integer[] =
@@ -2313,7 +2313,7 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask)
#if !LL_DARWIN
S32 loc = TYPE_TEXTURE_INDEX;
void *ptr = (void*) (base + mOffsets[TYPE_VERTEX] + 12);
glVertexAttribIPointer(loc, 4, GL_UNSIGNED_BYTE, LLVertexBuffer::sTypeSize[TYPE_VERTEX], ptr);
glVertexAttribIPointer(loc, 1, GL_UNSIGNED_INT, LLVertexBuffer::sTypeSize[TYPE_VERTEX], ptr);
#endif
}
if (data_mask & MAP_VERTEX)