From 79750ed1ad5c225b4b3764092e81dde87a096b77 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Wed, 20 Jan 2016 22:00:07 -0800 Subject: [PATCH 1/6] Add a config setting to control depth quality. For those who want 1x PSP like behavior. --- Core/Config.cpp | 1 + Core/Config.h | 1 + GPU/Common/GPUStateUtils.cpp | 18 ++++++++++++------ GPU/Directx9/GPU_DX9.cpp | 4 +++- GPU/GLES/GLES_GPU.cpp | 14 ++++++++------ GPU/GPUState.h | 1 + 6 files changed, 26 insertions(+), 13 deletions(-) diff --git a/Core/Config.cpp b/Core/Config.cpp index a438ebcce5..d182a1ab32 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -442,6 +442,7 @@ static ConfigSetting graphicsSettings[] = { ReportedConfigSetting("BufferFiltering", &g_Config.iBufFilter, 1, true, true), ReportedConfigSetting("InternalResolution", &g_Config.iInternalResolution, &DefaultInternalResolution, true, true), ReportedConfigSetting("AndroidHwScale", &g_Config.iAndroidHwScale, &DefaultAndroidHwScale), + ReportedConfigSetting("HighQualityDepth", &g_Config.bHighQualityDepth, true, true, true), ReportedConfigSetting("FrameSkip", &g_Config.iFrameSkip, 0, true, true), ReportedConfigSetting("AutoFrameSkip", &g_Config.bAutoFrameSkip, false, true, true), ReportedConfigSetting("FrameRate", &g_Config.iFpsLimit, 0, true, true), diff --git a/Core/Config.h b/Core/Config.h index ac5b990554..3333dd3602 100644 --- a/Core/Config.h +++ b/Core/Config.h @@ -173,6 +173,7 @@ public: bool bFullScreen; int iInternalResolution; // 0 = Auto (native), 1 = 1x (480x272), 2 = 2x, 3 = 3x, 4 = 4x and so on. int iAnisotropyLevel; // 0 - 5, powers of 2: 0 = 1x = no aniso + int bHighQualityDepth; bool bTrueColor; bool bMipMap; int iTexScalingLevel; // 1 = off, 2 = 2x, ..., 5 = 5x diff --git a/GPU/Common/GPUStateUtils.cpp b/GPU/Common/GPUStateUtils.cpp index 29676f5fd8..8a6065c6f3 100644 --- a/GPU/Common/GPUStateUtils.cpp +++ b/GPU/Common/GPUStateUtils.cpp @@ -498,10 +498,19 @@ LogicOpReplaceType ReplaceLogicOpType() { return LOGICOPTYPE_NORMAL; } -static const float depthSliceFactor = 4.0f; +static const float DEPTH_SLICE_FACTOR_HIGH = 4.0f; +static const float DEPTH_SLICE_FACTOR_16BIT = 256.0f; + +float DepthSliceFactor() { + if (gstate_c.Supports(GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT)) { + return DEPTH_SLICE_FACTOR_16BIT; + } + return DEPTH_SLICE_FACTOR_HIGH; +} // This is used for float values which might not be integers, but are in the integer scale of 65535. static float ToScaledDepthFromInteger(float z) { + const float depthSliceFactor = DepthSliceFactor(); const float offset = 0.5f * (depthSliceFactor - 1.0f) * (1.0f / depthSliceFactor); return z * (1.0f / depthSliceFactor) * (1.0f / 65535.0f) + offset; } @@ -511,14 +520,11 @@ float ToScaledDepth(u16 z) { } float FromScaledDepth(float z) { + const float depthSliceFactor = DepthSliceFactor(); const float offset = 0.5f * (depthSliceFactor - 1.0f) * (1.0f / depthSliceFactor); return (z - offset) * depthSliceFactor * 65535.0f; } -float DepthSliceFactor() { - return depthSliceFactor; -} - void ConvertViewportAndScissor(bool useBufferedRendering, float renderWidth, float renderHeight, int bufferWidth, int bufferHeight, ViewportAndScissor &out) { bool throughmode = gstate.isModeThrough(); out.dirtyProj = false; @@ -662,7 +668,7 @@ void ConvertViewportAndScissor(bool useBufferedRendering, float renderWidth, flo // Here, we should "clamp." But clamping per fragment would be slow. // So, instead, we just increase the available range and hope. // If depthSliceFactor is 4, it means (75% / 2) of the depth lies in each direction. - float fullDepthRange = 65535.0f * (depthSliceFactor - 1.0f) * (1.0f / 2.0f); + float fullDepthRange = 65535.0f * (DepthSliceFactor() - 1.0f) * (1.0f / 2.0f); if (minz == 0) { minz -= fullDepthRange; } diff --git a/GPU/Directx9/GPU_DX9.cpp b/GPU/Directx9/GPU_DX9.cpp index ab62acfc3e..73ea41c7dd 100644 --- a/GPU/Directx9/GPU_DX9.cpp +++ b/GPU/Directx9/GPU_DX9.cpp @@ -478,7 +478,9 @@ void DIRECTX9_GPU::CheckGPUFeatures() { features |= GPU_SUPPORTS_TEXTURE_LOD_CONTROL; features |= GPU_PREFER_CPU_DOWNLOAD; - if (PSP_CoreParameter().compat.flags().VertexDepthRounding) { + if (!g_Config.bHighQualityDepth) { + features |= GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT; + } else if (PSP_CoreParameter().compat.flags().VertexDepthRounding) { features |= GPU_ROUND_DEPTH_TO_16BIT; } diff --git a/GPU/GLES/GLES_GPU.cpp b/GPU/GLES/GLES_GPU.cpp index aa22c23549..3c7bf702a6 100644 --- a/GPU/GLES/GLES_GPU.cpp +++ b/GPU/GLES/GLES_GPU.cpp @@ -565,13 +565,15 @@ void GLES_GPU::CheckGPUFeatures() { if (gl_extensions.GLES3 || !gl_extensions.IsGLES) features |= GPU_SUPPORTS_TEXTURE_LOD_CONTROL; - // In the future, also disable this when we get a proper 16-bit depth buffer. - if ((!gl_extensions.IsGLES || gl_extensions.GLES3) && PSP_CoreParameter().compat.flags().PixelDepthRounding) { - features |= GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT; - } else { - if (PSP_CoreParameter().compat.flags().VertexDepthRounding) { - features |= GPU_ROUND_DEPTH_TO_16BIT; + if (!g_Config.bHighQualityDepth) { + features |= GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT; + } else if (PSP_CoreParameter().compat.flags().PixelDepthRounding) { + if (!gl_extensions.IsGLES || gl_extensions.GLES3) { + // Use fragment rounding on desktop and GLES3, most accurate. + features |= GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT; } + } else if (PSP_CoreParameter().compat.flags().VertexDepthRounding) { + features |= GPU_ROUND_DEPTH_TO_16BIT; } #ifdef MOBILE_DEVICE diff --git a/GPU/GPUState.h b/GPU/GPUState.h index 814ae686d9..b3467c39b2 100644 --- a/GPU/GPUState.h +++ b/GPU/GPUState.h @@ -458,6 +458,7 @@ enum { GPU_SUPPORTS_VAO = FLAG_BIT(18), GPU_SUPPORTS_ANY_COPY_IMAGE = FLAG_BIT(19), GPU_SUPPORTS_ANY_FRAMEBUFFER_FETCH = FLAG_BIT(20), + GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT = FLAG_BIT(21), GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT = FLAG_BIT(22), GPU_ROUND_DEPTH_TO_16BIT = FLAG_BIT(23), // Can be disabled either per game or if we use a real 16-bit depth buffer GPU_SUPPORTS_TEXTURE_LOD_CONTROL = FLAG_BIT(24), From 27dba51e70692d82f593d57dd2d089a729853819 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Wed, 20 Jan 2016 22:01:18 -0800 Subject: [PATCH 2/6] Add fallbacks where low quality depth is required. Even on GLES2, this should work. Also check the depth before applying rounding - we might even already be 24-bit. --- GPU/GLES/FBO.cpp | 13 +++++++++++++ GPU/GLES/FBO.h | 2 ++ GPU/GLES/GLES_GPU.cpp | 26 ++++++++++++++++++-------- 3 files changed, 33 insertions(+), 8 deletions(-) diff --git a/GPU/GLES/FBO.cpp b/GPU/GLES/FBO.cpp index 889ed00767..47ff42a06b 100644 --- a/GPU/GLES/FBO.cpp +++ b/GPU/GLES/FBO.cpp @@ -143,6 +143,18 @@ int fbo_check_framebuffer_status(FBO *fbo) { return (int)fbStatus; } +int fbo_standard_z_depth() { + // This matches the fbo_create() logic. + if (gl_extensions.IsGLES) { + if (gl_extensions.OES_packed_depth_stencil) { + return 24; + } + return gl_extensions.OES_depth24 ? 24 : 16; + } else { + return 24; + } +} + FBO *fbo_create(int width, int height, int num_color_textures, bool z_stencil, FBOColorDepth colorDepth) { CheckGLExtensions(); @@ -216,6 +228,7 @@ FBO *fbo_create(int width, int height, int num_color_textures, bool z_stencil, F // 16/24-bit Z, separate 8-bit stencil glGenRenderbuffers(1, &fbo->z_buffer); glBindRenderbuffer(GL_RENDERBUFFER, fbo->z_buffer); + // Don't forget to make sure fbo_standard_z_depth() matches. glRenderbufferStorage(GL_RENDERBUFFER, gl_extensions.OES_depth24 ? GL_DEPTH_COMPONENT24 : GL_DEPTH_COMPONENT16, width, height); // 8-bit stencil buffer diff --git a/GPU/GLES/FBO.h b/GPU/GLES/FBO.h index 24c06cb13a..5548923f35 100644 --- a/GPU/GLES/FBO.h +++ b/GPU/GLES/FBO.h @@ -43,6 +43,8 @@ enum FBOColorDepth { // On some hardware, you might get a 24-bit depth buffer even though you only wanted a 16-bit one. FBO *fbo_create(int width, int height, int num_color_textures, bool z_stencil, FBOColorDepth colorDepth = FBO_8888); +int fbo_standard_z_depth(); + // Create an opaque FBO from a native GL FBO, optionally reusing an existing FBO structure. // Useful for overriding the backbuffer FBO that is generated outside of this wrapper. FBO *fbo_create_from_native_fbo(GLuint native_fbo, FBO *fbo = NULL); diff --git a/GPU/GLES/GLES_GPU.cpp b/GPU/GLES/GLES_GPU.cpp index 3c7bf702a6..10073fea38 100644 --- a/GPU/GLES/GLES_GPU.cpp +++ b/GPU/GLES/GLES_GPU.cpp @@ -565,15 +565,25 @@ void GLES_GPU::CheckGPUFeatures() { if (gl_extensions.GLES3 || !gl_extensions.IsGLES) features |= GPU_SUPPORTS_TEXTURE_LOD_CONTROL; - if (!g_Config.bHighQualityDepth) { - features |= GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT; - } else if (PSP_CoreParameter().compat.flags().PixelDepthRounding) { - if (!gl_extensions.IsGLES || gl_extensions.GLES3) { - // Use fragment rounding on desktop and GLES3, most accurate. - features |= GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT; + // If we already have a 16-bit depth buffer, we don't need to round. + if (fbo_standard_z_depth() > 16) { + if (!g_Config.bHighQualityDepth) { + features |= GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT; + } else if (PSP_CoreParameter().compat.flags().PixelDepthRounding) { + if (!gl_extensions.IsGLES || gl_extensions.GLES3) { + // Use fragment rounding on desktop and GLES3, most accurate. + features |= GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT; + } else if (fbo_standard_z_depth() == 24) { + // Here we can simulate a 16 bit depth buffer by scaling. + // Note that the depth buffer is fixed point, not floating, so dividing by 256 is pretty good. + features |= GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT; + } else { + // At least do vertex rounding if nothing else. + features |= GPU_ROUND_DEPTH_TO_16BIT; + } + } else if (PSP_CoreParameter().compat.flags().VertexDepthRounding) { + features |= GPU_ROUND_DEPTH_TO_16BIT; } - } else if (PSP_CoreParameter().compat.flags().VertexDepthRounding) { - features |= GPU_ROUND_DEPTH_TO_16BIT; } #ifdef MOBILE_DEVICE From f9970dba9452a68ec5b4271297e0851c1452d5f2 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Wed, 20 Jan 2016 22:02:07 -0800 Subject: [PATCH 3/6] d3d9: Respect per-pixel depth rounding. Using the 16-bit depth range. --- GPU/Directx9/GPU_DX9.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/GPU/Directx9/GPU_DX9.cpp b/GPU/Directx9/GPU_DX9.cpp index 73ea41c7dd..b88e3d385f 100644 --- a/GPU/Directx9/GPU_DX9.cpp +++ b/GPU/Directx9/GPU_DX9.cpp @@ -480,6 +480,9 @@ void DIRECTX9_GPU::CheckGPUFeatures() { if (!g_Config.bHighQualityDepth) { features |= GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT; + } else if (PSP_CoreParameter().compat.flags().PixelDepthRounding) { + // Assume we always have a 24-bit depth buffer. + features |= GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT; } else if (PSP_CoreParameter().compat.flags().VertexDepthRounding) { features |= GPU_ROUND_DEPTH_TO_16BIT; } From 2916298695552b0460accfc090fa0562822998d3 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 18 Jan 2016 01:30:05 -0800 Subject: [PATCH 4/6] gedbg: Add scaled 16-bit z support. --- GPU/Common/GPUDebugInterface.cpp | 2 ++ GPU/Common/GPUDebugInterface.h | 3 +++ GPU/Directx9/FramebufferDX9.cpp | 3 +++ GPU/GLES/Framebuffer.cpp | 6 +++++- Windows/GEDebugger/GEDebugger.cpp | 18 ++++++++++++++++++ Windows/GEDebugger/SimpleGLWindow.cpp | 21 +++++++++++++++++++++ Windows/GEDebugger/SimpleGLWindow.h | 3 +++ 7 files changed, 55 insertions(+), 1 deletion(-) diff --git a/GPU/Common/GPUDebugInterface.cpp b/GPU/Common/GPUDebugInterface.cpp index d76ab6111b..9fb5d2916c 100644 --- a/GPU/Common/GPUDebugInterface.cpp +++ b/GPU/Common/GPUDebugInterface.cpp @@ -57,6 +57,8 @@ u32 GPUDebugBuffer::PixelSize(GPUDebugBufferFormat fmt) const { case GPU_DBG_FORMAT_FLOAT: case GPU_DBG_FORMAT_24BIT_8X: case GPU_DBG_FORMAT_24X_8BIT: + case GPU_DBG_FORMAT_FLOAT_DIV_256: + case GPU_DBG_FORMAT_24BIT_8X_DIV_256: return 4; case GPU_DBG_FORMAT_888_RGB: diff --git a/GPU/Common/GPUDebugInterface.h b/GPU/Common/GPUDebugInterface.h index f2676484b2..a31caba641 100644 --- a/GPU/Common/GPUDebugInterface.h +++ b/GPU/Common/GPUDebugInterface.h @@ -59,6 +59,9 @@ enum GPUDebugBufferFormat { GPU_DBG_FORMAT_24BIT_8X = 0x13, GPU_DBG_FORMAT_24X_8BIT = 0x14, + GPU_DBG_FORMAT_FLOAT_DIV_256 = 0x18, + GPU_DBG_FORMAT_24BIT_8X_DIV_256 = 0x1B, + // This is used for screenshots, mainly. GPU_DBG_FORMAT_888_RGB = 0x20, }; diff --git a/GPU/Directx9/FramebufferDX9.cpp b/GPU/Directx9/FramebufferDX9.cpp index 9318ec0784..3b77259fd1 100644 --- a/GPU/Directx9/FramebufferDX9.cpp +++ b/GPU/Directx9/FramebufferDX9.cpp @@ -1320,6 +1320,9 @@ namespace DX9 { if (SUCCEEDED(hr)) { GPUDebugBufferFormat fmt = GPU_DBG_FORMAT_24BIT_8X; + if (gstate_c.Supports(GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT)) { + fmt = GPU_DBG_FORMAT_24BIT_8X_DIV_256; + } int pixelSize = 4; buffer.Allocate(locked.Pitch / pixelSize, desc.Height, fmt, false); diff --git a/GPU/GLES/Framebuffer.cpp b/GPU/GLES/Framebuffer.cpp index 8ba44fcd36..ada8235c62 100644 --- a/GPU/GLES/Framebuffer.cpp +++ b/GPU/GLES/Framebuffer.cpp @@ -1971,7 +1971,11 @@ bool FramebufferManager::GetDepthbuffer(u32 fb_address, int fb_stride, u32 z_add return true; } - buffer.Allocate(vfb->renderWidth, vfb->renderHeight, GPU_DBG_FORMAT_FLOAT, false); + if (gstate_c.Supports(GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT)) { + buffer.Allocate(vfb->renderWidth, vfb->renderHeight, GPU_DBG_FORMAT_FLOAT_DIV_256, false); + } else { + buffer.Allocate(vfb->renderWidth, vfb->renderHeight, GPU_DBG_FORMAT_FLOAT, false); + } if (vfb->fbo) fbo_bind_for_read(vfb->fbo); if (gl_extensions.GLES3 || !gl_extensions.IsGLES) diff --git a/Windows/GEDebugger/GEDebugger.cpp b/Windows/GEDebugger/GEDebugger.cpp index d8bf28efd6..b9ae191b55 100644 --- a/Windows/GEDebugger/GEDebugger.cpp +++ b/Windows/GEDebugger/GEDebugger.cpp @@ -402,6 +402,15 @@ void CGEDebugger::DescribePixel(u32 pix, GPUDebugBufferFormat fmt, int x, int y, _snwprintf(desc, 256, L"%d,%d: %d / %f / %f", x, y, pix & 0x00FFFFFF, (pix & 0x00FFFFFF) * (1.0f / 16777215.0f), FromScaledDepth((pix & 0x00FFFFFF) * (1.0f / 16777215.0f))); break; + case GPU_DBG_FORMAT_24BIT_8X_DIV_256: + { + // These are only ever going to be depth values, so let's also show scaled to 16 bit. + int z24 = pix & 0x00FFFFFF; + int z16 = z24 - 0x800000 + 0x8000; + _snwprintf(desc, 256, L"%d,%d: %d / %f", x, y, z16, z16 * (1.0f / 65535.0f)); + } + break; + case GPU_DBG_FORMAT_24X_8BIT: _snwprintf(desc, 256, L"%d,%d: %d / %f", x, y, (pix >> 24) & 0xFF, ((pix >> 24) & 0xFF) * (1.0f / 255.0f)); break; @@ -410,6 +419,15 @@ void CGEDebugger::DescribePixel(u32 pix, GPUDebugBufferFormat fmt, int x, int y, _snwprintf(desc, 256, L"%d,%d: %f / %f", x, y, *(float *)&pix, FromScaledDepth(*(float *)&pix)); break; + case GPU_DBG_FORMAT_FLOAT_DIV_256: + { + double z = *(float *)&pix; + int z24 = (int)(z * 16777215.0); + int z16 = z24 - 0x800000 + 0x8000; + _snwprintf(desc, 256, L"%d,%d: %d / %f", x, y, z16, (z - 0.5 + (1.0 / 512.0)) * 256.0); + } + break; + default: _snwprintf(desc, 256, L"Unexpected format"); } diff --git a/Windows/GEDebugger/SimpleGLWindow.cpp b/Windows/GEDebugger/SimpleGLWindow.cpp index 7041405114..a755dc46b6 100644 --- a/Windows/GEDebugger/SimpleGLWindow.cpp +++ b/Windows/GEDebugger/SimpleGLWindow.cpp @@ -250,10 +250,18 @@ void SimpleGLWindow::Draw(const u8 *data, int w, int h, bool flipped, Format fmt } else if (fmt == FORMAT_FLOAT) { glfmt = GL_FLOAT; components = GL_RED; + } else if (fmt == FORMAT_FLOAT_DIV_256) { + glfmt = GL_UNSIGNED_INT; + components = GL_RED; + finalData = Reformat(data, fmt, w * h); } else if (fmt == FORMAT_24BIT_8X) { glfmt = GL_UNSIGNED_INT; components = GL_RED; finalData = Reformat(data, fmt, w * h); + } else if (fmt == FORMAT_24BIT_8X_DIV_256) { + glfmt = GL_UNSIGNED_INT; + components = GL_RED; + finalData = Reformat(data, fmt, w * h); } else if (fmt == FORMAT_24X_8BIT) { glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glfmt = GL_UNSIGNED_BYTE; @@ -545,6 +553,19 @@ const u8 *SimpleGLWindow::Reformat(const u8 *data, Format fmt, u32 numPixels) { for (u32 i = 0; i < numPixels; ++i) { reformatBuf_[i] = (data32[i] << 8) | ((data32[i] >> 16) & 0xFF); } + } else if (fmt == FORMAT_24BIT_8X_DIV_256) { + for (u32 i = 0; i < numPixels; ++i) { + int z24 = data32[i] & 0x00FFFFFF; + int z16 = z24 - 0x800000 + 0x8000; + reformatBuf_[i] = (z16 << 16) | z16; + } + } else if (fmt == FORMAT_FLOAT_DIV_256) { + for (u32 i = 0; i < numPixels; ++i) { + double z = *(float *)&data32[i]; + int z24 = (int)(z * 16777215.0); + int z16 = z24 - 0x800000 + 0x8000; + reformatBuf_[i] = (z16 << 16) | z16; + } } else if (fmt == FORMAT_24X_8BIT) { u8 *buf8 = (u8 *)reformatBuf_; for (u32 i = 0; i < numPixels; ++i) { diff --git a/Windows/GEDebugger/SimpleGLWindow.h b/Windows/GEDebugger/SimpleGLWindow.h index 26ebbcbea9..23b1f40ef6 100644 --- a/Windows/GEDebugger/SimpleGLWindow.h +++ b/Windows/GEDebugger/SimpleGLWindow.h @@ -42,6 +42,9 @@ struct SimpleGLWindow { FORMAT_8BIT = 0x12, FORMAT_24BIT_8X = 0x13, FORMAT_24X_8BIT = 0x14, + + FORMAT_FLOAT_DIV_256 = 0x18, + FORMAT_24BIT_8X_DIV_256 = 0x1B, }; enum Flags { From 0443fbebd07e2fed9c706b854f1f29e1684d2b45 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 18 Jan 2016 12:57:37 -0800 Subject: [PATCH 5/6] Add methods to download depth to PSP RAM. --- GPU/Common/FramebufferCommon.cpp | 2 + GPU/Directx9/FramebufferDX9.cpp | 49 +++++++++++++++++++++++ GPU/Directx9/FramebufferDX9.h | 1 + GPU/GLES/Framebuffer.cpp | 68 ++++++++++++++++++++++++++------ GPU/GLES/Framebuffer.h | 1 + 5 files changed, 108 insertions(+), 13 deletions(-) diff --git a/GPU/Common/FramebufferCommon.cpp b/GPU/Common/FramebufferCommon.cpp index e1122ab11d..0c4795073e 100644 --- a/GPU/Common/FramebufferCommon.cpp +++ b/GPU/Common/FramebufferCommon.cpp @@ -310,6 +310,8 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(const Frame vfb->fb_stride = params.fb_stride; vfb->format = params.fmt; } + // Keep track, but this isn't really used. + vfb->z_stride = params.z_stride; // Heuristic: In throughmode, a higher height could be used. Let's avoid shrinking the buffer. if (params.isModeThrough && (int)vfb->width < params.fb_stride) { vfb->width = std::max((int)vfb->width, drawing_width); diff --git a/GPU/Directx9/FramebufferDX9.cpp b/GPU/Directx9/FramebufferDX9.cpp index 3b77259fd1..9939fb865e 100644 --- a/GPU/Directx9/FramebufferDX9.cpp +++ b/GPU/Directx9/FramebufferDX9.cpp @@ -1055,6 +1055,55 @@ namespace DX9 { } } + void FramebufferManagerDX9::PackDepthbuffer(VirtualFramebuffer *vfb, int x, int y, int w, int h) { + if (!vfb->fbo) { + ERROR_LOG_REPORT_ONCE(vfbfbozero, SCEGE, "PackDepthbuffer: vfb->fbo == 0"); + return; + } + + // We always read the depth buffer in 24_8 format. + const u32 z_address = (0x04000000) | vfb->z_address; + + DEBUG_LOG(SCEGE, "Reading depthbuffer to mem at %08x for vfb=%08x", z_address, vfb->fb_address); + + LPDIRECT3DTEXTURE9 tex = fbo_get_depth_texture(vfb->fbo_dx9); + if (tex) { + D3DSURFACE_DESC desc; + D3DLOCKED_RECT locked; + tex->GetLevelDesc(0, &desc); + RECT rect = {0, 0, (LONG)desc.Width, (LONG)desc.Height}; + HRESULT hr = tex->LockRect(0, &locked, &rect, D3DLOCK_READONLY); + + if (SUCCEEDED(hr)) { + const int dstByteOffset = y * vfb->fb_stride * sizeof(s16); + const u32 *packed = (const u32 *)locked.pBits; + u16 *depth = (u16 *)Memory::GetPointer(z_address); + + // TODO: Optimize. + for (int yp = 0; yp < h; ++yp) { + for (int xp = 0; xp < w; ++xp) { + const int offset = (yp + y) & vfb->z_stride + x + xp; + + float scaled = FromScaledDepth((packed[offset] & 0x00FFFFFF) * (1.0f / 16777215.0f)); + if (scaled <= 0.0f) { + depth[offset] = 0; + } else if (scaled >= 65535.0f) { + depth[offset] = 65535; + } else { + depth[offset] = (int)scaled; + } + } + } + + tex->UnlockRect(0); + } else { + ERROR_LOG_REPORT(G3D, "Unable to lock rect from depth %08x: %d,%d %dx%d of %dx%d", vfb->fb_address, rect.left, rect.top, rect.right, rect.bottom, vfb->renderWidth, vfb->renderHeight); + } + } else { + ERROR_LOG_REPORT(G3D, "Unable to download render target depth from %08x", vfb->fb_address); + } + } + void FramebufferManagerDX9::EndFrame() { if (resized_) { DestroyAllFBOs(); diff --git a/GPU/Directx9/FramebufferDX9.h b/GPU/Directx9/FramebufferDX9.h index 81c5dfcdd6..9ea5b6b035 100644 --- a/GPU/Directx9/FramebufferDX9.h +++ b/GPU/Directx9/FramebufferDX9.h @@ -115,6 +115,7 @@ private: void SetNumExtraFBOs(int num); void PackFramebufferDirectx9_(VirtualFramebuffer *vfb, int x, int y, int w, int h); + void PackDepthbuffer(VirtualFramebuffer *vfb, int x, int y, int w, int h); static bool GetRenderTargetFramebuffer(LPDIRECT3DSURFACE9 renderTarget, LPDIRECT3DSURFACE9 offscreen, int w, int h, GPUDebugBuffer &buffer); // Used by DrawPixels diff --git a/GPU/GLES/Framebuffer.cpp b/GPU/GLES/Framebuffer.cpp index ada8235c62..680284f215 100644 --- a/GPU/GLES/Framebuffer.cpp +++ b/GPU/GLES/Framebuffer.cpp @@ -1676,30 +1676,30 @@ void FramebufferManager::PackFramebufferSync_(VirtualFramebuffer *vfb, int x, in } // Pixel size always 4 here because we always request RGBA8888 - size_t bufSize = vfb->fb_stride * std::max(vfb->height, (u16)h) * 4; + u32 bufSize = vfb->fb_stride * (h - y) * 4; u32 fb_address = (0x04000000) | vfb->fb_address; GLubyte *packed = 0; bool convert = vfb->format != GE_FORMAT_8888 || UseBGRA8888(); const int dstBpp = vfb->format == GE_FORMAT_8888 ? 4 : 2; - const int packWidth = x + w < vfb->width ? x + w : vfb->width; + const int packWidth = std::min(vfb->fb_stride, std::min(x + w, (int)vfb->width)); if (!convert) { - packed = (GLubyte *)Memory::GetPointer(fb_address); - } else { // End result may be 16-bit but we are reading 32-bit, so there may not be enough space at fb_address - u32 neededSize = (u32)bufSize * sizeof(GLubyte); - if (!convBuf_ || convBufSize_ < neededSize) { + int byteOffset = y * vfb->fb_stride * 4; + packed = (GLubyte *)Memory::GetPointer(fb_address + byteOffset); + } else { + // End result may be 16-bit but we are reading 32-bit, so there may not be enough space at fb_address + if (!convBuf_ || convBufSize_ < bufSize) { delete [] convBuf_; - convBuf_ = new u8[neededSize]; - convBufSize_ = neededSize; + convBuf_ = new u8[bufSize]; + convBufSize_ = bufSize; } packed = convBuf_; } if (packed) { - DEBUG_LOG(SCEGE, "Reading framebuffer to mem, bufSize = %u, packed = %p, fb_address = %08x", - (u32)bufSize, packed, fb_address); + DEBUG_LOG(SCEGE, "Reading framebuffer to mem, bufSize = %u, fb_address = %08x", bufSize, fb_address); glPixelStorei(GL_PACK_ALIGNMENT, 4); GLenum glfmt = GL_RGBA; @@ -1707,12 +1707,11 @@ void FramebufferManager::PackFramebufferSync_(VirtualFramebuffer *vfb, int x, in glfmt = GL_BGRA_EXT; } - int byteOffset = y * vfb->fb_stride * 4; - SafeGLReadPixels(0, y, h == 1 ? packWidth : vfb->fb_stride, h, glfmt, GL_UNSIGNED_BYTE, packed + byteOffset); + SafeGLReadPixels(0, y, h == 1 ? packWidth : vfb->fb_stride, h, glfmt, GL_UNSIGNED_BYTE, packed); if (convert) { int dstByteOffset = y * vfb->fb_stride * dstBpp; - ConvertFromRGBA8888(Memory::GetPointer(fb_address + dstByteOffset), packed + byteOffset, vfb->fb_stride, vfb->fb_stride, packWidth, h, vfb->format); + ConvertFromRGBA8888(Memory::GetPointer(fb_address + dstByteOffset), packed, vfb->fb_stride, vfb->fb_stride, packWidth, h, vfb->format); } } @@ -1731,6 +1730,49 @@ void FramebufferManager::PackFramebufferSync_(VirtualFramebuffer *vfb, int x, in fbo_unbind_read(); } +void FramebufferManager::PackDepthbuffer(VirtualFramebuffer *vfb, int x, int y, int w, int h) { + if (vfb->fbo) { + fbo_bind_for_read(vfb->fbo); + } else { + ERROR_LOG_REPORT_ONCE(vfbfbozero, SCEGE, "PackDepthbuffer: vfb->fbo == 0"); + return; + } + + // Pixel size always 4 here because we always request float + const u32 bufSize = vfb->z_stride * (h - y) * 4; + const u32 z_address = (0x04000000) | vfb->z_address; + const int packWidth = std::min(vfb->z_stride, std::min(x + w, (int)vfb->width)); + + if (!convBuf_ || convBufSize_ < bufSize) { + delete [] convBuf_; + convBuf_ = new u8[bufSize]; + convBufSize_ = bufSize; + } + + DEBUG_LOG(SCEGE, "Reading depthbuffer to mem at %08x for vfb=%08x", z_address, vfb->fb_address); + + glPixelStorei(GL_PACK_ALIGNMENT, 4); + SafeGLReadPixels(0, y, h == 1 ? packWidth : vfb->z_stride, h, GL_DEPTH_COMPONENT, GL_FLOAT, convBuf_); + + int dstByteOffset = y * vfb->fb_stride * sizeof(u16); + u16 *depth = (u16 *)Memory::GetPointer(z_address + dstByteOffset); + GLfloat *packed = (GLfloat *)convBuf_; + + int totalPixels = h == 1 ? packWidth : vfb->z_stride * h; + for (int i = 0; i < totalPixels; ++i) { + float scaled = FromScaledDepth(packed[i]); + if (scaled <= 0.0f) { + depth[i] = 0; + } else if (scaled >= 65535.0f) { + depth[i] = 65535; + } else { + depth[i] = (int)scaled; + } + } + + fbo_unbind_read(); +} + #ifdef _WIN32 void ShowScreenResolution(); #endif diff --git a/GPU/GLES/Framebuffer.h b/GPU/GLES/Framebuffer.h index 48e878be87..751364deea 100644 --- a/GPU/GLES/Framebuffer.h +++ b/GPU/GLES/Framebuffer.h @@ -145,6 +145,7 @@ private: void PackFramebufferAsync_(VirtualFramebuffer *vfb); // Not used under ES currently void PackFramebufferSync_(VirtualFramebuffer *vfb, int x, int y, int w, int h); + void PackDepthbuffer(VirtualFramebuffer *vfb, int x, int y, int w, int h); // Used by DrawPixels unsigned int drawPixelsTex_; From 79792a3c384e0bf0a7646cfe2c872042f41085aa Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Wed, 20 Jan 2016 22:53:47 -0800 Subject: [PATCH 6/6] d3d9: Account for half-pixel z offset. --- GPU/Directx9/ShaderManagerDX9.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/GPU/Directx9/ShaderManagerDX9.cpp b/GPU/Directx9/ShaderManagerDX9.cpp index fd760fa555..40831cba10 100644 --- a/GPU/Directx9/ShaderManagerDX9.cpp +++ b/GPU/Directx9/ShaderManagerDX9.cpp @@ -488,7 +488,8 @@ void ShaderManagerDX9::VSUpdateUniforms(int dirtyUniforms) { float halfActualZRange = vpZScale / gstate_c.vpDepthScale; float minz = -((gstate_c.vpZOffset * halfActualZRange) - vpZCenter) - halfActualZRange; float viewZScale = halfActualZRange * 2.0f; - float viewZCenter = minz; + // Account for the half pixel offset. + float viewZCenter = minz + (DepthSliceFactor() / 256.0f) * 0.5f; float viewZInvScale; if (viewZScale != 0.0) {