summaryrefslogtreecommitdiff
path: root/indra/llrender
diff options
context:
space:
mode:
authorRunitaiLinden <davep@lindenlab.com>2023-01-27 17:24:22 -0600
committerGitHub <noreply@github.com>2023-01-27 17:24:22 -0600
commit3ef31cb9b28f7b026e109eab69d383dddc922850 (patch)
treeeb4034470bbc59bba139a66b053583bb05e3d7c1 /indra/llrender
parent503e18fc646c6d88cd8006ad2210a8afd0bced83 (diff)
SL-19203 et al -- Integrate SSR with reflection probes, tweak probe blending. (#63)
* SL-19203 WIP -- Integrate SSR with reflection probes. Decruft LLRenderTarget. * SL-19203 WIP -- Re-integrate SSR. Incidental decruft. * SL-19203 WIP -- SSR frame delta correction (still broken for Z) * SL-19203 WIP -- SSR frame delta Z fix * SL-19203 WIP -- Make SSR toggleable again and disable SSR in cube snapshots. * SL-19203 WIP -- Soften sphere probe transitions and fix reflections on void water (make fallback probe a simple terrain+water+sky probe). Remove parallax correction for automatic probes to reduce artifacts. * SL-19203 Tune probe blending. * SL-19203 Cleanup.
Diffstat (limited to 'indra/llrender')
-rw-r--r--indra/llrender/llgl.cpp3
-rw-r--r--indra/llrender/llrender.cpp7
-rw-r--r--indra/llrender/llrender.h2
-rw-r--r--indra/llrender/llrendertarget.cpp786
-rw-r--r--indra/llrender/llrendertarget.h33
-rw-r--r--indra/llrender/llshadermgr.cpp8
-rw-r--r--indra/llrender/llshadermgr.h6
-rw-r--r--indra/llrender/llvertexbuffer.cpp2
8 files changed, 405 insertions, 442 deletions
diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp
index 72d9c14ccf..c08c576531 100644
--- a/indra/llrender/llgl.cpp
+++ b/indra/llrender/llgl.cpp
@@ -2270,7 +2270,7 @@ void do_assert_glerror()
GLenum error;
error = glGetError();
BOOL quit = FALSE;
- while (LL_UNLIKELY(error))
+ if (LL_UNLIKELY(error))
{
quit = TRUE;
GLubyte const * gl_error_msg = gluErrorString(error);
@@ -2295,7 +2295,6 @@ void do_assert_glerror()
gFailLog << "GL Error: UNKNOWN 0x" << std::hex << error << std::dec << std::endl;
}
}
- error = glGetError();
}
if (quit)
diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp
index d6b2aa2289..6dbde719f4 100644
--- a/indra/llrender/llrender.cpp
+++ b/indra/llrender/llrender.cpp
@@ -55,8 +55,14 @@ F32 gGLModelView[16];
F32 gGLLastModelView[16];
F32 gGLLastProjection[16];
F32 gGLProjection[16];
+
+// transform from last frame's camera space to this frame's camera space (and inverse)
+F32 gGLDeltaModelView[16];
+F32 gGLInverseDeltaModelView[16];
+
S32 gGLViewport[4];
+
U32 LLRender::sUICalls = 0;
U32 LLRender::sUIVerts = 0;
U32 LLTexUnit::sWhiteTexture = 0;
@@ -373,7 +379,6 @@ bool LLTexUnit::bind(LLRenderTarget* renderTarget, bool bindDepth)
if (bindDepth)
{
llassert(renderTarget->getDepth()); // target MUST have a depth buffer attachment
- llassert(renderTarget->canSampleDepth()); // depth buffer attachment MUST be sampleable
bindManual(renderTarget->getUsage(), renderTarget->getDepth());
}
diff --git a/indra/llrender/llrender.h b/indra/llrender/llrender.h
index cbd3de5736..e8baf6bb7e 100644
--- a/indra/llrender/llrender.h
+++ b/indra/llrender/llrender.h
@@ -507,6 +507,8 @@ extern F32 gGLLastModelView[16];
extern F32 gGLLastProjection[16];
extern F32 gGLProjection[16];
extern S32 gGLViewport[4];
+extern F32 gGLDeltaModelView[16];
+extern F32 gGLInverseDeltaModelView[16];
extern thread_local LLRender gGL;
diff --git a/indra/llrender/llrendertarget.cpp b/indra/llrender/llrendertarget.cpp
index 9827db8084..6dac614eea 100644
--- a/indra/llrender/llrendertarget.cpp
+++ b/indra/llrender/llrendertarget.cpp
@@ -35,19 +35,19 @@ U32 LLRenderTarget::sBytesAllocated = 0;
void check_framebuffer_status()
{
- if (gDebugGL)
- {
- GLenum status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
- switch (status)
- {
- case GL_FRAMEBUFFER_COMPLETE:
- break;
- default:
- LL_WARNS() << "check_framebuffer_status failed -- " << std::hex << status << LL_ENDL;
- ll_fail("check_framebuffer_status failed");
- break;
- }
- }
+ if (gDebugGL)
+ {
+ GLenum status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
+ switch (status)
+ {
+ case GL_FRAMEBUFFER_COMPLETE:
+ break;
+ default:
+ LL_WARNS() << "check_framebuffer_status failed -- " << std::hex << status << LL_ENDL;
+ ll_fail("check_framebuffer_status failed");
+ break;
+ }
+ }
}
bool LLRenderTarget::sUseFBO = false;
@@ -60,112 +60,86 @@ U32 LLRenderTarget::sCurResX = 0;
U32 LLRenderTarget::sCurResY = 0;
LLRenderTarget::LLRenderTarget() :
- mResX(0),
- mResY(0),
- mFBO(0),
- mPreviousFBO(0),
- mPreviousResX(0),
- mPreviousResY(0),
- mDepth(0),
- mUseDepth(false),
- mSampleDepth(false),
- mUsage(LLTexUnit::TT_TEXTURE)
+ mResX(0),
+ mResY(0),
+ mFBO(0),
+ mDepth(0),
+ mUseDepth(false),
+ mUsage(LLTexUnit::TT_TEXTURE)
{
}
LLRenderTarget::~LLRenderTarget()
{
- release();
+ release();
}
void LLRenderTarget::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;
-
- llassert(mInternalFormat.size() == mTex.size());
-
- for (U32 i = 0; i < mTex.size(); ++i)
- { //resize color attachments
- gGL.getTexUnit(0)->bindManual(mUsage, mTex[i]);
- LLImageGL::setManualImage(LLTexUnit::getInternalType(mUsage), 0, mInternalFormat[i], mResX, mResY, GL_RGBA, GL_UNSIGNED_BYTE, NULL, false);
- sBytesAllocated += pix_diff*4;
- }
-
- if (mDepth)
- { //resize depth attachment
- if (!mSampleDepth)
- {
- //use render buffers where stencil buffers are in play
- glBindRenderbuffer(GL_RENDERBUFFER, mDepth);
- glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, mResX, mResY);
- glBindRenderbuffer(GL_RENDERBUFFER, 0);
- }
- else
- {
- 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);
- }
-
- sBytesAllocated += pix_diff*4;
- }
+ //for accounting, get the number of pixels added/subtracted
+ S32 pix_diff = (resx*resy)-(mResX*mResY);
+
+ mResX = resx;
+ mResY = resy;
+
+ llassert(mInternalFormat.size() == mTex.size());
+
+ for (U32 i = 0; i < mTex.size(); ++i)
+ { //resize color attachments
+ gGL.getTexUnit(0)->bindManual(mUsage, mTex[i]);
+ LLImageGL::setManualImage(LLTexUnit::getInternalType(mUsage), 0, mInternalFormat[i], mResX, mResY, GL_RGBA, GL_UNSIGNED_BYTE, NULL, false);
+ sBytesAllocated += pix_diff*4;
+ }
+
+ if (mDepth)
+ {
+ 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);
+
+ sBytesAllocated += pix_diff*4;
+ }
}
-
+
-bool LLRenderTarget::allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, bool sample_depth, LLTexUnit::eTextureType usage, bool use_fbo, S32 samples)
+bool LLRenderTarget::allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, LLTexUnit::eTextureType usage)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY;
- resx = llmin(resx, (U32) gGLManager.mGLMaxTextureSize);
- resy = llmin(resy, (U32) gGLManager.mGLMaxTextureSize);
+ llassert(usage == LLTexUnit::TT_TEXTURE);
+ llassert(!isBoundInStack());
- stop_glerror();
- release();
- stop_glerror();
+ resx = llmin(resx, (U32) gGLManager.mGLMaxTextureSize);
+ resy = llmin(resy, (U32) gGLManager.mGLMaxTextureSize);
- mResX = resx;
- mResY = resy;
+ release();
+
+ mResX = resx;
+ mResY = resy;
- mUsage = usage;
+ mUsage = usage;
mUseDepth = depth;
- mSampleDepth = sample_depth;
-
- if ((sUseFBO || use_fbo))
- {
- if (depth)
- {
- if (!allocateDepth())
- {
- LL_WARNS() << "Failed to allocate depth buffer for render target." << LL_ENDL;
- return false;
- }
- }
-
- glGenFramebuffers(1, (GLuint *) &mFBO);
-
- if (mDepth)
- {
- glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
+
+ if (depth)
+ {
+ if (!allocateDepth())
+ {
+ LL_WARNS() << "Failed to allocate depth buffer for render target." << LL_ENDL;
+ return false;
+ }
+ }
+
+ glGenFramebuffers(1, (GLuint *) &mFBO);
+
+ if (mDepth)
+ {
+ glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
- if (!canSampleDepth())
- {
- glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, mDepth);
- }
- else
- {
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, LLTexUnit::getInternalType(mUsage), mDepth, 0);
- stop_glerror();
- }
- glBindFramebuffer(GL_FRAMEBUFFER, sCurFBO);
- }
-
- stop_glerror();
- }
-
- return addColorAttachment(color_fmt);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, LLTexUnit::getInternalType(mUsage), mDepth, 0);
+
+ glBindFramebuffer(GL_FRAMEBUFFER, sCurFBO);
+ }
+
+ return addColorAttachment(color_fmt);
}
void LLRenderTarget::setColorAttachment(LLImageGL* img, LLGLuint use_name)
@@ -175,6 +149,7 @@ void LLRenderTarget::setColorAttachment(LLImageGL* img, LLGLuint use_name)
llassert(sUseFBO); // FBO support must be enabled
llassert(mDepth == 0); // depth buffers not supported with this mode
llassert(mTex.empty()); // mTex must be empty with this mode (binding target should be done via LLImageGL)
+ llassert(!isBoundInStack());
if (mFBO == 0)
{
@@ -205,6 +180,7 @@ void LLRenderTarget::setColorAttachment(LLImageGL* img, LLGLuint use_name)
void LLRenderTarget::releaseColorAttachment()
{
LL_PROFILE_ZONE_SCOPED;
+ llassert(!isBoundInStack());
llassert(mTex.size() == 1); //cannot use releaseColorAttachment with LLRenderTarget managed color targets
llassert(mFBO != 0); // mFBO must be valid
@@ -218,323 +194,291 @@ void LLRenderTarget::releaseColorAttachment()
bool LLRenderTarget::addColorAttachment(U32 color_fmt)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY;
- if (color_fmt == 0)
- {
- return true;
- }
-
- U32 offset = mTex.size();
-
- if( offset >= 4 )
- {
- LL_WARNS() << "Too many color attachments" << LL_ENDL;
- llassert( offset < 4 );
- return false;
- }
- if( offset > 0 && (mFBO == 0) )
- {
- llassert( mFBO != 0 );
- return false;
- }
-
- U32 tex;
- LLImageGL::generateTextures(1, &tex);
- gGL.getTexUnit(0)->bindManual(mUsage, tex);
-
- stop_glerror();
-
-
- {
- clear_glerror();
- LLImageGL::setManualImage(LLTexUnit::getInternalType(mUsage), 0, color_fmt, mResX, mResY, GL_RGBA, GL_UNSIGNED_BYTE, NULL, false);
- if (glGetError() != GL_NO_ERROR)
- {
- LL_WARNS() << "Could not allocate color buffer for render target." << LL_ENDL;
- return false;
- }
- }
-
- sBytesAllocated += mResX*mResY*4;
-
- stop_glerror();
-
-
- if (offset == 0)
- { //use bilinear filtering on single texture render targets that aren't multisampled
- gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
- stop_glerror();
- }
- else
- { //don't filter data attachments
- gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
- stop_glerror();
- }
-
- if (mUsage != LLTexUnit::TT_RECT_TEXTURE)
- {
- gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_MIRROR);
- stop_glerror();
- }
- else
- {
- // ATI doesn't support mirrored repeat for rectangular textures.
- gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
- stop_glerror();
- }
-
- if (mFBO)
- {
- stop_glerror();
- glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+offset,
- LLTexUnit::getInternalType(mUsage), tex, 0);
- stop_glerror();
-
- check_framebuffer_status();
-
- glBindFramebuffer(GL_FRAMEBUFFER, sCurFBO);
- }
-
- mTex.push_back(tex);
- mInternalFormat.push_back(color_fmt);
-
- if (gDebugGL)
- { //bind and unbind to validate target
- bindTarget();
- flush();
- }
+ llassert(!isBoundInStack());
+
+ if (color_fmt == 0)
+ {
+ return true;
+ }
+
+ U32 offset = mTex.size();
+
+ if( offset >= 4 )
+ {
+ LL_WARNS() << "Too many color attachments" << LL_ENDL;
+ llassert( offset < 4 );
+ return false;
+ }
+ if( offset > 0 && (mFBO == 0) )
+ {
+ llassert( mFBO != 0 );
+ return false;
+ }
+
+ U32 tex;
+ LLImageGL::generateTextures(1, &tex);
+ gGL.getTexUnit(0)->bindManual(mUsage, tex);
+
+ stop_glerror();
+
+
+ {
+ clear_glerror();
+ LLImageGL::setManualImage(LLTexUnit::getInternalType(mUsage), 0, color_fmt, mResX, mResY, GL_RGBA, GL_UNSIGNED_BYTE, NULL, false);
+ if (glGetError() != GL_NO_ERROR)
+ {
+ LL_WARNS() << "Could not allocate color buffer for render target." << LL_ENDL;
+ return false;
+ }
+ }
+
+ sBytesAllocated += mResX*mResY*4;
+
+ stop_glerror();
+
+
+ if (offset == 0)
+ { //use bilinear filtering on single texture render targets that aren't multisampled
+ gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
+ stop_glerror();
+ }
+ else
+ { //don't filter data attachments
+ gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+ stop_glerror();
+ }
+
+ if (mUsage != LLTexUnit::TT_RECT_TEXTURE)
+ {
+ gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_MIRROR);
+ stop_glerror();
+ }
+ else
+ {
+ // ATI doesn't support mirrored repeat for rectangular textures.
+ gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
+ stop_glerror();
+ }
+
+ if (mFBO)
+ {
+ glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+offset,
+ LLTexUnit::getInternalType(mUsage), tex, 0);
+
+ check_framebuffer_status();
+
+ glBindFramebuffer(GL_FRAMEBUFFER, sCurFBO);
+ }
+
+ mTex.push_back(tex);
+ mInternalFormat.push_back(color_fmt);
+
+ if (gDebugGL)
+ { //bind and unbind to validate target
+ bindTarget();
+ flush();
+ }
- return true;
+ return true;
}
bool LLRenderTarget::allocateDepth()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY;
- if (!mSampleDepth)
- {
- //use render buffers if depth buffer won't be sampled
- glGenRenderbuffers(1, (GLuint *) &mDepth);
- glBindRenderbuffer(GL_RENDERBUFFER, mDepth);
- glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, mResX, mResY);
- glBindRenderbuffer(GL_RENDERBUFFER, 0);
- }
- else
- {
- LLImageGL::generateTextures(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);
- gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
- }
-
- sBytesAllocated += mResX*mResY*4;
-
- if (glGetError() != GL_NO_ERROR)
- {
- LL_WARNS() << "Unable to allocate depth buffer for render target." << LL_ENDL;
- return false;
- }
-
- return true;
+ LLImageGL::generateTextures(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);
+ gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+
+ sBytesAllocated += mResX*mResY*4;
+
+ if (glGetError() != GL_NO_ERROR)
+ {
+ LL_WARNS() << "Unable to allocate depth buffer for render target." << LL_ENDL;
+ return false;
+ }
+
+ return true;
}
void LLRenderTarget::shareDepthBuffer(LLRenderTarget& target)
{
- if (!mFBO || !target.mFBO)
- {
- LL_ERRS() << "Cannot share depth buffer between non FBO render targets." << LL_ENDL;
- }
-
- if (target.mDepth)
- {
- LL_ERRS() << "Attempting to override existing depth buffer. Detach existing buffer first." << LL_ENDL;
- }
-
- if (target.mUseDepth)
- {
- LL_ERRS() << "Attempting to override existing shared depth buffer. Detach existing buffer first." << LL_ENDL;
- }
-
- if (mDepth)
- {
- glBindFramebuffer(GL_FRAMEBUFFER, target.mFBO);
-
- if (!mSampleDepth)
- {
- glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, mDepth);
- }
- else
- {
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, LLTexUnit::getInternalType(mUsage), mDepth, 0);
- }
-
- check_framebuffer_status();
-
- glBindFramebuffer(GL_FRAMEBUFFER, sCurFBO);
-
- target.mUseDepth = true;
- }
+ llassert(!isBoundInStack());
+
+ if (!mFBO || !target.mFBO)
+ {
+ LL_ERRS() << "Cannot share depth buffer between non FBO render targets." << LL_ENDL;
+ }
+
+ if (target.mDepth)
+ {
+ LL_ERRS() << "Attempting to override existing depth buffer. Detach existing buffer first." << LL_ENDL;
+ }
+
+ if (target.mUseDepth)
+ {
+ LL_ERRS() << "Attempting to override existing shared depth buffer. Detach existing buffer first." << LL_ENDL;
+ }
+
+ if (mDepth)
+ {
+ glBindFramebuffer(GL_FRAMEBUFFER, target.mFBO);
+
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, LLTexUnit::getInternalType(mUsage), mDepth, 0);
+
+ check_framebuffer_status();
+
+ glBindFramebuffer(GL_FRAMEBUFFER, sCurFBO);
+
+ target.mUseDepth = true;
+ }
}
void LLRenderTarget::release()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY;
- if (mDepth)
- {
- if (!mSampleDepth)
- {
- glDeleteRenderbuffers(1, (GLuint*) &mDepth);
- }
- else
- {
- LLImageGL::deleteTextures(1, &mDepth);
- }
- mDepth = 0;
-
- sBytesAllocated -= mResX*mResY*4;
- }
- else if (mFBO)
- {
- glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
-
- if (mUseDepth)
- { //detach shared depth buffer
- if (!mSampleDepth)
- { //attached as a renderbuffer
- glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
- mSampleDepth = false;
- }
- else
- { //attached as a texture
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, LLTexUnit::getInternalType(mUsage), 0, 0);
- }
- mUseDepth = false;
- }
- }
-
- // Detach any extra color buffers (e.g. SRGB spec buffers)
- //
- if (mFBO && (mTex.size() > 1))
- {
- glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
- S32 z;
- for (z = mTex.size() - 1; z >= 1; z--)
- {
- sBytesAllocated -= mResX*mResY*4;
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+z, LLTexUnit::getInternalType(mUsage), 0, 0);
- stop_glerror();
- LLImageGL::deleteTextures(1, &mTex[z]);
- }
- }
-
- if (mFBO)
- {
- glDeleteFramebuffers(1, (GLuint *) &mFBO);
- stop_glerror();
- mFBO = 0;
- }
-
- if (mTex.size() > 0)
- {
- sBytesAllocated -= mResX*mResY*4;
- LLImageGL::deleteTextures(1, &mTex[0]);
- }
-
- mTex.clear();
- mInternalFormat.clear();
-
- mResX = mResY = 0;
-
- sBoundTarget = NULL;
+ llassert(!isBoundInStack());
+
+ if (mDepth)
+ {
+ LLImageGL::deleteTextures(1, &mDepth);
+
+ mDepth = 0;
+
+ sBytesAllocated -= mResX*mResY*4;
+ }
+ else if (mFBO)
+ {
+ glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
+
+ if (mUseDepth)
+ { //detach shared depth buffer
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, LLTexUnit::getInternalType(mUsage), 0, 0);
+ mUseDepth = false;
+ }
+
+ glBindFramebuffer(GL_FRAMEBUFFER, sCurFBO);
+ }
+
+ // Detach any extra color buffers (e.g. SRGB spec buffers)
+ //
+ if (mFBO && (mTex.size() > 1))
+ {
+ glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
+ S32 z;
+ for (z = mTex.size() - 1; z >= 1; z--)
+ {
+ sBytesAllocated -= mResX*mResY*4;
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+z, LLTexUnit::getInternalType(mUsage), 0, 0);
+ LLImageGL::deleteTextures(1, &mTex[z]);
+ }
+ glBindFramebuffer(GL_FRAMEBUFFER, sCurFBO);
+ }
+
+ if (mFBO == sCurFBO)
+ {
+ sCurFBO = 0;
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ }
+
+ if (mFBO)
+ {
+ glDeleteFramebuffers(1, (GLuint *) &mFBO);
+ mFBO = 0;
+ }
+
+ if (mTex.size() > 0)
+ {
+ sBytesAllocated -= mResX*mResY*4;
+ LLImageGL::deleteTextures(1, &mTex[0]);
+ }
+
+ mTex.clear();
+ mInternalFormat.clear();
+
+ mResX = mResY = 0;
}
void LLRenderTarget::bindTarget()
{
LL_PROFILE_GPU_ZONE("bindTarget");
llassert(mFBO);
+ llassert(!isBoundInStack());
+
+ glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
+ sCurFBO = mFBO;
+
+ //setup multiple render targets
+ GLenum drawbuffers[] = {GL_COLOR_ATTACHMENT0,
+ GL_COLOR_ATTACHMENT1,
+ GL_COLOR_ATTACHMENT2,
+ GL_COLOR_ATTACHMENT3};
+ glDrawBuffers(mTex.size(), drawbuffers);
+
+ if (mTex.empty())
+ { //no color buffer to draw to
+ glDrawBuffer(GL_NONE);
+ glReadBuffer(GL_NONE);
+ }
- if (mFBO)
- {
- stop_glerror();
-
- mPreviousFBO = sCurFBO;
- glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
- sCurFBO = mFBO;
-
- stop_glerror();
- //setup multiple render targets
- GLenum drawbuffers[] = {GL_COLOR_ATTACHMENT0,
- GL_COLOR_ATTACHMENT1,
- GL_COLOR_ATTACHMENT2,
- GL_COLOR_ATTACHMENT3};
- glDrawBuffers(mTex.size(), drawbuffers);
-
- if (mTex.empty())
- { //no color buffer to draw to
- glDrawBuffer(GL_NONE);
- glReadBuffer(GL_NONE);
- }
-
- check_framebuffer_status();
-
- stop_glerror();
- }
-
- mPreviousResX = sCurResX;
- mPreviousResY = sCurResY;
- glViewport(0, 0, mResX, mResY);
- sCurResX = mResX;
- sCurResY = mResY;
-
- sBoundTarget = this;
+ check_framebuffer_status();
+
+ glViewport(0, 0, mResX, mResY);
+ sCurResX = mResX;
+ sCurResY = mResY;
+
+ mPreviousRT = sBoundTarget;
+ sBoundTarget = this;
}
void LLRenderTarget::clear(U32 mask_in)
{
LL_PROFILE_GPU_ZONE("clear");
llassert(mFBO);
- U32 mask = GL_COLOR_BUFFER_BIT;
- if (mUseDepth)
- {
- mask |= GL_DEPTH_BUFFER_BIT; // stencil buffer is deprecated, performance pnealty | GL_STENCIL_BUFFER_BIT;
+ U32 mask = GL_COLOR_BUFFER_BIT;
+ if (mUseDepth)
+ {
+ mask |= GL_DEPTH_BUFFER_BIT;
- }
- if (mFBO)
- {
- check_framebuffer_status();
- stop_glerror();
- glClear(mask & mask_in);
- stop_glerror();
- }
- else
- {
- LLGLEnable scissor(GL_SCISSOR_TEST);
- glScissor(0, 0, mResX, mResY);
- stop_glerror();
- glClear(mask & mask_in);
- }
+ }
+ if (mFBO)
+ {
+ check_framebuffer_status();
+ stop_glerror();
+ glClear(mask & mask_in);
+ stop_glerror();
+ }
+ else
+ {
+ LLGLEnable scissor(GL_SCISSOR_TEST);
+ glScissor(0, 0, mResX, mResY);
+ stop_glerror();
+ glClear(mask & mask_in);
+ }
}
U32 LLRenderTarget::getTexture(U32 attachment) const
{
- if (attachment > mTex.size()-1)
- {
- LL_ERRS() << "Invalid attachment index." << LL_ENDL;
- }
- if (mTex.empty())
- {
- return 0;
- }
- return mTex[attachment];
+ if (attachment > mTex.size()-1)
+ {
+ LL_ERRS() << "Invalid attachment index." << LL_ENDL;
+ }
+ if (mTex.empty())
+ {
+ return 0;
+ }
+ return mTex[attachment];
}
U32 LLRenderTarget::getNumTextures() const
{
- return mTex.size();
+ return mTex.size();
}
void LLRenderTarget::bindTexture(U32 index, S32 channel, LLTexUnit::eTextureFilterOptions filter_options)
@@ -560,64 +504,54 @@ void LLRenderTarget::bindTexture(U32 index, S32 channel, LLTexUnit::eTextureFilt
gGL.getTexUnit(channel)->setTextureColorSpace(isSRGB ? LLTexUnit::TCS_SRGB : LLTexUnit::TCS_LINEAR);
}
-void LLRenderTarget::flush(bool fetch_depth)
+void LLRenderTarget::flush()
{
LL_PROFILE_GPU_ZONE("rt flush");
- gGL.flush();
+ gGL.flush();
llassert(mFBO);
- if (!mFBO)
- {
- gGL.getTexUnit(0)->bind(this);
- glCopyTexSubImage2D(LLTexUnit::getInternalType(mUsage), 0, 0, 0, 0, 0, mResX, mResY);
-
- if (fetch_depth)
- {
- if (!mDepth)
- {
- allocateDepth();
- }
-
- gGL.getTexUnit(0)->bind(this);
- glCopyTexImage2D(LLTexUnit::getInternalType(mUsage), 0, GL_DEPTH24_STENCIL8, 0, 0, mResX, mResY, 0);
- }
-
- gGL.getTexUnit(0)->disable();
- }
- else
- {
- stop_glerror();
- glBindFramebuffer(GL_FRAMEBUFFER, mPreviousFBO);
- sCurFBO = mPreviousFBO;
-
- if (mPreviousFBO)
- {
- glViewport(0, 0, mPreviousResX, mPreviousResY);
- sCurResX = mPreviousResX;
- sCurResY = mPreviousResY;
- }
- else
- {
- glViewport(gGLViewport[0],gGLViewport[1],gGLViewport[2],gGLViewport[3]);
- sCurResX = gGLViewport[2];
- sCurResY = gGLViewport[3];
- }
-
- stop_glerror();
- }
+ llassert(sCurFBO == mFBO);
+ llassert(sBoundTarget == this);
+
+ if (mPreviousRT)
+ {
+ // a bit hacky -- pop the RT stack back two frames and push
+ // the previous frame back on to play nice with the GL state machine
+ sBoundTarget = mPreviousRT->mPreviousRT;
+ mPreviousRT->bindTarget();
+ }
+ else
+ {
+ sBoundTarget = nullptr;
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ sCurFBO = 0;
+ glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]);
+ sCurResX = gGLViewport[2];
+ sCurResY = gGLViewport[3];
+ }
}
bool LLRenderTarget::isComplete() const
{
- return (!mTex.empty() || mDepth) ? true : false;
+ return (!mTex.empty() || mDepth) ? true : false;
}
void LLRenderTarget::getViewport(S32* viewport)
{
- viewport[0] = 0;
- viewport[1] = 0;
- viewport[2] = mResX;
- viewport[3] = mResY;
+ viewport[0] = 0;
+ viewport[1] = 0;
+ viewport[2] = mResX;
+ viewport[3] = mResY;
}
+bool LLRenderTarget::isBoundInStack() const
+{
+ LLRenderTarget* cur = sBoundTarget;
+ while (cur && cur != this)
+ {
+ cur = cur->mPreviousRT;
+ }
+
+ return cur == this;
+}
diff --git a/indra/llrender/llrendertarget.h b/indra/llrender/llrendertarget.h
index 5f3214add3..71727bf09d 100644
--- a/indra/llrender/llrendertarget.h
+++ b/indra/llrender/llrendertarget.h
@@ -33,6 +33,8 @@
#include "llrender.h"
/*
+ Wrapper around OpenGL framebuffer objects for use in render-to-texture
+
SAMPLE USAGE:
LLRenderTarget target;
@@ -73,7 +75,12 @@ public:
//allocate resources for rendering
//must be called before use
//multiple calls will release previously allocated resources
- bool allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, bool sample_depth, LLTexUnit::eTextureType usage = LLTexUnit::TT_TEXTURE, bool use_fbo = false, S32 samples = 0);
+ // resX - width
+ // resY - height
+ // color_fmt - GL color format (e.g. GL_RGB)
+ // depth - if true, allocate a depth buffer
+ // usage - deprecated, should always be TT_TEXTURE
+ bool allocate(U32 resx, U32 resy, U32 color_fmt, bool depth = false, LLTexUnit::eTextureType usage = LLTexUnit::TT_TEXTURE);
//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
@@ -93,7 +100,7 @@ public:
// attachment -- LLImageGL to render into
// use_name -- optional texture name to target instead of attachment->getTexName()
// NOTE: setColorAttachment and releaseColorAttachment cannot be used in conjuction with
- // addColorAttachment, allocateDepth, resize, etc.
+ // addColorAttachment, allocateDepth, resize, etc.
void setColorAttachment(LLImageGL* attachment, LLGLuint use_name = 0);
// detach from current color attachment
@@ -111,14 +118,19 @@ public:
//free any allocated resources
//safe to call redundantly
+ // asserts that this target is not currently bound or present in the RT stack
void release();
//bind target for rendering
//applies appropriate viewport
+ // If an LLRenderTarget is currently bound, stores a reference to that LLRenderTarget
+ // and restores previous binding on flush() (maintains a stack of Render Targets)
+ // Asserts that this target is not currently bound in the stack
void bindTarget();
//clear render targer, clears depth buffer if present,
//uses scissor rect if in copy-to-texture mode
+ // asserts that this target is currently bound
void clear(U32 mask = 0xFFFFFFFF);
//get applied viewport
@@ -136,7 +148,6 @@ public:
U32 getNumTextures() const;
U32 getDepth(void) const { return mDepth; }
- bool canSampleDepth() const { return mSampleDepth; }
void bindTexture(U32 index, S32 channel, LLTexUnit::eTextureFilterOptions filter_options = LLTexUnit::TFO_BILINEAR);
@@ -144,15 +155,18 @@ public:
//must be called when rendering is complete
//should be used 1:1 with bindTarget
// call bindTarget once, do all your rendering, call flush once
- // if fetch_depth is TRUE, every effort will be made to copy the depth buffer into
- // the current depth texture. A depth texture will be allocated if needed.
- void flush(bool fetch_depth = FALSE);
+ // If an LLRenderTarget was bound when bindTarget was called, binds that RenderTarget for rendering (maintains RT stack)
+ // asserts that this target is currently bound
+ void flush();
//Returns TRUE if target is ready to be rendered into.
//That is, if the target has been allocated with at least
//one renderable attachment (i.e. color buffer, depth buffer).
bool isComplete() const;
+ // Returns true if this RenderTarget is bound somewhere in the stack
+ bool isBoundInStack() const;
+
static LLRenderTarget* getCurrentBoundTarget() { return sBoundTarget; }
protected:
@@ -161,13 +175,10 @@ protected:
std::vector<U32> mTex;
std::vector<U32> mInternalFormat;
U32 mFBO;
- U32 mPreviousFBO;
- U32 mPreviousResX;
- U32 mPreviousResY;
+ LLRenderTarget* mPreviousRT = nullptr;
- U32 mDepth;
+ U32 mDepth;
bool mUseDepth;
- bool mSampleDepth;
LLTexUnit::eTextureType mUsage;
diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp
index 6001b011ee..27ac4053df 100644
--- a/indra/llrender/llshadermgr.cpp
+++ b/indra/llrender/llshadermgr.cpp
@@ -222,7 +222,7 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
}
}
- if (features->hasScreenSpaceReflections)
+ if (features->hasScreenSpaceReflections || features->hasReflectionProbes)
{
if (!shader->attachFragmentObject("deferred/screenSpaceReflUtil.glsl"))
{
@@ -1244,6 +1244,8 @@ void LLShaderMgr::initAttribsAndUniforms()
mReservedUniforms.push_back("bumpMap");
mReservedUniforms.push_back("bumpMap2");
mReservedUniforms.push_back("environmentMap");
+ mReservedUniforms.push_back("sceneMap");
+ mReservedUniforms.push_back("sceneDepth");
mReservedUniforms.push_back("reflectionProbes");
mReservedUniforms.push_back("irradianceProbes");
mReservedUniforms.push_back("cloud_noise_texture");
@@ -1323,6 +1325,10 @@ void LLShaderMgr::initAttribsAndUniforms()
llassert(mReservedUniforms.size() == LLShaderMgr::DEFERRED_SHADOW_TARGET_WIDTH+1);
+ mReservedUniforms.push_back("modelview_delta");
+ mReservedUniforms.push_back("inv_modelview_delta");
+ mReservedUniforms.push_back("cube_snapshot");
+
mReservedUniforms.push_back("tc_scale");
mReservedUniforms.push_back("rcp_screen_res");
mReservedUniforms.push_back("rcp_frame_opt");
diff --git a/indra/llrender/llshadermgr.h b/indra/llrender/llshadermgr.h
index f6abfe9027..86ada6c132 100644
--- a/indra/llrender/llshadermgr.h
+++ b/indra/llrender/llshadermgr.h
@@ -90,6 +90,8 @@ public:
BUMP_MAP, // "bumpMap"
BUMP_MAP2, // "bumpMap2"
ENVIRONMENT_MAP, // "environmentMap"
+ SCENE_MAP, // "sceneMap"
+ SCENE_DEPTH, // "sceneDepth"
REFLECTION_PROBES, // "reflectionProbes"
IRRADIANCE_PROBES, // "irradianceProbes"
CLOUD_NOISE_MAP, // "cloud_noise_texture"
@@ -158,6 +160,10 @@ public:
DEFERRED_NORM_CUTOFF, // "norm_cutoff"
DEFERRED_SHADOW_TARGET_WIDTH, // "shadow_target_width"
+ MODELVIEW_DELTA_MATRIX, // "modelview_delta"
+ INVERSE_MODELVIEW_DELTA_MATRIX, // "inv_modelview_delta"
+ CUBE_SNAPSHOT, // "cube_snapshot"
+
FXAA_TC_SCALE, // "tc_scale"
FXAA_RCP_SCREEN_RES, // "rcp_screen_res"
FXAA_RCP_FRAME_OPT, // "rcp_frame_opt"
diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp
index 40ab4a2e0f..11e2b6e5c4 100644
--- a/indra/llrender/llvertexbuffer.cpp
+++ b/indra/llrender/llvertexbuffer.cpp
@@ -744,7 +744,7 @@ void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indi
void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const
{
- drawRange(mode, 0, mNumVerts, count, indices_offset);
+ drawRange(mode, 0, mNumVerts-1, count, indices_offset);
}