diff options
author | RunitaiLinden <davep@lindenlab.com> | 2023-01-27 17:24:22 -0600 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-01-27 17:24:22 -0600 |
commit | 3ef31cb9b28f7b026e109eab69d383dddc922850 (patch) | |
tree | eb4034470bbc59bba139a66b053583bb05e3d7c1 /indra/llrender | |
parent | 503e18fc646c6d88cd8006ad2210a8afd0bced83 (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.cpp | 3 | ||||
-rw-r--r-- | indra/llrender/llrender.cpp | 7 | ||||
-rw-r--r-- | indra/llrender/llrender.h | 2 | ||||
-rw-r--r-- | indra/llrender/llrendertarget.cpp | 786 | ||||
-rw-r--r-- | indra/llrender/llrendertarget.h | 33 | ||||
-rw-r--r-- | indra/llrender/llshadermgr.cpp | 8 | ||||
-rw-r--r-- | indra/llrender/llshadermgr.h | 6 | ||||
-rw-r--r-- | indra/llrender/llvertexbuffer.cpp | 2 |
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); } |