From 90446056fc95b3fa1f770905e9169c11afeeaf21 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 3 Mar 2026 01:51:39 +0000 Subject: [PATCH 1/5] Initial plan From f83e0c00425319a7debd71a8b11031784f90068f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 3 Mar 2026 02:10:19 +0000 Subject: [PATCH 2/5] Add glInvalidateFramebuffer to discard FBO depth/stencil on ANGLE When deactivating an FBO render target, call glInvalidateFramebuffer to hint that depth/stencil data is no longer needed. Without this, ANGLE (Windows/Android WebGL backend) performs an expensive depth/stencil resolve/copy when switching away from the FBO, causing severe render-to-texture performance degradation. This is especially visible in the planar reflection sample. The function is core in GLES 3.0 (always available on WebGL 2.0) and optionally loaded on desktop GL 3.3+ (GL 4.3 / ARB_invalidate_subdata). Co-authored-by: kaetemi <1581053+kaetemi@users.noreply.github.com> --- .../3d/driver/opengl3/driver_opengl3_extension.cpp | 4 ++++ .../3d/driver/opengl3/driver_opengl3_extension.h | 2 ++ .../3d/driver/opengl3/driver_opengl3_texture.cpp | 14 ++++++++++++++ 3 files changed, 20 insertions(+) diff --git a/nel/src/3d/driver/opengl3/driver_opengl3_extension.cpp b/nel/src/3d/driver/opengl3/driver_opengl3_extension.cpp index 2cfd037a06..0f92c84d38 100644 --- a/nel/src/3d/driver/opengl3/driver_opengl3_extension.cpp +++ b/nel/src/3d/driver/opengl3/driver_opengl3_extension.cpp @@ -183,6 +183,7 @@ PFNGLGENERATEMIPMAPPROC nglGenerateMipmap; PFNGLBLITFRAMEBUFFERPROC nglBlitFramebuffer; PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC nglRenderbufferStorageMultisample; PFNGLFRAMEBUFFERTEXTURELAYERPROC nglFramebufferTextureLayer; +PFNGLINVALIDATEFRAMEBUFFERPROC nglInvalidateFramebuffer; PFNGLACTIVETEXTUREPROC nglActiveTexture; @@ -503,6 +504,9 @@ static bool setupGLCore(std::vector &glext) CHECK_ADDRESS(PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC, glRenderbufferStorageMultisample); CHECK_ADDRESS(PFNGLFRAMEBUFFERTEXTURELAYERPROC, glFramebufferTextureLayer); + // GL 4.3 / ARB_invalidate_subdata: optional on GL 3.3, always available on GLES 3.0 + nglInvalidateFramebuffer = (PFNGLINVALIDATEFRAMEBUFFERPROC)nglGetProcAddress("glInvalidateFramebuffer"); + CHECK_ADDRESS(PFNGLACTIVETEXTUREPROC, glActiveTexture); CHECK_ADDRESS(PFNGLCOMPRESSEDTEXIMAGE3DPROC, glCompressedTexImage3D); diff --git a/nel/src/3d/driver/opengl3/driver_opengl3_extension.h b/nel/src/3d/driver/opengl3/driver_opengl3_extension.h index 136197a970..9ccf1b24bf 100644 --- a/nel/src/3d/driver/opengl3/driver_opengl3_extension.h +++ b/nel/src/3d/driver/opengl3/driver_opengl3_extension.h @@ -284,6 +284,7 @@ namespace NLDRIVERGL3 { #define nglBlitFramebuffer glBlitFramebuffer #define nglRenderbufferStorageMultisample glRenderbufferStorageMultisample #define nglFramebufferTextureLayer glFramebufferTextureLayer +#define nglInvalidateFramebuffer glInvalidateFramebuffer #define nglActiveTexture glActiveTexture @@ -491,6 +492,7 @@ extern PFNGLGENERATEMIPMAPPROC nglGenerateMipmap; extern PFNGLBLITFRAMEBUFFERPROC nglBlitFramebuffer; extern PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC nglRenderbufferStorageMultisample; extern PFNGLFRAMEBUFFERTEXTURELAYERPROC nglFramebufferTextureLayer; +extern PFNGLINVALIDATEFRAMEBUFFERPROC nglInvalidateFramebuffer; extern PFNGLACTIVETEXTUREPROC nglActiveTexture; diff --git a/nel/src/3d/driver/opengl3/driver_opengl3_texture.cpp b/nel/src/3d/driver/opengl3/driver_opengl3_texture.cpp index c27b84a6e3..ae0a60bfd4 100644 --- a/nel/src/3d/driver/opengl3/driver_opengl3_texture.cpp +++ b/nel/src/3d/driver/opengl3/driver_opengl3_texture.cpp @@ -254,6 +254,20 @@ bool CTextureDrvInfosGL3::activeFrameBufferObject(ITexture * tex) } else { + // Invalidate depth/stencil attachments before unbinding the FBO. + // On ANGLE (Windows/Android WebGL), switching away from an FBO without + // invalidating forces an expensive depth/stencil resolve/copy. This hint + // tells the driver the data is no longer needed, avoiding the stall. + if (AttachDepthStencil) + { + const GLenum attachments[2] = { GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT }; +#ifdef USE_OPENGLES3 + nglInvalidateFramebuffer(GL_FRAMEBUFFER, 2, attachments); +#else + if (nglInvalidateFramebuffer) + nglInvalidateFramebuffer(GL_FRAMEBUFFER, 2, attachments); +#endif + } _Driver->_DriverGLStates.forceBindFramebuffer(0); } From bbd1a05d4aae796a991c196707910048d755cef1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 3 Mar 2026 03:29:17 +0000 Subject: [PATCH 3/5] Fix: add glInvalidateFramebuffer to correct code paths MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous fix placed glInvalidateFramebuffer in CTextureDrvInfosGL3::activeFrameBufferObject(NULL), but setRenderTarget(NULL) calls CDriverGL3::activeFrameBufferObject(NULL) which bypasses it entirely — going straight to forceBindFramebuffer(0). Fix unbind path: Add invalidation in CDriverGL3::activeFrameBufferObject (driver_opengl3.cpp) which is the actual code path called by setRenderTarget(NULL). Tells ANGLE not to store depth/stencil data. Fix bind path: Add invalidation in CTextureDrvInfosGL3::activeFrameBufferObject(tex) after binding the FBO. Tells ANGLE not to load previous depth/stencil data into the new render pass (VK_ATTACHMENT_LOAD_OP_DONT_CARE on Vulkan backend, avoids blit on D3D11 backend). Co-authored-by: kaetemi <1581053+kaetemi@users.noreply.github.com> --- nel/src/3d/driver/opengl3/driver_opengl3.cpp | 11 +++++++++++ .../3d/driver/opengl3/driver_opengl3_texture.cpp | 15 +++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/nel/src/3d/driver/opengl3/driver_opengl3.cpp b/nel/src/3d/driver/opengl3/driver_opengl3.cpp index d6b70ced80..cfafcc403d 100644 --- a/nel/src/3d/driver/opengl3/driver_opengl3.cpp +++ b/nel/src/3d/driver/opengl3/driver_opengl3.cpp @@ -710,6 +710,17 @@ bool CDriverGL3::activeFrameBufferObject(ITexture * tex) } else { + // Invalidate depth/stencil attachments before unbinding the FBO. + // On ANGLE (Windows/Android WebGL), switching away from an FBO without + // invalidating forces an expensive depth/stencil resolve/copy. This hint + // tells the driver the data is no longer needed, avoiding the stall. + const GLenum attachments[2] = { GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT }; +#ifdef USE_OPENGLES3 + nglInvalidateFramebuffer(GL_FRAMEBUFFER, 2, attachments); +#else + if (nglInvalidateFramebuffer) + nglInvalidateFramebuffer(GL_FRAMEBUFFER, 2, attachments); +#endif _DriverGLStates.forceBindFramebuffer(0); return true; } diff --git a/nel/src/3d/driver/opengl3/driver_opengl3_texture.cpp b/nel/src/3d/driver/opengl3/driver_opengl3_texture.cpp index ae0a60bfd4..d4a30412e6 100644 --- a/nel/src/3d/driver/opengl3/driver_opengl3_texture.cpp +++ b/nel/src/3d/driver/opengl3/driver_opengl3_texture.cpp @@ -248,6 +248,21 @@ bool CTextureDrvInfosGL3::activeFrameBufferObject(ITexture * tex) { _Driver->_DriverGLStates.forceBindTexture(TextureMode, 0); _Driver->_DriverGLStates.forceBindFramebuffer(FBOId); + + // Invalidate depth/stencil after binding the FBO. + // Tells ANGLE not to load previous depth/stencil data into the + // new render pass (LOAD_OP_DONT_CARE), avoiding an expensive blit. + // The application is expected to clear depth/stencil before use. + if (AttachDepthStencil) + { + const GLenum attachments[2] = { GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT }; +#ifdef USE_OPENGLES3 + nglInvalidateFramebuffer(GL_FRAMEBUFFER, 2, attachments); +#else + if (nglInvalidateFramebuffer) + nglInvalidateFramebuffer(GL_FRAMEBUFFER, 2, attachments); +#endif + } } else return false; From 1054aa55a10169c8a59ef57508d8ee23f604b8b7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 3 Mar 2026 04:43:10 +0000 Subject: [PATCH 4/5] Fix extension detection and remove counterproductive bind-time invalidation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Add proper GL_ARB_invalidate_subdata extension detection instead of gambling on the function address. The extension flag is checked via the standard extension string mechanism (setupARBInvalidateSubdata + CHECK_EXT_2), not by testing whether nglGetProcAddress returned non-null (which can succeed even when the extension is absent). 2. Remove bind-time glInvalidateFramebuffer in activeFrameBufferObject(tex). Calling invalidate right after binding prevents ANGLE from merging the subsequent clearBuffers() into a LOAD_OP_CLEAR render pass. Instead, ANGLE sees LOAD_OP_DONT_CARE (from invalidation) then issues a slower mid-pass vkCmdClearAttachments. Without the invalidation, ANGLE sees the clear first and uses the optimal LOAD_OP_CLEAR. 3. Keep unbind-time invalidation (STORE_OP_DONT_CARE) which is the actually beneficial hint — tells ANGLE not to resolve/store depth/stencil when switching away from the FBO. Co-authored-by: kaetemi <1581053+kaetemi@users.noreply.github.com> --- nel/src/3d/driver/opengl3/driver_opengl3.cpp | 3 ++- .../opengl3/driver_opengl3_extension.cpp | 11 +++++++++ .../driver/opengl3/driver_opengl3_extension.h | 3 +++ .../driver/opengl3/driver_opengl3_texture.cpp | 23 ++++++------------- 4 files changed, 23 insertions(+), 17 deletions(-) diff --git a/nel/src/3d/driver/opengl3/driver_opengl3.cpp b/nel/src/3d/driver/opengl3/driver_opengl3.cpp index cfafcc403d..2dc27ae3db 100644 --- a/nel/src/3d/driver/opengl3/driver_opengl3.cpp +++ b/nel/src/3d/driver/opengl3/driver_opengl3.cpp @@ -714,11 +714,12 @@ bool CDriverGL3::activeFrameBufferObject(ITexture * tex) // On ANGLE (Windows/Android WebGL), switching away from an FBO without // invalidating forces an expensive depth/stencil resolve/copy. This hint // tells the driver the data is no longer needed, avoiding the stall. + // (STORE_OP_DONT_CARE on Vulkan, DiscardView on D3D11) const GLenum attachments[2] = { GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT }; #ifdef USE_OPENGLES3 nglInvalidateFramebuffer(GL_FRAMEBUFFER, 2, attachments); #else - if (nglInvalidateFramebuffer) + if (_Extensions.ARBInvalidateSubdata) nglInvalidateFramebuffer(GL_FRAMEBUFFER, 2, attachments); #endif _DriverGLStates.forceBindFramebuffer(0); diff --git a/nel/src/3d/driver/opengl3/driver_opengl3_extension.cpp b/nel/src/3d/driver/opengl3/driver_opengl3_extension.cpp index 0f92c84d38..122323e2e2 100644 --- a/nel/src/3d/driver/opengl3/driver_opengl3_extension.cpp +++ b/nel/src/3d/driver/opengl3/driver_opengl3_extension.cpp @@ -607,6 +607,14 @@ static bool setupAMDPinnedMemory(std::vector &glext) return true; } +// ********************************* +static bool setupARBInvalidateSubdata(std::vector &glext) +{ + CHECK_EXT_2("GL_ARB_invalidate_subdata"); + + return true; +} + // ********************************* static bool setupNVXGPUMemoryInfo(std::vector &glext) { @@ -705,6 +713,9 @@ bool registerGlExtensions(CGlExtensions &ext) // Check GL_AMD_pinned_memory ext.AMDPinnedMemory = false; // setupAMDPinnedMemory(glext); // TODO: Proper frame sync check + // Check GL_ARB_invalidate_subdata (GL 4.3 core; optional on GL 3.3) + ext.ARBInvalidateSubdata = setupARBInvalidateSubdata(glext); + // Memory info extensions ext.NVXGPUMemoryInfo = setupNVXGPUMemoryInfo(glext); ext.ATIMeminfo = setupATIMeminfo(glext); diff --git a/nel/src/3d/driver/opengl3/driver_opengl3_extension.h b/nel/src/3d/driver/opengl3/driver_opengl3_extension.h index 9ccf1b24bf..4a2402d4c0 100644 --- a/nel/src/3d/driver/opengl3/driver_opengl3_extension.h +++ b/nel/src/3d/driver/opengl3/driver_opengl3_extension.h @@ -52,6 +52,7 @@ struct CGlExtensions bool EXTTextureCompressionS3TC; bool EXTTextureFilterAnisotropic; float EXTTextureFilterAnisotropicMaximum; + bool ARBInvalidateSubdata; bool AMDPinnedMemory; // Extensions to get memory info @@ -95,6 +96,7 @@ struct CGlExtensions EXTTextureCompressionS3TC = false; EXTTextureFilterAnisotropic = false; EXTTextureFilterAnisotropicMaximum = 0.f; + ARBInvalidateSubdata = false; AMDPinnedMemory = false; NVXGPUMemoryInfo = false; @@ -133,6 +135,7 @@ struct CGlExtensions result += "\n Buffers: "; result += AMDPinnedMemory ? "AMDPinnedMemory " : ""; + result += ARBInvalidateSubdata ? "ARBInvalidateSubdata " : ""; result += "\n Memory info: "; result += NVXGPUMemoryInfo ? "NVXGPUMemoryInfo " : ""; diff --git a/nel/src/3d/driver/opengl3/driver_opengl3_texture.cpp b/nel/src/3d/driver/opengl3/driver_opengl3_texture.cpp index d4a30412e6..efd7856fb9 100644 --- a/nel/src/3d/driver/opengl3/driver_opengl3_texture.cpp +++ b/nel/src/3d/driver/opengl3/driver_opengl3_texture.cpp @@ -248,21 +248,11 @@ bool CTextureDrvInfosGL3::activeFrameBufferObject(ITexture * tex) { _Driver->_DriverGLStates.forceBindTexture(TextureMode, 0); _Driver->_DriverGLStates.forceBindFramebuffer(FBOId); - - // Invalidate depth/stencil after binding the FBO. - // Tells ANGLE not to load previous depth/stencil data into the - // new render pass (LOAD_OP_DONT_CARE), avoiding an expensive blit. - // The application is expected to clear depth/stencil before use. - if (AttachDepthStencil) - { - const GLenum attachments[2] = { GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT }; -#ifdef USE_OPENGLES3 - nglInvalidateFramebuffer(GL_FRAMEBUFFER, 2, attachments); -#else - if (nglInvalidateFramebuffer) - nglInvalidateFramebuffer(GL_FRAMEBUFFER, 2, attachments); -#endif - } + // Do NOT invalidate depth/stencil here at bind time. + // The application clears depth/stencil immediately after binding, + // which allows ANGLE to use LOAD_OP_CLEAR for the render pass. + // An invalidation here would downgrade that to LOAD_OP_DONT_CARE + // followed by a mid-pass vkCmdClearAttachments, which is slower. } else return false; @@ -273,13 +263,14 @@ bool CTextureDrvInfosGL3::activeFrameBufferObject(ITexture * tex) // On ANGLE (Windows/Android WebGL), switching away from an FBO without // invalidating forces an expensive depth/stencil resolve/copy. This hint // tells the driver the data is no longer needed, avoiding the stall. + // (STORE_OP_DONT_CARE on Vulkan, DiscardView on D3D11) if (AttachDepthStencil) { const GLenum attachments[2] = { GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT }; #ifdef USE_OPENGLES3 nglInvalidateFramebuffer(GL_FRAMEBUFFER, 2, attachments); #else - if (nglInvalidateFramebuffer) + if (_Driver->_Extensions.ARBInvalidateSubdata) nglInvalidateFramebuffer(GL_FRAMEBUFFER, 2, attachments); #endif } From 9f1165819d407769b67889ec388a7a3c79354d86 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 3 Mar 2026 05:28:12 +0000 Subject: [PATCH 5/5] Improve ANGLE/D3D11 render-to-texture performance Three targeted optimizations for ANGLE/D3D11 FBO render target performance: 1. Invalidate default framebuffer depth/stencil before swapBuffers. Depth/stencil data is never needed across frames. Without this hint, ANGLE stores it during present (STORE_OP_STORE on Vulkan, expensive resolve on D3D11). With invalidation, ANGLE can skip the store (DiscardView on D3D11, STORE_OP_DONT_CARE on Vulkan). 2. Add combined clearDepthStencil() using nglClearBufferfi. On ANGLE/D3D11 this maps to a single ClearDepthStencilView call with D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, instead of two separate ClearDepthStencilView calls (one for depth, one for stencil). Used by CDriverUser::clearBuffers() which is the common path. 3. Remove unnecessary enableZWrite(true) from clearZBuffer. glClearBuffer* is not affected by the depth write mask per GL spec. The state change was wasting a D3D11 depth-stencil state update. 4. Route FBO deactivation through texture-level method. setRenderTarget(NULL) now goes through the per-FBO activeFrameBufferObject instead of the driver-level fallback, so the AttachDepthStencil flag is properly checked before invalidating (avoids unnecessary invalidation on FBOs without depth/stencil). Co-authored-by: kaetemi <1581053+kaetemi@users.noreply.github.com> Co-authored-by: kaetemi <1581053+kaetemi@users.noreply.github.com> --- nel/include/nel/3d/driver.h | 3 ++ nel/src/3d/driver/opengl3/driver_opengl3.cpp | 31 ++++++++++++++++++- nel/src/3d/driver/opengl3/driver_opengl3.h | 1 + .../driver/opengl3/driver_opengl3_texture.cpp | 5 ++- nel/src/3d/driver_user.cpp | 3 +- 5 files changed, 39 insertions(+), 4 deletions(-) diff --git a/nel/include/nel/3d/driver.h b/nel/include/nel/3d/driver.h index d1c88e852c..80d0e5b84a 100644 --- a/nel/include/nel/3d/driver.h +++ b/nel/include/nel/3d/driver.h @@ -318,6 +318,9 @@ class IDriver : public NLMISC::CRefCount /// Clear the current target surface stencil buffer. The function ignores the viewport settings but uses the scissor. virtual bool clearStencilBuffer(sint stencilval=0) = 0; + /// Clear both the depth and stencil buffers in one call. Drivers may override for efficiency. + virtual bool clearDepthStencil(float zval=1, sint stencilval=0) { clearZBuffer(zval); clearStencilBuffer(stencilval); return true; } + /// Set the color mask filter through where the operation done will pass virtual void setColorMask(bool bRed, bool bGreen, bool bBlue, bool bAlpha) = 0; // @} diff --git a/nel/src/3d/driver/opengl3/driver_opengl3.cpp b/nel/src/3d/driver/opengl3/driver_opengl3.cpp index 2dc27ae3db..b51b65805b 100644 --- a/nel/src/3d/driver/opengl3/driver_opengl3.cpp +++ b/nel/src/3d/driver/opengl3/driver_opengl3.cpp @@ -765,7 +765,8 @@ bool CDriverGL3::clearZBuffer(float zval) { H_AUTO_OGL(CDriverGL3_clearZBuffer); - _DriverGLStates.enableZWrite(true); + // glClearBufferfv is not affected by the depth write mask (GL spec), + // so enableZWrite(true) is not needed here. nglClearBufferfv(GL_DEPTH, 0, &zval); return true; @@ -781,6 +782,19 @@ bool CDriverGL3::clearStencilBuffer(sint stencilval) return true; } +// -------------------------------------------------- +bool CDriverGL3::clearDepthStencil(float zval, sint stencilval) +{ + H_AUTO_OGL(CDriverGL3_clearDepthStencil) + + // Combined depth/stencil clear: one GL call instead of two. + // On ANGLE/D3D11 this maps to a single ClearDepthStencilView with + // D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, avoiding two separate calls. + nglClearBufferfi(GL_DEPTH_STENCIL, 0, zval, stencilval); + + return true; +} + // -------------------------------------------------- void CDriverGL3::setColorMask (bool bRed, bool bGreen, bool bBlue, bool bAlpha) { @@ -850,6 +864,21 @@ bool CDriverGL3::swapBuffers() _SwapBufferSync[syncI] = nglFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); nlassert(_SwapBufferSync[syncI]); + // Invalidate the default framebuffer's depth/stencil before the swap. + // The depth/stencil data is never needed across frames. Without this hint, + // ANGLE stores the depth/stencil during present (an expensive resolve/copy + // on D3D11, and STORE_OP_STORE on Vulkan). With invalidation, ANGLE can + // skip the store (DiscardView on D3D11, STORE_OP_DONT_CARE on Vulkan). + { + const GLenum attachments[2] = { GL_DEPTH, GL_STENCIL }; +#ifdef USE_OPENGLES3 + nglInvalidateFramebuffer(GL_FRAMEBUFFER, 2, attachments); +#else + if (_Extensions.ARBInvalidateSubdata) + nglInvalidateFramebuffer(GL_FRAMEBUFFER, 2, attachments); +#endif + } + ++_SwapBufferCounter; if (!_WndActive) diff --git a/nel/src/3d/driver/opengl3/driver_opengl3.h b/nel/src/3d/driver/opengl3/driver_opengl3.h index 98cf599a2b..689b085995 100644 --- a/nel/src/3d/driver/opengl3/driver_opengl3.h +++ b/nel/src/3d/driver/opengl3/driver_opengl3.h @@ -542,6 +542,7 @@ class CDriverGL3 : public IDriver virtual bool clearZBuffer(float zval=1); virtual bool clearStencilBuffer(sint stencilval=0); + virtual bool clearDepthStencil(float zval=1, sint stencilval=0); virtual void setColorMask (bool bRed, bool bGreen, bool bBlue, bool bAlpha); virtual void setDepthRange(float znear, float zfar); virtual void getDepthRange(float &znear, float &zfar) const; diff --git a/nel/src/3d/driver/opengl3/driver_opengl3_texture.cpp b/nel/src/3d/driver/opengl3/driver_opengl3_texture.cpp index efd7856fb9..71c5f5b4c3 100644 --- a/nel/src/3d/driver/opengl3/driver_opengl3_texture.cpp +++ b/nel/src/3d/driver/opengl3/driver_opengl3_texture.cpp @@ -1785,7 +1785,10 @@ bool CDriverGL3::setRenderTarget (ITexture *tex, uint32 x, uint32 y, uint32 widt } else if (_RenderTargetFBO) { - activeFrameBufferObject(NULL); + // Deactivate through the texture-level method so it can use per-FBO + // state (e.g. AttachDepthStencil) for conditional invalidation. + CTextureDrvInfosGL3* gltext = (CTextureDrvInfosGL3*)(ITextureDrvInfos*)(_RenderTargetFBO->TextureDrvShare->DrvTexture); + gltext->activeFrameBufferObject(NULL); setupViewport(_OldViewport); _OldViewport = _CurrViewport; diff --git a/nel/src/3d/driver_user.cpp b/nel/src/3d/driver_user.cpp index 9c4c3889e6..79ee670c56 100644 --- a/nel/src/3d/driver_user.cpp +++ b/nel/src/3d/driver_user.cpp @@ -1357,8 +1357,7 @@ void CDriverUser::clearBuffers(CRGBA col) NL3D_HAUTO_CLEAR_DRIVER; _Driver->clear2D(col); - _Driver->clearZBuffer(); - _Driver->clearStencilBuffer(); + _Driver->clearDepthStencil(); } // *************************************************************************** void CDriverUser::swapBuffers()