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);