Reworked LLPostProcess and implemented FBO support (much faster if multiple post shaders are enabled, or need a lot of passes).

Tweaked LLRenderTarget to support depth textures if FBO support is lacking.
Prefer LLRenderTarget::getFBO() over LLRenderTarget::sUseFBO when determining how to handle a specific LLRenderTarget object. (Decoupling to simplify logic without having to track a global)
This commit is contained in:
Shyotl
2012-07-29 04:28:11 -05:00
parent 701230b49c
commit 1d1947c51a
17 changed files with 660 additions and 473 deletions

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;
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);
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();
}
void LLPostProcess::applyShaders(void)
{
bool copy_buffer = false;
if (tweaks.useColorFilter())
{
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)
void LLPostProcess::createNoiseTexture()
{
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(i || j)
copyFrameBuffer();
glUniform1iARB(horiz_pass, j);
drawOrthoQuad(QUAD_NORMAL);
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);
}
}
for(std::list<LLPointer<LLPostProcessShader> >::iterator it=mShaders.begin();it!=mShaders.end();++it)
{
if((*it)->getDepthChannel()>=0)
{
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();
break;
}
}
}
}
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

@@ -380,7 +380,7 @@ bool LLTexUnit::bind(LLRenderTarget* renderTarget, bool bindDepth)
if (bindDepth)
{
if (renderTarget->hasStencil())
if (renderTarget->hasStencil() && renderTarget->getFBO())
{
llerrs << "Cannot bind a render buffer for sampling. Allocate render target without a stencil buffer if sampling of depth buffer is required." << llendl;
}

View File

@@ -93,7 +93,7 @@ void LLRenderTarget::resize(U32 resx, U32 resy, U32 color_fmt)
if (mDepth)
{ //resize depth attachment
if (mStencil)
if (mStencil && mFBO)
{
//use render buffers where stencil buffers are in play
glBindRenderbuffer(GL_RENDERBUFFER, mDepth);
@@ -104,7 +104,10 @@ void LLRenderTarget::resize(U32 resx, U32 resy, U32 color_fmt)
{
gGL.getTexUnit(0)->bindManual(mUsage, mDepth);
U32 internal_type = LLTexUnit::getInternalType(mUsage);
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);
}
sBytesAllocated += pix_diff*4;
@@ -131,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())
@@ -143,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);
@@ -162,7 +164,7 @@ bool LLRenderTarget::allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, boo
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
stop_glerror();
}
@@ -255,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);
@@ -267,13 +269,19 @@ 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);
}
@@ -337,7 +345,7 @@ void LLRenderTarget::release()
{
if (mDepth)
{
if (mStencil)
if (mStencil && mFBO)
{
glDeleteRenderbuffers(1, (GLuint*) &mDepth);
stop_glerror();
@@ -490,6 +498,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)
{
@@ -498,8 +507,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();
@@ -589,7 +600,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();

View File

@@ -151,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:

View File

@@ -0,0 +1,23 @@
/**
* @file colorFilterF.glsl
*
* Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
* $License$
*/
#extension GL_ARB_texture_rectangle : enable
#ifdef DEFINE_GL_FRAGCOLOR
out vec4 gl_FragColor;
#endif
uniform sampler2DRect tex0;
uniform int layerCount;
VARYING vec2 vary_texcoord0;
void main(void)
{
vec3 color = pow(floor(pow(vec3(texture2D(tex0, vary_texcoord0.st)),vec3(.6)) * layerCount)/layerCount,vec3(1.66666));
gl_FragColor = vec4(color, 1.0);
}

View File

@@ -174,6 +174,8 @@
<boolean>0</boolean>
<key>enable_gauss_blur</key>
<boolean>0</boolean>
<key>enable_posterize</key>
<boolean>0</boolean>
<key>gauss_blur_passes</key>
<integer>2</integer>
<key>extract_high</key>
@@ -186,6 +188,8 @@
<real>0.40000000000000002</real>
<key>saturation</key>
<real>1</real>
</map>
<key>posterize_layers</key>
<real>10</real>
</map>
</map>
</llsd>

View File

@@ -57,7 +57,6 @@
#include "lldaycyclemanager.h"
#include "llwlparamset.h"
#include "llwlparammanager.h"
#include "llpostprocess.h"
#include "llfloaterwindlight.h"

View File

@@ -115,17 +115,7 @@ LLFloaterPostProcess* LLFloaterPostProcess::instance()
void LLFloaterPostProcess::onControlChanged(LLUICtrl* ctrl, void* userData)
{
char const *VariableName = (char const *)userData;
char buf[256];
S32 elem=0;
if(sscanf(VariableName,"%255[^[][%d]", buf, &elem) == 2)
{
LLPostProcess::getInstance()->tweaks[(const char*)buf][elem] = ctrl->getValue();
}
else
{
LLPostProcess::getInstance()->tweaks[VariableName] = ctrl->getValue();
}
LLPostProcess::getInstance()->setSelectedEffectValue((char const *)userData,ctrl->getValue());
}
void LLFloaterPostProcess::onLoadEffect(void* userData)
@@ -145,7 +135,7 @@ void LLFloaterPostProcess::onSaveEffect(void* userData)
std::string effectName(editBox->getValue().asString());
if (LLPostProcess::getInstance()->mAllEffects.has(effectName))
if (LLPostProcess::getInstance()->getAllEffectInfo().has(effectName))
{
LLSD payload;
payload["effect_name"] = effectName;
@@ -153,7 +143,7 @@ void LLFloaterPostProcess::onSaveEffect(void* userData)
}
else
{
LLPostProcess::getInstance()->saveEffect(effectName);
LLPostProcess::getInstance()->saveEffectAs(effectName);
sPostProcess->syncMenu();
}
}
@@ -175,7 +165,7 @@ bool LLFloaterPostProcess::saveAlertCallback(const LLSD& notification, const LLS
// if they choose save, do it. Otherwise, don't do anything
if (option == 0)
{
LLPostProcess::getInstance()->saveEffect(notification["payload"]["effect_name"].asString());
LLPostProcess::getInstance()->saveEffectAs(notification["payload"]["effect_name"].asString());
sPostProcess->syncMenu();
}
@@ -209,17 +199,17 @@ void LLFloaterPostProcess::syncMenu()
comboBox->removeall();
LLSD::map_const_iterator currEffect;
for(currEffect = LLPostProcess::getInstance()->mAllEffects.beginMap();
currEffect != LLPostProcess::getInstance()->mAllEffects.endMap();
for(currEffect = LLPostProcess::getInstance()->getAllEffectInfo().beginMap();
currEffect != LLPostProcess::getInstance()->getAllEffectInfo().endMap();
++currEffect)
{
comboBox->add(currEffect->first);
}
// set the current effect as selected.
comboBox->selectByValue(LLPostProcess::getInstance()->getSelectedEffect());
comboBox->selectByValue(LLPostProcess::getInstance()->getSelectedEffectName());
LLSD &tweaks = LLPostProcess::getInstance()->tweaks;
const LLSD &tweaks = LLPostProcess::getInstance()->getSelectedEffectInfo();
//Iterate down all uniforms handled by post-process shaders. Update any linked ui elements.
for (LLSD::map_const_iterator it = tweaks.beginMap(); it != tweaks.endMap(); ++it)
{

View File

@@ -62,7 +62,6 @@
#include "llwaterparamset.h"
#include "llwaterparammanager.h"
#include "llpostprocess.h"
#undef max

View File

@@ -62,7 +62,6 @@
#include "llwlparamset.h"
#include "llwlparammanager.h"
#include "llpostprocess.h"
#undef max

View File

@@ -200,7 +200,6 @@
#include "llnamelistctrl.h"
#include "llnamebox.h"
#include "llnameeditor.h"
#include "llpostprocess.h"
#include "llwlparammanager.h"
#include "llwaterparammanager.h"
#include "llagentlanguage.h"

View File

@@ -1009,7 +1009,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot, boo
if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender)
{
gPipeline.mDeferredScreen.flush();
if(LLRenderTarget::sUseFBO)
if(gPipeline.mDeferredScreen.getFBO())
{
LLRenderTarget::copyContentsToFramebuffer(gPipeline.mDeferredScreen, 0, 0, gPipeline.mDeferredScreen.getWidth(),
gPipeline.mDeferredScreen.getHeight(), 0, 0,
@@ -1021,7 +1021,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot, boo
else
{
gPipeline.mScreen.flush();
if(LLRenderTarget::sUseFBO)
if(gPipeline.mScreen.getFBO())
{
LLRenderTarget::copyContentsToFramebuffer(gPipeline.mScreen, 0, 0, gPipeline.mScreen.getWidth(),
gPipeline.mScreen.getHeight(), 0, 0,
@@ -1283,14 +1283,12 @@ void render_ui(F32 zoom_factor, int subfield, bool tiling)
if (to_texture)
{
gPipeline.renderBloom(gSnapshot, zoom_factor, subfield, tiling);
gPipeline.mScreen.flush(); //blit, etc.
}
/// We copy the frame buffer straight into a texture here,
/// and then display it again with compositor effects.
/// Using render to texture would be faster/better, but I don't have a
/// grasp of their full display stack just yet.
if(gPipeline.canUseVertexShaders())
LLPostProcess::getInstance()->apply(gViewerWindow->getWindowDisplayWidth(), gViewerWindow->getWindowDisplayHeight());
{
LLPostProcess::getInstance()->renderEffects(gViewerWindow->getWindowDisplayWidth(), gViewerWindow->getWindowDisplayHeight());
}
render_hud_elements();
render_hud_attachments();

View File

@@ -170,6 +170,7 @@ LLGLSLShader gGlowExtractProgram(LLViewerShaderMgr::SHADER_EFFECT); //Not in
LLGLSLShader gPostColorFilterProgram(LLViewerShaderMgr::SHADER_EFFECT); //Not in mShaderList
LLGLSLShader gPostNightVisionProgram(LLViewerShaderMgr::SHADER_EFFECT); //Not in mShaderList
LLGLSLShader gPostGaussianBlurProgram(LLViewerShaderMgr::SHADER_EFFECT); //Not in mShaderList
LLGLSLShader gPostPosterizeProgram(LLViewerShaderMgr::SHADER_EFFECT); //Not in mShaderList
// Deferred rendering shaders
LLGLSLShader gDeferredImpostorProgram(LLViewerShaderMgr::SHADER_DEFERRED);
@@ -958,6 +959,23 @@ BOOL LLViewerShaderMgr::loadShadersEffects()
gPostGaussianBlurProgram.uniform1i("tex0", 0);
}
}
{
vector<string> shaderUniforms;
shaderUniforms.reserve(1);
shaderUniforms.push_back("layerCount");
gPostPosterizeProgram.mName = "Posterize Shader (Post)";
gPostPosterizeProgram.mShaderFiles.clear();
gPostPosterizeProgram.mShaderFiles.push_back(make_pair("effects/PosterizeF.glsl", GL_FRAGMENT_SHADER_ARB));
gPostPosterizeProgram.mShaderFiles.push_back(make_pair("interface/onetexturenocolorV.glsl", GL_VERTEX_SHADER_ARB));
gPostPosterizeProgram.mShaderLevel = mVertexShaderLevel[SHADER_EFFECT];
if(gPostPosterizeProgram.createShader(NULL, &shaderUniforms))
{
gPostPosterizeProgram.bind();
gPostPosterizeProgram.uniform1i("tex0", 0);
}
}
#endif
return success;

View File

@@ -4839,7 +4839,7 @@ void LLViewerWindow::stopGL(BOOL save_state)
if(LLPostProcess::instanceExists())
{
LLPostProcess::getInstance()->invalidate();
LLPostProcess::getInstance()->destroyGL();
}
gTextureList.destroyGL(save_state);

View File

@@ -54,6 +54,7 @@
#include "llglheaders.h"
#include "llrender.h"
#include "llwindow.h"
#include "llpostprocess.h"
// newview includes
#include "llagent.h"
@@ -863,6 +864,9 @@ void LLPipeline::releaseGLBuffers()
gBumpImageList.destroyGL();
LLVOAvatar::resetImpostors();
if(LLPostProcess::instanceExists())
LLPostProcess::getInstance()->destroyGL();
}
void LLPipeline::releaseLUTBuffers()
@@ -6111,12 +6115,14 @@ void LLPipeline::doResetVertexBuffers()
LLVOPartGroup::destroyGL();
if(LLPostProcess::instanceExists())
LLPostProcess::getInstance()->destroyGL();
LLVertexBuffer::cleanupClass();
//delete all name pool caches
LLGLNamePool::cleanupPools();
if (LLVertexBuffer::sGLCount > 0)
{
llwarns << "VBO wipe failed -- " << LLVertexBuffer::sGLCount << " buffers remaining." << llendl;
@@ -6923,7 +6929,7 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield, b
}
if (LLRenderTarget::sUseFBO)
if (mScreen.getFBO())
{ //copy depth buffer from mScreen to framebuffer
LLRenderTarget::copyContentsToFramebuffer(mScreen, 0, 0, mScreen.getWidth(), mScreen.getHeight(),
0, 0, mScreen.getWidth(), mScreen.getHeight(), GL_DEPTH_BUFFER_BIT, GL_NEAREST);

View File

@@ -146,6 +146,25 @@
left="14" max_val="1" min_val="0" mouse_opaque="true"
name="noise_strength" show_text="true" value="1.0" width="200" />
</panel>
<panel border="true" bottom="-180" follows="left|top|right|bottom" height="400"
label="Posterize" left="1" mouse_opaque="false"
name="PosterizePanel" width="398">
<check_box bottom="-20" follows="left|top"
font="SansSerifSmall" height="16" initial_value="false" label="Enable"
left="14" mouse_opaque="true" name="enable_posterize" width="200" />
<text type="string" length="1" bg_visible="false" border_drop_shadow_visible="false" border_visible="false"
bottom_delta="-21" drop_shadow_visible="true" follows="left|top|right"
font="SansSerif" h_pad="0" halign="left" height="16"
left="10" mouse_opaque="true" name="PosterLayersText" v_pad="0"
width="355">
Layer Count
</text>
<slider bottom_delta="-30" can_edit_text="true"
decimal_digits="3" follows="left"
height="18" increment="1" initial_val="10" label="" left="14"
max_val="20" min_val="1" mouse_opaque="true"
name="posterize_layers" show_text="true" value="10" width="200" />
</panel>
<!--<panel border="true" bottom="-180" follows="left|top|right|bottom" height="400"
label="Bloom" left="1" mouse_opaque="true"
name="BloomPanel" width="398">