From c2da29392c51d4a1772b1d9e1fb43b0c90e57179 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 24 Dec 2018 16:29:13 -0800 Subject: [PATCH 1/5] GLES: Depth download cleanup. --- GPU/GLES/DepthBufferGLES.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/GPU/GLES/DepthBufferGLES.cpp b/GPU/GLES/DepthBufferGLES.cpp index f76d133564..0a3178cfe7 100644 --- a/GPU/GLES/DepthBufferGLES.cpp +++ b/GPU/GLES/DepthBufferGLES.cpp @@ -52,7 +52,6 @@ void main() { vec4 enc = u_depthShift * clamped; enc = floor(mod(enc, 256.0)) * u_depthTo8; - enc = enc * u_depthTo8; // Let's ignore the bits outside 16 bit precision. gl_FragColor = enc.yzww; } @@ -75,11 +74,22 @@ void main() { } )"; +static bool SupportsDepthTexturing() { + if (gl_extensions.IsGLES) { + return gl_extensions.OES_packed_depth_stencil && (gl_extensions.OES_depth_texture || gl_extensions.GLES3); + } + return gl_extensions.VersionGEThan(3, 0); +} + void FramebufferManagerGLES::ReadbackDepthbufferSync(VirtualFramebuffer *vfb, int x, int y, int w, int h) { if (!vfb->fbo) { ERROR_LOG_REPORT_ONCE(vfbfbozero, SCEGE, "ReadbackDepthbufferSync: vfb->fbo == 0"); return; } + // Old desktop GL can download depth, but not upload. + if (gl_extensions.IsGLES && !SupportsDepthTexturing()) { + return; + } // Pixel size always 4 here because we always request float const u32 bufSize = vfb->z_stride * (h - y) * 4; From 93346d6e2c479cd0e1a3df161d9c2b4d0b008614 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 9 Oct 2022 23:15:12 -0700 Subject: [PATCH 2/5] GLES: Refactor depth shader download. This makes it similar to the Draw interface. --- GPU/GLES/DepthBufferGLES.cpp | 80 +++++++++++++++++-------------- GPU/GLES/FramebufferManagerGLES.h | 1 + 2 files changed, 45 insertions(+), 36 deletions(-) diff --git a/GPU/GLES/DepthBufferGLES.cpp b/GPU/GLES/DepthBufferGLES.cpp index 0a3178cfe7..ff9582ac82 100644 --- a/GPU/GLES/DepthBufferGLES.cpp +++ b/GPU/GLES/DepthBufferGLES.cpp @@ -86,24 +86,35 @@ void FramebufferManagerGLES::ReadbackDepthbufferSync(VirtualFramebuffer *vfb, in ERROR_LOG_REPORT_ONCE(vfbfbozero, SCEGE, "ReadbackDepthbufferSync: vfb->fbo == 0"); return; } + + const u32 z_address = vfb->z_address; + DEBUG_LOG(FRAMEBUF, "Reading depthbuffer to mem at %08x for vfb=%08x", z_address, vfb->fb_address); + + int dstByteOffset = y * vfb->z_stride * sizeof(u16); + u16 *depth = (u16 *)Memory::GetPointer(z_address + dstByteOffset); + ReadbackDepthbufferSync(vfb->fbo, x, y, w, h, depth, vfb->z_stride); + + gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS); +} + +void FramebufferManagerGLES::ReadbackDepthbufferSync(Draw::Framebuffer *fbo, int x, int y, int w, int h, uint16_t *pixels, int pixelsStride) { + if (!fbo) { + ERROR_LOG_REPORT_ONCE(vfbfbozero, SCEGE, "ReadbackDepthbufferSync: bad fbo"); + return; + } // Old desktop GL can download depth, but not upload. if (gl_extensions.IsGLES && !SupportsDepthTexturing()) { return; } - // Pixel size always 4 here because we always request float - const u32 bufSize = vfb->z_stride * (h - y) * 4; - const u32 z_address = vfb->z_address; - const int packWidth = std::min((int)vfb->z_stride, std::min(x + w, (int)vfb->width)); - + // Pixel size always 4 here because we always request float or RGBA. + const u32 bufSize = w * h * 4; if (!convBuf_ || convBufSize_ < bufSize) { delete[] convBuf_; convBuf_ = new u8[bufSize]; convBufSize_ = bufSize; } - DEBUG_LOG(FRAMEBUF, "Reading depthbuffer to mem at %08x for vfb=%08x", z_address, vfb->fb_address); - const bool useColorPath = gl_extensions.IsGLES; bool format16Bit = false; @@ -139,12 +150,12 @@ void FramebufferManagerGLES::ReadbackDepthbufferSync(VirtualFramebuffer *vfb, in } shaderManager_->DirtyLastShader(); - auto *blitFBO = GetTempFBO(TempFBO::COPY, vfb->renderWidth, vfb->renderHeight); + auto *blitFBO = GetTempFBO(TempFBO::COPY, fbo->Width(), fbo->Height()); draw_->BindFramebufferAsRenderTarget(blitFBO, { Draw::RPAction::CLEAR, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "ReadbackDepthbufferSync"); - render->SetViewport({ 0, 0, (float)vfb->renderWidth, (float)vfb->renderHeight, 0.0f, 1.0f }); + render->SetViewport({ 0, 0, (float)fbo->Width(), (float)fbo->Height(), 0.0f, 1.0f }); // 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->SetScissor({ 0, 0, fbo->Width(), fbo->Height() }); render->SetDepth(false, false, GL_ALWAYS); render->SetRaster(false, GL_CCW, GL_FRONT, GL_FALSE, GL_FALSE); render->BindProgram(depthDownloadProgram_); @@ -162,54 +173,51 @@ void FramebufferManagerGLES::ReadbackDepthbufferSync(VirtualFramebuffer *vfb, in float to8[] = { 1.0f / 255.0f, 1.0f / 255.0f, 1.0f / 255.0f, 1.0f / 255.0f }; render->SetUniformF(&u_depthDownloadTo8, 4, to8); - draw_->BindFramebufferAsTexture(vfb->fbo, TEX_SLOT_PSP_TEXTURE, Draw::FB_DEPTH_BIT, 0); + draw_->BindFramebufferAsTexture(fbo, TEX_SLOT_PSP_TEXTURE, Draw::FB_DEPTH_BIT, 0); float u1 = 1.0f; float v1 = 1.0f; - DrawActiveTexture(x, y, w, h, vfb->renderWidth, vfb->renderHeight, 0.0f, 0.0f, u1, v1, ROTATION_LOCKED_HORIZONTAL, DRAWTEX_NEAREST); + DrawActiveTexture(x, y, w, h, fbo->Width(), fbo->Height(), 0.0f, 0.0f, u1, v1, ROTATION_LOCKED_HORIZONTAL, DRAWTEX_NEAREST); - draw_->CopyFramebufferToMemorySync(blitFBO, Draw::FB_COLOR_BIT, 0, y, packWidth, h, Draw::DataFormat::R8G8B8A8_UNORM, convBuf_, vfb->z_stride, "ReadbackDepthbufferSync"); + draw_->CopyFramebufferToMemorySync(blitFBO, Draw::FB_COLOR_BIT, x, y, w, h, Draw::DataFormat::R8G8B8A8_UNORM, convBuf_, w, "ReadbackDepthbufferSync"); textureCache_->ForgetLastTexture(); - // TODO: Use 4444 so we can copy lines directly? + // TODO: Use 4444 so we can copy lines directly (instead of 32 -> 16 on CPU)? format16Bit = true; } else { - draw_->CopyFramebufferToMemorySync(vfb->fbo, Draw::FB_DEPTH_BIT, 0, y, packWidth, h, Draw::DataFormat::D32F, convBuf_, vfb->z_stride, "ReadbackDepthbufferSync"); + draw_->CopyFramebufferToMemorySync(fbo, Draw::FB_DEPTH_BIT, x, y, w, h, Draw::DataFormat::D32F, convBuf_, w, "ReadbackDepthbufferSync"); format16Bit = false; } - int dstByteOffset = y * vfb->z_stride * sizeof(u16); - u16 *depth = (u16 *)Memory::GetPointer(z_address + dstByteOffset); - u32_le *packed32 = (u32_le *)convBuf_; - GLfloat *packedf = (GLfloat *)convBuf_; - - int totalPixels = h == 1 ? packWidth : vfb->z_stride * h; if (format16Bit) { - // TODO: We have to apply GetDepthScaleFactors here too, right? + // In this case, we used the shader to apply depth scale factors. + uint16_t *dest = pixels; + const u32_le *packed32 = (u32_le *)convBuf_; for (int yp = 0; yp < h; ++yp) { - int row_offset = vfb->z_stride * yp; - for (int xp = 0; xp < packWidth; ++xp) { - const int i = row_offset + xp; - depth[i] = packed32[i] & 0xFFFF; + for (int xp = 0; xp < w; ++xp) { + dest[xp] = packed32[xp] & 0xFFFF; } + dest += pixelsStride; + packed32 += w; } } else { - // TODO: Apply this in the shader. + // TODO: Apply this in the shader? May have precision issues if it becomes important to match. + // We downloaded float values directly in this case. + uint16_t *dest = pixels; + const GLfloat *packedf = (GLfloat *)convBuf_; DepthScaleFactors depthScale = GetDepthScaleFactors(); for (int yp = 0; yp < h; ++yp) { - int row_offset = vfb->z_stride * yp; - for (int xp = 0; xp < packWidth; ++xp) { - const int i = row_offset + xp; - float scaled = depthScale.Apply(packedf[i]); + for (int xp = 0; xp < w; ++xp) { + float scaled = depthScale.Apply(packedf[xp]); if (scaled <= 0.0f) { - depth[i] = 0; + dest[xp] = 0; } else if (scaled >= 65535.0f) { - depth[i] = 65535; + dest[xp] = 65535; } else { - depth[i] = (int)scaled; + dest[xp] = (int)scaled; } } + dest += pixelsStride; + packedf += w; } } - - gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS); } diff --git a/GPU/GLES/FramebufferManagerGLES.h b/GPU/GLES/FramebufferManagerGLES.h index 61c2daef1b..eca6d80f06 100644 --- a/GPU/GLES/FramebufferManagerGLES.h +++ b/GPU/GLES/FramebufferManagerGLES.h @@ -39,6 +39,7 @@ public: protected: void UpdateDownloadTempBuffer(VirtualFramebuffer *nvfb) override; void ReadbackDepthbufferSync(VirtualFramebuffer *vfb, int x, int y, int w, int h) override; + void ReadbackDepthbufferSync(Draw::Framebuffer *fbo, int x, int y, int w, int h, uint16_t *pixels, int pixelsStride); private: u8 *convBuf_ = nullptr; From 179c1e4a3b4e40bcb060869ffc1dfda8bb05e119 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 9 Oct 2022 23:19:31 -0700 Subject: [PATCH 3/5] GLES: Enable EXT_depth_clamp where supported. Seems like Freedreno may support this. --- Common/GPU/OpenGL/GLFeatures.cpp | 1 + Common/GPU/OpenGL/GLFeatures.h | 1 + Common/GPU/OpenGL/thin3d_gl.cpp | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Common/GPU/OpenGL/GLFeatures.cpp b/Common/GPU/OpenGL/GLFeatures.cpp index aa79ac5941..103fe00985 100644 --- a/Common/GPU/OpenGL/GLFeatures.cpp +++ b/Common/GPU/OpenGL/GLFeatures.cpp @@ -386,6 +386,7 @@ void CheckGLExtensions() { gl_extensions.OES_texture_3D = g_set_gl_extensions.count("GL_OES_texture_3D") != 0; gl_extensions.EXT_buffer_storage = g_set_gl_extensions.count("GL_EXT_buffer_storage") != 0; gl_extensions.EXT_clip_cull_distance = g_set_gl_extensions.count("GL_EXT_clip_cull_distance") != 0; + gl_extensions.EXT_depth_clamp = g_set_gl_extensions.count("GL_EXT_depth_clamp") != 0; gl_extensions.APPLE_clip_distance = g_set_gl_extensions.count("GL_APPLE_clip_distance") != 0; #if defined(__ANDROID__) diff --git a/Common/GPU/OpenGL/GLFeatures.h b/Common/GPU/OpenGL/GLFeatures.h index 43f0ba52a7..5fe965c3f0 100644 --- a/Common/GPU/OpenGL/GLFeatures.h +++ b/Common/GPU/OpenGL/GLFeatures.h @@ -87,6 +87,7 @@ struct GLExtensions { bool EXT_draw_instanced; bool EXT_buffer_storage; bool EXT_clip_cull_distance; + bool EXT_depth_clamp; // NV bool NV_copy_image; diff --git a/Common/GPU/OpenGL/thin3d_gl.cpp b/Common/GPU/OpenGL/thin3d_gl.cpp index 95e737e63a..bb937379ef 100644 --- a/Common/GPU/OpenGL/thin3d_gl.cpp +++ b/Common/GPU/OpenGL/thin3d_gl.cpp @@ -551,7 +551,7 @@ OpenGLContext::OpenGLContext() { caps_.framebufferBlitSupported = gl_extensions.NV_framebuffer_blit || gl_extensions.ARB_framebuffer_object || gl_extensions.GLES3; caps_.framebufferDepthBlitSupported = caps_.framebufferBlitSupported; caps_.framebufferStencilBlitSupported = caps_.framebufferBlitSupported; - caps_.depthClampSupported = gl_extensions.ARB_depth_clamp; + caps_.depthClampSupported = gl_extensions.ARB_depth_clamp || gl_extensions.EXT_depth_clamp; caps_.blendMinMaxSupported = gl_extensions.EXT_blend_minmax; if (gl_extensions.IsGLES) { From f8908c691b710847e294c9536c60bfd1e3371310 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 10 Oct 2022 00:40:54 -0700 Subject: [PATCH 4/5] GLES: Use Draw for depth readback shader. Was not working before, since the program was not being used by Draw2D. --- GPU/Common/FramebufferManagerCommon.cpp | 2 + GPU/Common/FramebufferManagerCommon.h | 3 + GPU/GLES/DepthBufferGLES.cpp | 159 +++++++++++++++--------- GPU/GLES/FramebufferManagerGLES.h | 2 +- 4 files changed, 103 insertions(+), 63 deletions(-) diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index f6e66efd98..27d18c476f 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -2811,6 +2811,8 @@ void FramebufferManagerCommon::DeviceLost() { } DoRelease(stencilUploadSampler_); DoRelease(stencilUploadPipeline_); + DoRelease(depthReadbackSampler_); + DoRelease(depthReadbackPipeline_); DoRelease(draw2DPipelineColor_); DoRelease(draw2DPipelineColorRect2Lin_); DoRelease(draw2DPipelineDepth_); diff --git a/GPU/Common/FramebufferManagerCommon.h b/GPU/Common/FramebufferManagerCommon.h index d44a0ecb18..28d83186d8 100644 --- a/GPU/Common/FramebufferManagerCommon.h +++ b/GPU/Common/FramebufferManagerCommon.h @@ -571,6 +571,9 @@ protected: Draw::Pipeline *stencilUploadPipeline_ = nullptr; Draw::SamplerState *stencilUploadSampler_ = nullptr; + Draw::Pipeline *depthReadbackPipeline_ = nullptr; + Draw::SamplerState *depthReadbackSampler_ = nullptr; + // Draw2D pipelines Draw2DPipeline *draw2DPipelineColor_ = nullptr; Draw2DPipeline *draw2DPipelineColorRect2Lin_ = nullptr; diff --git a/GPU/GLES/DepthBufferGLES.cpp b/GPU/GLES/DepthBufferGLES.cpp index ff9582ac82..bf239f547f 100644 --- a/GPU/GLES/DepthBufferGLES.cpp +++ b/GPU/GLES/DepthBufferGLES.cpp @@ -40,13 +40,13 @@ precision mediump float; #define gl_FragColor fragColor0 out vec4 fragColor0; #endif -varying vec2 v_texcoord0; -uniform vec2 u_depthFactor; +varying vec2 v_texcoord; +uniform vec4 u_depthFactor; uniform vec4 u_depthShift; uniform vec4 u_depthTo8; uniform sampler2D tex; void main() { - float depth = texture2D(tex, v_texcoord0).r; + float depth = texture2D(tex, v_texcoord).r; // At this point, clamped maps [0, 1] to [0, 65535]. float clamped = clamp((depth + u_depthFactor.x) * u_depthFactor.y, 0.0, 1.0); @@ -65,15 +65,26 @@ precision highp float; #define attribute in #define varying out #endif -attribute vec4 a_position; -attribute vec2 a_texcoord0; -varying vec2 v_texcoord0; +attribute vec2 a_position; +varying vec2 v_texcoord; void main() { - v_texcoord0 = a_texcoord0; - gl_Position = a_position; + v_texcoord = a_position * 2.0; + gl_Position = vec4(v_texcoord * 2.0 - vec2(1.0, 1.0), 0.0, 1.0); } )"; +struct DepthUB { + float u_depthFactor[4]; + float u_depthShift[4]; + float u_depthTo8[4]; +}; + +const UniformBufferDesc depthUBDesc{ sizeof(DepthUB), { + { "u_depthFactor", -1, -1, UniformType::FLOAT4, 0 }, + { "u_depthShift", -1, -1, UniformType::FLOAT4, 16 }, + { "u_depthTo8", -1, -1, UniformType::FLOAT4, 32 }, +} }; + static bool SupportsDepthTexturing() { if (gl_extensions.IsGLES) { return gl_extensions.OES_packed_depth_stencil && (gl_extensions.OES_depth_texture || gl_extensions.GLES3); @@ -94,17 +105,19 @@ void FramebufferManagerGLES::ReadbackDepthbufferSync(VirtualFramebuffer *vfb, in u16 *depth = (u16 *)Memory::GetPointer(z_address + dstByteOffset); ReadbackDepthbufferSync(vfb->fbo, x, y, w, h, depth, vfb->z_stride); - gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS); + gstate_c.Dirty(DIRTY_ALL_RENDER_STATE); } -void FramebufferManagerGLES::ReadbackDepthbufferSync(Draw::Framebuffer *fbo, int x, int y, int w, int h, uint16_t *pixels, int pixelsStride) { +bool FramebufferManagerGLES::ReadbackDepthbufferSync(Draw::Framebuffer *fbo, int x, int y, int w, int h, uint16_t *pixels, int pixelsStride) { + using namespace Draw; + if (!fbo) { ERROR_LOG_REPORT_ONCE(vfbfbozero, SCEGE, "ReadbackDepthbufferSync: bad fbo"); - return; + return false; } // Old desktop GL can download depth, but not upload. if (gl_extensions.IsGLES && !SupportsDepthTexturing()) { - return; + return false; } // Pixel size always 4 here because we always request float or RGBA. @@ -118,73 +131,93 @@ void FramebufferManagerGLES::ReadbackDepthbufferSync(Draw::Framebuffer *fbo, int const bool useColorPath = gl_extensions.IsGLES; bool format16Bit = false; - GLRenderManager *render = (GLRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); - if (useColorPath) { - if (!depthDownloadProgram_) { - std::string errorString; - static std::string vs_code, fs_code; - vs_code = ApplyGLSLPrelude(depth_vs, GL_VERTEX_SHADER); - fs_code = ApplyGLSLPrelude(depth_dl_fs, GL_FRAGMENT_SHADER); - std::vector shaders; - shaders.push_back(render->CreateShader(GL_VERTEX_SHADER, vs_code, "depth_dl")); - shaders.push_back(render->CreateShader(GL_FRAGMENT_SHADER, fs_code, "depth_dl")); - std::vector semantics; - semantics.push_back({ 0, "a_position" }); - semantics.push_back({ 1, "a_texcoord0" }); - std::vector queries; - queries.push_back({ &u_depthDownloadTex, "tex" }); - queries.push_back({ &u_depthDownloadFactor, "u_depthFactor" }); - queries.push_back({ &u_depthDownloadShift, "u_depthShift" }); - queries.push_back({ &u_depthDownloadTo8, "u_depthTo8" }); - std::vector inits; - inits.push_back({ &u_depthDownloadTex, 0, TEX_SLOT_PSP_TEXTURE }); - GLRProgramFlags flags{}; - depthDownloadProgram_ = render->CreateProgram(shaders, semantics, queries, inits, flags); - for (auto iter : shaders) { - render->DeleteShader(iter); - } - if (!depthDownloadProgram_) { - ERROR_LOG_REPORT(G3D, "Failed to compile depthDownloadProgram! This shouldn't happen.\n%s", errorString.c_str()); - } + if (!depthReadbackPipeline_) { + const ShaderLanguageDesc &shaderLanguageDesc = draw_->GetShaderLanguageDesc(); + + ShaderModule *depthReadbackFs = draw_->CreateShaderModule(ShaderStage::Fragment, shaderLanguageDesc.shaderLanguage, (const uint8_t *)depth_dl_fs, strlen(depth_dl_fs), "depth_dl_fs"); + ShaderModule *depthReadbackVs = draw_->CreateShaderModule(ShaderStage::Vertex, shaderLanguageDesc.shaderLanguage, (const uint8_t *)depth_vs, strlen(depth_vs), "depth_vs"); + _assert_(depthReadbackFs && depthReadbackVs); + + InputLayoutDesc desc = { + { + { 8, false }, + }, + { + { 0, SEM_POSITION, DataFormat::R32G32_FLOAT, 0 }, + }, + }; + InputLayout *inputLayout = draw_->CreateInputLayout(desc); + + BlendState *blendOff = draw_->CreateBlendState({ false, 0xF }); + DepthStencilState *stencilIgnore = draw_->CreateDepthStencilState({}); + RasterState *rasterNoCull = draw_->CreateRasterState({}); + + PipelineDesc depthReadbackDesc{ + Primitive::TRIANGLE_LIST, + { depthReadbackVs, depthReadbackFs }, + inputLayout, stencilIgnore, blendOff, rasterNoCull, &depthUBDesc, + }; + depthReadbackPipeline_ = draw_->CreateGraphicsPipeline(depthReadbackDesc, "depth_dl"); + _assert_(depthReadbackPipeline_); + + rasterNoCull->Release(); + blendOff->Release(); + stencilIgnore->Release(); + inputLayout->Release(); + + depthReadbackFs->Release(); + depthReadbackVs->Release(); + + SamplerStateDesc descNearest{}; + depthReadbackSampler_ = draw_->CreateSamplerState(descNearest); } shaderManager_->DirtyLastShader(); auto *blitFBO = GetTempFBO(TempFBO::COPY, fbo->Width(), fbo->Height()); - draw_->BindFramebufferAsRenderTarget(blitFBO, { Draw::RPAction::CLEAR, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE }, "ReadbackDepthbufferSync"); - render->SetViewport({ 0, 0, (float)fbo->Width(), (float)fbo->Height(), 0.0f, 1.0f }); + draw_->BindFramebufferAsRenderTarget(blitFBO, { RPAction::DONT_CARE, RPAction::DONT_CARE, RPAction::DONT_CARE }, "ReadbackDepthbufferSync"); + Draw::Viewport viewport = { 0.0f, 0.0f, (float)fbo->Width(), (float)fbo->Height(), 0.0f, 1.0f }; + draw_->SetViewports(1, &viewport); - // We must bind the program after starting the render pass, and set the color mask after clearing. - render->SetScissor({ 0, 0, fbo->Width(), fbo->Height() }); - render->SetDepth(false, false, GL_ALWAYS); - render->SetRaster(false, GL_CCW, GL_FRONT, GL_FALSE, GL_FALSE); - render->BindProgram(depthDownloadProgram_); + draw_->BindFramebufferAsTexture(fbo, TEX_SLOT_PSP_TEXTURE, FB_DEPTH_BIT, 0); + draw_->BindSamplerStates(TEX_SLOT_PSP_TEXTURE, 1, &depthReadbackSampler_); - if (!gstate_c.Supports(GPU_SUPPORTS_ACCURATE_DEPTH)) { - float factors[] = { 0.0f, 1.0f }; - render->SetUniformF(&u_depthDownloadFactor, 2, factors); + // We must bind the program after starting the render pass. + draw_->SetScissorRect(0, 0, w, h); + draw_->BindPipeline(depthReadbackPipeline_); + + DepthUB ub{}; + + if (gstate_c.Supports(GPU_SUPPORTS_ACCURATE_DEPTH)) { + ub.u_depthFactor[0] = 0.0f; + ub.u_depthFactor[1] = 1.0f; } else { const float factor = DepthSliceFactor(); - float factors[] = { -0.5f * (factor - 1.0f) * (1.0f / factor), factor }; - render->SetUniformF(&u_depthDownloadFactor, 2, factors); + ub.u_depthFactor[0] = -0.5f * (factor - 1.0f) * (1.0f / factor); + ub.u_depthFactor[1] = factor; } - float shifts[] = { 16777215.0f, 16777215.0f / 256.0f, 16777215.0f / 65536.0f, 16777215.0f / 16777216.0f }; - render->SetUniformF(&u_depthDownloadShift, 4, shifts); - float to8[] = { 1.0f / 255.0f, 1.0f / 255.0f, 1.0f / 255.0f, 1.0f / 255.0f }; - render->SetUniformF(&u_depthDownloadTo8, 4, to8); + static constexpr float shifts[] = { 16777215.0f, 16777215.0f / 256.0f, 16777215.0f / 65536.0f, 16777215.0f / 16777216.0f }; + memcpy(ub.u_depthShift, shifts, sizeof(shifts)); + static constexpr float to8[] = { 1.0f / 255.0f, 1.0f / 255.0f, 1.0f / 255.0f, 1.0f / 255.0f }; + memcpy(ub.u_depthTo8, to8, sizeof(to8)); - draw_->BindFramebufferAsTexture(fbo, TEX_SLOT_PSP_TEXTURE, Draw::FB_DEPTH_BIT, 0); - float u1 = 1.0f; - float v1 = 1.0f; - DrawActiveTexture(x, y, w, h, fbo->Width(), fbo->Height(), 0.0f, 0.0f, u1, v1, ROTATION_LOCKED_HORIZONTAL, DRAWTEX_NEAREST); + draw_->UpdateDynamicUniformBuffer(&ub, sizeof(ub)); - draw_->CopyFramebufferToMemorySync(blitFBO, Draw::FB_COLOR_BIT, x, y, w, h, Draw::DataFormat::R8G8B8A8_UNORM, convBuf_, w, "ReadbackDepthbufferSync"); + // Fullscreen triangle coordinates. + static const float positions[6] = { + 0.0, 0.0, + 1.0, 0.0, + 0.0, 1.0, + }; + draw_->DrawUP(positions, 3); + + draw_->CopyFramebufferToMemorySync(blitFBO, FB_COLOR_BIT, x, y, w, h, DataFormat::R8G8B8A8_UNORM, convBuf_, w, "ReadbackDepthbufferSync"); textureCache_->ForgetLastTexture(); // TODO: Use 4444 so we can copy lines directly (instead of 32 -> 16 on CPU)? format16Bit = true; } else { - draw_->CopyFramebufferToMemorySync(fbo, Draw::FB_DEPTH_BIT, x, y, w, h, Draw::DataFormat::D32F, convBuf_, w, "ReadbackDepthbufferSync"); + draw_->CopyFramebufferToMemorySync(fbo, FB_DEPTH_BIT, x, y, w, h, DataFormat::D32F, convBuf_, w, "ReadbackDepthbufferSync"); format16Bit = false; } @@ -220,4 +253,6 @@ void FramebufferManagerGLES::ReadbackDepthbufferSync(Draw::Framebuffer *fbo, int packedf += w; } } + + return true; } diff --git a/GPU/GLES/FramebufferManagerGLES.h b/GPU/GLES/FramebufferManagerGLES.h index eca6d80f06..b5967e7c40 100644 --- a/GPU/GLES/FramebufferManagerGLES.h +++ b/GPU/GLES/FramebufferManagerGLES.h @@ -39,7 +39,7 @@ public: protected: void UpdateDownloadTempBuffer(VirtualFramebuffer *nvfb) override; void ReadbackDepthbufferSync(VirtualFramebuffer *vfb, int x, int y, int w, int h) override; - void ReadbackDepthbufferSync(Draw::Framebuffer *fbo, int x, int y, int w, int h, uint16_t *pixels, int pixelsStride); + bool ReadbackDepthbufferSync(Draw::Framebuffer *fbo, int x, int y, int w, int h, uint16_t *pixels, int pixelsStride); private: u8 *convBuf_ = nullptr; From 1dc35b3ac4b5841c9743e760c2b5b2fa477d8b47 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 10 Oct 2022 00:53:31 -0700 Subject: [PATCH 5/5] GLES: Simplify, enable debug depth readback. --- GPU/Common/FramebufferManagerCommon.cpp | 36 ++++++++++++------------- GPU/Common/FramebufferManagerCommon.h | 2 +- GPU/Directx9/FramebufferManagerDX9.h | 2 +- GPU/GLES/DepthBufferGLES.cpp | 20 +++----------- GPU/GLES/FramebufferManagerGLES.h | 3 +-- 5 files changed, 23 insertions(+), 40 deletions(-) diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index 27d18c476f..c36d39a6f1 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -2538,6 +2538,12 @@ bool FramebufferManagerCommon::GetDepthbuffer(u32 fb_address, int fb_stride, u32 } // No need to free on failure, that's the caller's job (it likely will reuse a buffer.) bool retval = draw_->CopyFramebufferToMemorySync(vfb->fbo, Draw::FB_DEPTH_BIT, 0, 0, w, h, Draw::DataFormat::D32F, buffer.GetData(), w, "GetDepthBuffer"); + if (!retval) { + // Try ReadbackDepthbufferSync, in case GLES. + buffer.Allocate(w, h, GPU_DBG_FORMAT_16BIT, flipY); + retval = ReadbackDepthbufferSync(vfb->fbo, 0, 0, w, h, (uint16_t *)buffer.GetData(), w); + } + // After a readback we'll have flushed and started over, need to dirty a bunch of things to be safe. gstate_c.Dirty(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS); // That may have unbound the framebuffer, rebind to avoid crashes when debugging. @@ -2604,7 +2610,7 @@ void FramebufferManagerCommon::ReadbackFramebufferSync(VirtualFramebuffer *vfb, return; } - const u32 fb_address = vfb->fb_address; + const u32 fb_address = channel == RASTER_COLOR ? vfb->fb_address : vfb->z_address; Draw::DataFormat destFormat = channel == RASTER_COLOR ? GEFormatToThin3D(vfb->fb_format) : GEFormatToThin3D(GE_FORMAT_DEPTH16); const int dstBpp = (int)DataFormatSizeInBytes(destFormat); @@ -2627,31 +2633,23 @@ void FramebufferManagerCommon::ReadbackFramebufferSync(VirtualFramebuffer *vfb, // Right now that's always 8888. DEBUG_LOG(G3D, "Reading framebuffer to mem, fb_address = %08x, ptr=%p", fb_address, destPtr); - if (destPtr) { - if (channel == RASTER_DEPTH) - ReadbackDepthbufferSync(vfb, x, y, w, h); - else - draw_->CopyFramebufferToMemorySync(vfb->fbo, channel == RASTER_COLOR ? Draw::FB_COLOR_BIT : Draw::FB_DEPTH_BIT, x, y, w, h, destFormat, destPtr, vfb->fb_stride, "ReadbackFramebufferSync"); - - char tag[128]; - size_t len = snprintf(tag, sizeof(tag), "FramebufferPack/%08x_%08x_%dx%d_%s", vfb->fb_address, vfb->z_address, w, h, GeBufferFormatToString(vfb->fb_format)); - NotifyMemInfo(MemBlockFlags::WRITE, fb_address + dstByteOffset, dstSize, tag, len); + if (channel == RASTER_DEPTH) { + _assert_msg_(vfb && vfb->z_address != 0 && vfb->z_stride != 0, "Depth buffer invalid"); + ReadbackDepthbufferSync(vfb->fbo, x, y, w, h, (uint16_t *)destPtr, stride); } else { - ERROR_LOG(G3D, "ReadbackFramebufferSync: Tried to readback to bad address %08x (stride = %d)", fb_address + dstByteOffset, vfb->fb_stride); + draw_->CopyFramebufferToMemorySync(vfb->fbo, channel == RASTER_COLOR ? Draw::FB_COLOR_BIT : Draw::FB_DEPTH_BIT, x, y, w, h, destFormat, destPtr, stride, "ReadbackFramebufferSync"); } + char tag[128]; + size_t len = snprintf(tag, sizeof(tag), "FramebufferPack/%08x_%08x_%dx%d_%s", vfb->fb_address, vfb->z_address, w, h, GeBufferFormatToString(vfb->fb_format)); + NotifyMemInfo(MemBlockFlags::WRITE, fb_address + dstByteOffset, dstSize, tag, len); + gpuStats.numReadbacks++; } -void FramebufferManagerCommon::ReadbackDepthbufferSync(VirtualFramebuffer *vfb, int x, int y, int w, int h) { - _assert_msg_(vfb && vfb->z_address != 0 && vfb->z_stride != 0, "Depth buffer invalid"); - +bool FramebufferManagerCommon::ReadbackDepthbufferSync(Draw::Framebuffer *fbo, int x, int y, int w, int h, uint16_t *pixels, int pixelsStride) { Draw::DataFormat destFormat = GEFormatToThin3D(GE_FORMAT_DEPTH16); - const int dstByteOffset = (y * vfb->z_stride + x) * 2; - u8 *destPtr = Memory::GetPointerWriteUnchecked(vfb->z_address + dstByteOffset); - if (!draw_->CopyFramebufferToMemorySync(vfb->fbo, Draw::FB_DEPTH_BIT, x, y, w, h, destFormat, destPtr, vfb->z_stride, "ReadbackDepthbufferSync")) { - WARN_LOG(G3D, "ReadbackDepthbufferSync failed"); - } + return draw_->CopyFramebufferToMemorySync(fbo, Draw::FB_DEPTH_BIT, x, y, w, h, destFormat, pixels, pixelsStride, "ReadbackDepthbufferSync"); } void FramebufferManagerCommon::ReadFramebufferToMemory(VirtualFramebuffer *vfb, int x, int y, int w, int h, RasterChannel channel) { diff --git a/GPU/Common/FramebufferManagerCommon.h b/GPU/Common/FramebufferManagerCommon.h index 28d83186d8..63f7b082ba 100644 --- a/GPU/Common/FramebufferManagerCommon.h +++ b/GPU/Common/FramebufferManagerCommon.h @@ -443,7 +443,7 @@ public: protected: virtual void ReadbackFramebufferSync(VirtualFramebuffer *vfb, int x, int y, int w, int h, RasterChannel channel); // Used for when a shader is required, such as GLES. - virtual void ReadbackDepthbufferSync(VirtualFramebuffer *vfb, int x, int y, int w, int h); + virtual bool ReadbackDepthbufferSync(Draw::Framebuffer *fbo, int x, int y, int w, int h, uint16_t *pixels, int pixelsStride); void SetViewport2D(int x, int y, int w, int h); Draw::Texture *MakePixelTexture(const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, int width, int height); void DrawActiveTexture(float x, float y, float w, float h, float destW, float destH, float u0, float v0, float u1, float v1, int uvRotation, int flags); diff --git a/GPU/Directx9/FramebufferManagerDX9.h b/GPU/Directx9/FramebufferManagerDX9.h index ea69262917..cb0a8ff37f 100644 --- a/GPU/Directx9/FramebufferManagerDX9.h +++ b/GPU/Directx9/FramebufferManagerDX9.h @@ -49,11 +49,11 @@ public: protected: void DecimateFBOs() override; - void ReadbackDepthbufferSync(VirtualFramebuffer *vfb, int x, int y, int w, int h) override; void ReadbackFramebufferSync(VirtualFramebuffer *vfb, int x, int y, int w, int h, RasterChannel channel) override; private: bool GetRenderTargetFramebuffer(LPDIRECT3DSURFACE9 renderTarget, LPDIRECT3DSURFACE9 offscreen, int w, int h, GPUDebugBuffer &buffer); + void ReadbackDepthbufferSync(VirtualFramebuffer *vfb, int x, int y, int w, int h); LPDIRECT3DDEVICE9 device_; LPDIRECT3DDEVICE9 deviceEx_; diff --git a/GPU/GLES/DepthBufferGLES.cpp b/GPU/GLES/DepthBufferGLES.cpp index bf239f547f..6b9dbc219c 100644 --- a/GPU/GLES/DepthBufferGLES.cpp +++ b/GPU/GLES/DepthBufferGLES.cpp @@ -92,22 +92,6 @@ static bool SupportsDepthTexturing() { return gl_extensions.VersionGEThan(3, 0); } -void FramebufferManagerGLES::ReadbackDepthbufferSync(VirtualFramebuffer *vfb, int x, int y, int w, int h) { - if (!vfb->fbo) { - ERROR_LOG_REPORT_ONCE(vfbfbozero, SCEGE, "ReadbackDepthbufferSync: vfb->fbo == 0"); - return; - } - - const u32 z_address = vfb->z_address; - DEBUG_LOG(FRAMEBUF, "Reading depthbuffer to mem at %08x for vfb=%08x", z_address, vfb->fb_address); - - int dstByteOffset = y * vfb->z_stride * sizeof(u16); - u16 *depth = (u16 *)Memory::GetPointer(z_address + dstByteOffset); - ReadbackDepthbufferSync(vfb->fbo, x, y, w, h, depth, vfb->z_stride); - - gstate_c.Dirty(DIRTY_ALL_RENDER_STATE); -} - bool FramebufferManagerGLES::ReadbackDepthbufferSync(Draw::Framebuffer *fbo, int x, int y, int w, int h, uint16_t *pixels, int pixelsStride) { using namespace Draw; @@ -188,7 +172,8 @@ bool FramebufferManagerGLES::ReadbackDepthbufferSync(Draw::Framebuffer *fbo, int DepthUB ub{}; - if (gstate_c.Supports(GPU_SUPPORTS_ACCURATE_DEPTH)) { + if (!gstate_c.Supports(GPU_SUPPORTS_ACCURATE_DEPTH)) { + // Don't scale anything, since we're not using factors outside accurate mode. ub.u_depthFactor[0] = 0.0f; ub.u_depthFactor[1] = 1.0f; } else { @@ -254,5 +239,6 @@ bool FramebufferManagerGLES::ReadbackDepthbufferSync(Draw::Framebuffer *fbo, int } } + gstate_c.Dirty(DIRTY_ALL_RENDER_STATE); return true; } diff --git a/GPU/GLES/FramebufferManagerGLES.h b/GPU/GLES/FramebufferManagerGLES.h index b5967e7c40..36aa2545fd 100644 --- a/GPU/GLES/FramebufferManagerGLES.h +++ b/GPU/GLES/FramebufferManagerGLES.h @@ -38,8 +38,7 @@ public: protected: void UpdateDownloadTempBuffer(VirtualFramebuffer *nvfb) override; - void ReadbackDepthbufferSync(VirtualFramebuffer *vfb, int x, int y, int w, int h) override; - bool ReadbackDepthbufferSync(Draw::Framebuffer *fbo, int x, int y, int w, int h, uint16_t *pixels, int pixelsStride); + bool ReadbackDepthbufferSync(Draw::Framebuffer *fbo, int x, int y, int w, int h, uint16_t *pixels, int pixelsStride) override; private: u8 *convBuf_ = nullptr;