From df6abe83a379ab5bc2802e2d838262d4cfdbcede Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 10 Nov 2020 23:30:24 +0100 Subject: [PATCH] Support depth clamping in OpenGL where available. Should make support for depth texturing quite easy. Unfortunately, this extension does not exist on OpenGL ES. There we'll have to use ugly tricks with gl_FragDepth if we want this. --- Common/GPU/OpenGL/GLQueueRunner.cpp | 12 ++++++++++++ Common/GPU/OpenGL/GLQueueRunner.h | 1 + Common/GPU/OpenGL/GLRenderManager.h | 3 ++- Common/GPU/OpenGL/thin3d_gl.cpp | 6 +++++- GPU/GLES/DepthBufferGLES.cpp | 2 +- GPU/GLES/FramebufferManagerGLES.cpp | 2 +- GPU/GLES/GPU_GLES.cpp | 3 +++ GPU/GLES/StateMappingGLES.cpp | 19 ++++++++++++++++++- GPU/GLES/StencilBufferGLES.cpp | 2 +- 9 files changed, 44 insertions(+), 6 deletions(-) diff --git a/Common/GPU/OpenGL/GLQueueRunner.cpp b/Common/GPU/OpenGL/GLQueueRunner.cpp index 2fe56bfac6..d00a4a41ca 100644 --- a/Common/GPU/OpenGL/GLQueueRunner.cpp +++ b/Common/GPU/OpenGL/GLQueueRunner.cpp @@ -793,6 +793,7 @@ void GLQueueRunner::PerformRenderPass(const GLRStep &step, bool first, bool last bool blendEnabled = false; bool cullEnabled = false; bool ditherEnabled = false; + bool depthClampEnabled = false; #ifndef USING_GLES2 int logicOp = -1; bool logicEnabled = false; @@ -1283,6 +1284,15 @@ void GLQueueRunner::PerformRenderPass(const GLRStep &step, bool first, bool last glDisable(GL_DITHER); ditherEnabled = false; } + if (c.raster.depthClampEnable) { + if (!depthClampEnabled) { + glEnable(GL_DEPTH_CLAMP); + depthClampEnabled = true; + } + } else if (!c.raster.depthClampEnable && depthClampEnabled) { + glDisable(GL_DEPTH_CLAMP); + depthClampEnabled = false; + } CHECK_GL_ERROR_IF_DEBUG(); break; default: @@ -1321,6 +1331,8 @@ void GLQueueRunner::PerformRenderPass(const GLRStep &step, bool first, bool last glDisable(GL_BLEND); if (cullEnabled) glDisable(GL_CULL_FACE); + if (depthClampEnabled) + glDisable(GL_DEPTH_CLAMP); #ifndef USING_GLES2 if (!gl_extensions.IsGLES && logicEnabled) { glDisable(GL_COLOR_LOGIC_OP); diff --git a/Common/GPU/OpenGL/GLQueueRunner.h b/Common/GPU/OpenGL/GLQueueRunner.h index 07837421be..8dec753949 100644 --- a/Common/GPU/OpenGL/GLQueueRunner.h +++ b/Common/GPU/OpenGL/GLQueueRunner.h @@ -196,6 +196,7 @@ struct GLRRenderData { GLenum frontFace; GLenum cullFace; GLboolean ditherEnable; + GLboolean depthClampEnable; } raster; }; }; diff --git a/Common/GPU/OpenGL/GLRenderManager.h b/Common/GPU/OpenGL/GLRenderManager.h index 9edd5af35c..b4c3378739 100644 --- a/Common/GPU/OpenGL/GLRenderManager.h +++ b/Common/GPU/OpenGL/GLRenderManager.h @@ -813,13 +813,14 @@ public: curRenderStep_->commands.push_back(data); } - void SetRaster(GLboolean cullEnable, GLenum frontFace, GLenum cullFace, GLboolean ditherEnable) { + void SetRaster(GLboolean cullEnable, GLenum frontFace, GLenum cullFace, GLboolean ditherEnable, GLboolean depthClamp) { _dbg_assert_(curRenderStep_ && curRenderStep_->stepType == GLRStepType::RENDER); GLRRenderData data{ GLRRenderCommand::RASTER }; data.raster.cullEnable = cullEnable; data.raster.frontFace = frontFace; data.raster.cullFace = cullFace; data.raster.ditherEnable = ditherEnable; + data.raster.depthClampEnable = depthClamp; curRenderStep_->commands.push_back(data); } diff --git a/Common/GPU/OpenGL/thin3d_gl.cpp b/Common/GPU/OpenGL/thin3d_gl.cpp index 161c04eecf..1596f4c632 100644 --- a/Common/GPU/OpenGL/thin3d_gl.cpp +++ b/Common/GPU/OpenGL/thin3d_gl.cpp @@ -188,7 +188,7 @@ public: class OpenGLRasterState : public RasterState { public: void Apply(GLRenderManager *render) { - render->SetRaster(cullEnable, frontFace, cullMode, false); + render->SetRaster(cullEnable, frontFace, cullMode, GL_FALSE, GL_FALSE); } GLboolean cullEnable; @@ -533,6 +533,10 @@ OpenGLContext::OpenGLContext() { } caps_.framebufferBlitSupported = gl_extensions.NV_framebuffer_blit || gl_extensions.ARB_framebuffer_object; caps_.framebufferDepthBlitSupported = caps_.framebufferBlitSupported; + caps_.depthClampSupported = gl_extensions.ARB_depth_clamp; + + // Interesting potential hack for emulating GL_DEPTH_CLAMP (use a separate varying, force depth in fragment shader): + // https://stackoverflow.com/questions/5960757/how-to-emulate-gl-depth-clamp-nv switch (gl_extensions.gpuVendor) { case GPU_VENDOR_AMD: caps_.vendor = GPUVendor::VENDOR_AMD; break; diff --git a/GPU/GLES/DepthBufferGLES.cpp b/GPU/GLES/DepthBufferGLES.cpp index 9cd487ae5a..7eae61caa6 100644 --- a/GPU/GLES/DepthBufferGLES.cpp +++ b/GPU/GLES/DepthBufferGLES.cpp @@ -133,7 +133,7 @@ void FramebufferManagerGLES::PackDepthbuffer(VirtualFramebuffer *vfb, int x, int // We must bind the program after starting the render pass, and set the color mask after clearing. render_->SetScissor({ 0, 0, vfb->renderWidth, vfb->renderHeight }); render_->SetDepth(false, false, GL_ALWAYS); - render_->SetRaster(false, GL_CCW, GL_FRONT, GL_FALSE); + render_->SetRaster(false, GL_CCW, GL_FRONT, GL_FALSE, GL_FALSE); render_->BindProgram(depthDownloadProgram_); if (!gstate_c.Supports(GPU_SUPPORTS_ACCURATE_DEPTH)) { diff --git a/GPU/GLES/FramebufferManagerGLES.cpp b/GPU/GLES/FramebufferManagerGLES.cpp index 5870c899ef..f28b4f7016 100644 --- a/GPU/GLES/FramebufferManagerGLES.cpp +++ b/GPU/GLES/FramebufferManagerGLES.cpp @@ -203,7 +203,7 @@ void FramebufferManagerGLES::DrawActiveTexture(float x, float y, float w, float // We always want a plain state here, well, except for when it's used by the stencil stuff... render_->SetDepth(false, false, GL_ALWAYS); - render_->SetRaster(false, GL_CCW, GL_FRONT, GL_FALSE); + render_->SetRaster(false, GL_CCW, GL_FRONT, GL_FALSE, GL_FALSE); if (!(flags & DRAWTEX_KEEP_STENCIL_ALPHA)) { render_->SetNoBlendAndMask(0xF); render_->SetStencilDisabled(); diff --git a/GPU/GLES/GPU_GLES.cpp b/GPU/GLES/GPU_GLES.cpp index d60e1b5592..1f679f323c 100644 --- a/GPU/GLES/GPU_GLES.cpp +++ b/GPU/GLES/GPU_GLES.cpp @@ -221,6 +221,9 @@ void GPU_GLES::CheckGPUFeatures() { if (gl_extensions.ARB_texture_float || gl_extensions.OES_texture_float) features |= GPU_SUPPORTS_TEXTURE_FLOAT; + if (draw_->GetDeviceCaps().depthClampSupported) + features |= GPU_SUPPORTS_DEPTH_CLAMP; + // If we already have a 16-bit depth buffer, we don't need to round. bool prefer24 = draw_->GetDeviceCaps().preferredDepthBufferFormat == Draw::DataFormat::D24_S8; if (prefer24) { diff --git a/GPU/GLES/StateMappingGLES.cpp b/GPU/GLES/StateMappingGLES.cpp index 992695e4a5..9944be9947 100644 --- a/GPU/GLES/StateMappingGLES.cpp +++ b/GPU/GLES/StateMappingGLES.cpp @@ -230,7 +230,24 @@ void DrawEngineGLES::ApplyDrawState(int prim) { GLenum cullMode = cullingMode[gstate.getCullMode() ^ !useBufferedRendering]; cullEnable = !gstate.isModeClear() && prim != GE_PRIM_RECTANGLES && gstate.isCullEnabled(); - renderManager->SetRaster(cullEnable, GL_CCW, cullMode, dither); + + bool depthClampEnable = false; + if (gstate.isModeClear() || gstate.isModeThrough()) { + // TODO: Might happen in clear mode if not through... + depthClampEnable = false; + } else { + // Set cull + if (gstate.getDepthRangeMin() == 0 || gstate.getDepthRangeMax() == 65535) { + // TODO: Still has a bug where we clamp to depth range if one is not the full range. + // But the alternate is not clamping in either direction... + depthClampEnable = gstate.isDepthClampEnabled() && gstate_c.Supports(GPU_SUPPORTS_DEPTH_CLAMP); + } else { + // We just want to clip in this case, the clamp would be clipped anyway. + depthClampEnable = false; + } + } + + renderManager->SetRaster(cullEnable, GL_CCW, cullMode, dither, depthClampEnable); } if (gstate_c.IsDirty(DIRTY_DEPTHSTENCIL_STATE)) { diff --git a/GPU/GLES/StencilBufferGLES.cpp b/GPU/GLES/StencilBufferGLES.cpp index df9cd06193..480690b930 100644 --- a/GPU/GLES/StencilBufferGLES.cpp +++ b/GPU/GLES/StencilBufferGLES.cpp @@ -191,7 +191,7 @@ bool FramebufferManagerGLES::NotifyStencilUpload(u32 addr, int size, StencilUplo render_->SetDepth(false, false, GL_ALWAYS); render_->Clear(0, 0, 0, GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, 0x8, 0, 0, 0, 0); render_->SetStencilFunc(GL_TRUE, GL_ALWAYS, 0xFF, 0xFF); - render_->SetRaster(false, GL_CCW, GL_FRONT, GL_FALSE); + render_->SetRaster(false, GL_CCW, GL_FRONT, GL_FALSE, GL_FALSE); render_->BindProgram(stencilUploadProgram_); render_->SetNoBlendAndMask(0x8);