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