From 0e8aeaea3a70c47c922ae566f0ae9b82d61a87c1 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Tue, 14 Feb 2017 12:42:35 +0100 Subject: [PATCH 1/3] D3D11: Implement basic framebuffer readback. Also make debug interfaces more consistent. --- GPU/Common/DepalettizeShaderCommon.cpp | 2 + GPU/Common/FramebufferCommon.cpp | 1 + GPU/Common/FramebufferCommon.h | 6 ++ GPU/D3D11/FramebufferManagerD3D11.cpp | 122 +++++++++---------------- GPU/D3D11/FramebufferManagerD3D11.h | 10 +- GPU/D3D11/GPU_D3D11.cpp | 12 --- GPU/D3D11/GPU_D3D11.h | 3 - GPU/Directx9/FramebufferDX9.cpp | 26 +----- GPU/Directx9/FramebufferDX9.h | 6 +- GPU/Directx9/GPU_DX9.cpp | 12 --- GPU/Directx9/GPU_DX9.h | 3 - GPU/GLES/FramebufferManagerGLES.h | 6 +- GPU/GLES/GPU_GLES.cpp | 24 ----- GPU/GLES/GPU_GLES.h | 3 - GPU/GPUCommon.cpp | 24 +++++ GPU/GPUCommon.h | 4 + GPU/Software/SoftGpu.cpp | 3 +- GPU/Vulkan/FramebufferVulkan.cpp | 2 +- GPU/Vulkan/FramebufferVulkan.h | 6 +- ext/native/thin3d/thin3d.h | 1 + ext/native/thin3d/thin3d_d3d11.cpp | 13 ++- 21 files changed, 115 insertions(+), 174 deletions(-) diff --git a/GPU/Common/DepalettizeShaderCommon.cpp b/GPU/Common/DepalettizeShaderCommon.cpp index f4f6f936421b..29f68ce07886 100644 --- a/GPU/Common/DepalettizeShaderCommon.cpp +++ b/GPU/Common/DepalettizeShaderCommon.cpp @@ -26,6 +26,8 @@ #define WRITE p+=sprintf +// TODO: Add a compute shader path. Complete waste of time to set up a graphics state. + // Uses integer instructions available since OpenGL 3.0. Suitable for ES 3.0 as well. void GenerateDepalShader300(char *buffer, GEBufferFormat pixelFormat, ShaderLanguage language) { char *p = buffer; diff --git a/GPU/Common/FramebufferCommon.cpp b/GPU/Common/FramebufferCommon.cpp index a20d11828a4c..448637b03e1c 100644 --- a/GPU/Common/FramebufferCommon.cpp +++ b/GPU/Common/FramebufferCommon.cpp @@ -1325,6 +1325,7 @@ void FramebufferManagerCommon::FindTransferFramebuffers(VirtualFramebuffer *&dst } } +// 1:1 pixel sides buffers, we resize buffers to these before we read them back. VirtualFramebuffer *FramebufferManagerCommon::FindDownloadTempBuffer(VirtualFramebuffer *vfb) { // For now we'll keep these on the same struct as the ones that can get displayed // (and blatantly copy work already done above while at it). diff --git a/GPU/Common/FramebufferCommon.h b/GPU/Common/FramebufferCommon.h index 205120f31f37..faafae74aa8d 100644 --- a/GPU/Common/FramebufferCommon.h +++ b/GPU/Common/FramebufferCommon.h @@ -152,6 +152,7 @@ namespace Draw { class DrawContext; } +struct GPUDebugBuffer; class TextureCacheCommon; class ShaderManagerCommon; @@ -264,6 +265,11 @@ class FramebufferManagerCommon { Draw::Framebuffer *GetTempFBO(u16 w, u16 h, Draw::FBColorDepth depth = Draw::FBO_8888); + // Debug features + virtual bool GetFramebuffer(u32 fb_address, int fb_stride, GEBufferFormat format, GPUDebugBuffer &buffer, int maxRes) = 0; + virtual bool GetDepthbuffer(u32 fb_address, int fb_stride, u32 z_address, int z_stride, GPUDebugBuffer &buffer) = 0; + virtual bool GetStencilbuffer(u32 fb_address, int fb_stride, GPUDebugBuffer &buffer) = 0; + protected: virtual void SetViewport2D(int x, int y, int w, int h) = 0; void CalculatePostShaderUniforms(int bufferWidth, int bufferHeight, int renderWidth, int renderHeight, PostShaderUniforms *uniforms); diff --git a/GPU/D3D11/FramebufferManagerD3D11.cpp b/GPU/D3D11/FramebufferManagerD3D11.cpp index fba6d212b1ba..64fa1dd505f9 100644 --- a/GPU/D3D11/FramebufferManagerD3D11.cpp +++ b/GPU/D3D11/FramebufferManagerD3D11.cpp @@ -105,6 +105,18 @@ FramebufferManagerD3D11::FramebufferManagerD3D11(Draw::DrawContext *draw) vb.Usage = D3D11_USAGE_DYNAMIC; vb.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; device_->CreateBuffer(&vb, nullptr, &quadBuffer_); + + D3D11_TEXTURE2D_DESC packDesc{}; + packDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + packDesc.BindFlags = 0; + packDesc.Width = 512; // 512x512 is the maximum size of a framebuffer on the PSP. + packDesc.Height = 512; + packDesc.ArraySize = 1; + packDesc.MipLevels = 1; + packDesc.Usage = D3D11_USAGE_STAGING; + packDesc.SampleDesc.Count = 1; + packDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + device_->CreateTexture2D(&packDesc, nullptr, &packTexture_); } FramebufferManagerD3D11::~FramebufferManagerD3D11() { @@ -635,7 +647,7 @@ void ConvertFromRGBA8888(u8 *dst, u8 *src, u32 dstStride, u32 srcStride, u32 wid return; } else { for (u32 y = 0; y < height; ++y) { - ConvertBGRA8888ToRGBA8888(dst32, src32, width); + memcpy(dst32, src32, width * 4); src32 += srcStride; dst32 += dstStride; } @@ -646,21 +658,21 @@ void ConvertFromRGBA8888(u8 *dst, u8 *src, u32 dstStride, u32 srcStride, u32 wid switch (format) { case GE_FORMAT_565: // BGR 565 for (u32 y = 0; y < height; ++y) { - ConvertBGRA8888ToRGB565(dst16, src32, width); + ConvertRGBA8888ToRGB565(dst16, src32, width); src32 += srcStride; dst16 += dstStride; } break; case GE_FORMAT_5551: // ABGR 1555 for (u32 y = 0; y < height; ++y) { - ConvertBGRA8888ToRGBA5551(dst16, src32, width); + ConvertRGBA8888ToRGBA5551(dst16, src32, width); src32 += srcStride; dst16 += dstStride; } break; case GE_FORMAT_4444: // ABGR 4444 for (u32 y = 0; y < height; ++y) { - ConvertBGRA8888ToRGBA4444(dst16, src32, width); + ConvertRGBA8888ToRGBA4444(dst16, src32, width); src32 += srcStride; dst16 += dstStride; } @@ -673,6 +685,9 @@ void ConvertFromRGBA8888(u8 *dst, u8 *src, u32 dstStride, u32 srcStride, u32 wid } } +// This function takes an already correctly-sized framebuffer and packs it into RAM. +// Does not need to account for scaling. +// Color conversion is currently done on CPU but should be done on GPU. void FramebufferManagerD3D11::PackFramebufferD3D11_(VirtualFramebuffer *vfb, int x, int y, int w, int h) { if (!vfb->fbo) { ERROR_LOG_REPORT_ONCE(vfbfbozero, SCEGE, "PackFramebufferD3D11_: vfb->fbo == 0"); @@ -686,85 +701,38 @@ void FramebufferManagerD3D11::PackFramebufferD3D11_(VirtualFramebuffer *vfb, int // We always need to convert from the framebuffer native format. // Right now that's always 8888. DEBUG_LOG(HLE, "Reading framebuffer to mem, fb_address = %08x", fb_address); + ID3D11Texture2D *colorTex = (ID3D11Texture2D *)draw_->GetFramebufferAPITexture(vfb->fbo, Draw::FB_COLOR_BIT, 0); - /* - LPDIRECT3DSURFACE9 renderTarget = (LPDIRECT3DSURFACE9)draw_->GetFramebufferAPITexture(vfb->fbo, Draw::FB_COLOR_BIT | Draw::FB_SURFACE_BIT, 0); - D3DSURFACE_DESC desc; - renderTarget->GetDesc(&desc); - - LPDIRECT3DSURFACE9 offscreen = GetOffscreenSurface(renderTarget, vfb); - if (offscreen) { - HRESULT hr = pD3Ddevice->GetRenderTargetData(renderTarget, offscreen); - if (SUCCEEDED(hr)) { - D3DLOCKED_RECT locked; - u32 widthFactor = vfb->renderWidth / vfb->bufferWidth; - u32 heightFactor = vfb->renderHeight / vfb->bufferHeight; - RECT rect = { (LONG)(x * widthFactor), (LONG)(y * heightFactor), (LONG)((x + w) * widthFactor), (LONG)((y + h) * heightFactor) }; - hr = offscreen->LockRect(&locked, &rect, D3DLOCK_READONLY); - if (SUCCEEDED(hr)) { - // TODO: Handle the other formats? We don't currently create them, I think. - const int dstByteOffset = (y * vfb->fb_stride + x) * dstBpp; - // Pixel size always 4 here because we always request BGRA8888. - ConvertFromRGBA8888(Memory::GetPointer(fb_address + dstByteOffset), (u8 *)locked.pBits, vfb->fb_stride, locked.Pitch / 4, w, h, vfb->format); - offscreen->UnlockRect(); - } else { - ERROR_LOG_REPORT(G3D, "Unable to lock rect from %08x: %d,%d %dx%d of %dx%d", fb_address, rect.left, rect.top, rect.right, rect.bottom, vfb->renderWidth, vfb->renderHeight); - } - } else { - ERROR_LOG_REPORT(G3D, "Unable to download render target data from %08x", fb_address); - } + D3D11_BOX srcBox{ 0, 0, 0, vfb->width, vfb->height, 1 }; + context_->CopySubresourceRegion(packTexture_, 0, 0, 0, 0, colorTex, 0, &srcBox); + + // Ideally, we'd round robin between two packTexture_, and simply use the other one. Though if the game + // does a once-off copy, that won't work at all. + + // BIG GPU STALL + D3D11_MAPPED_SUBRESOURCE map; + HRESULT result = context_->Map(packTexture_, 0, D3D11_MAP_READ, 0, &map); + if (FAILED(result)) { + return; } - */ + + // TODO: Handle the other formats? We don't currently create them, I think. + const int srcByteOffset = y * map.RowPitch + x * 4; + const int dstByteOffset = (y * vfb->fb_stride + x) * dstBpp; + // Pixel size always 4 here because we always request BGRA8888. + ConvertFromRGBA8888(Memory::GetPointer(fb_address + dstByteOffset), (u8 *)map.pData, vfb->fb_stride, map.RowPitch/4, w, h, vfb->format); + context_->Unmap(packTexture_, 0); } +// Nobody calls this yet. void FramebufferManagerD3D11::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 = (LPDIRECT3DTEXTURE9)draw_->GetFramebufferAPITexture(vfb->fbo, Draw::FB_DEPTH_BIT, 0); - 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); - }*/ + // TODO } void FramebufferManagerD3D11::EndFrame() { @@ -868,18 +836,18 @@ void FramebufferManagerD3D11::Resized() { resized_ = true; } -bool FramebufferManagerD3D11::GetCurrentFramebuffer(GPUDebugBuffer &buffer, GPUDebugFramebufferType type, int maxRes) { +bool FramebufferManagerD3D11::GetFramebuffer(u32 fb_address, int fb_stride, GEBufferFormat format, GPUDebugBuffer &buffer, int maxRes) { return false; } -bool FramebufferManagerD3D11::GetOutputFramebuffer(GPUDebugBuffer &buffer) { +bool FramebufferManagerD3D11::GetDepthbuffer(u32 fb_address, int fb_stride, u32 z_address, int z_stride, GPUDebugBuffer &buffer) { return false; } -bool FramebufferManagerD3D11::GetCurrentDepthbuffer(GPUDebugBuffer &buffer) { +bool FramebufferManagerD3D11::GetStencilbuffer(u32 fb_address, int fb_stride, GPUDebugBuffer &buffer) { return false; } -bool FramebufferManagerD3D11::GetCurrentStencilbuffer(GPUDebugBuffer &buffer) { +bool FramebufferManagerD3D11::GetOutputFramebuffer(GPUDebugBuffer &buffer) { return false; -} \ No newline at end of file +} diff --git a/GPU/D3D11/FramebufferManagerD3D11.h b/GPU/D3D11/FramebufferManagerD3D11.h index bb91fd41654e..6ea83585cf0c 100644 --- a/GPU/D3D11/FramebufferManagerD3D11.h +++ b/GPU/D3D11/FramebufferManagerD3D11.h @@ -69,9 +69,9 @@ class FramebufferManagerD3D11 : public FramebufferManagerCommon { virtual bool NotifyStencilUpload(u32 addr, int size, bool skipZero = false) override; - bool GetCurrentFramebuffer(GPUDebugBuffer &buffer, GPUDebugFramebufferType type, int maxRes); - bool GetCurrentDepthbuffer(GPUDebugBuffer &buffer); - bool GetCurrentStencilbuffer(GPUDebugBuffer &buffer); + bool GetFramebuffer(u32 fb_address, int fb_stride, GEBufferFormat format, GPUDebugBuffer &buffer, int maxRes) override; + bool GetDepthbuffer(u32 fb_address, int fb_stride, u32 z_address, int z_stride, GPUDebugBuffer &buffer) override; + bool GetStencilbuffer(u32 fb_address, int fb_stride, GPUDebugBuffer &buffer) override; bool GetOutputFramebuffer(GPUDebugBuffer &buffer); virtual void RebindFramebuffer() override; @@ -136,6 +136,8 @@ class FramebufferManagerD3D11 : public FramebufferManagerCommon { ShaderManagerD3D11 *shaderManagerD3D11_; DrawEngineD3D11 *drawEngine_; + ID3D11Texture2D *packTexture_; + // Used by post-processing shader std::vector extraFBOs_; @@ -145,4 +147,4 @@ class FramebufferManagerD3D11 : public FramebufferManagerCommon { AsyncPBO *pixelBufObj_; //this isn't that large u8 currentPBO_; #endif -}; \ No newline at end of file +}; diff --git a/GPU/D3D11/GPU_D3D11.cpp b/GPU/D3D11/GPU_D3D11.cpp index 1fc5bc9b4424..46b54f608825 100644 --- a/GPU/D3D11/GPU_D3D11.cpp +++ b/GPU/D3D11/GPU_D3D11.cpp @@ -981,18 +981,6 @@ void GPU_D3D11::DoState(PointerWrap &p) { } } -bool GPU_D3D11::GetCurrentFramebuffer(GPUDebugBuffer &buffer, GPUDebugFramebufferType type, int maxRes) { - return framebufferManagerD3D11_->GetCurrentFramebuffer(buffer, type, maxRes); -} - -bool GPU_D3D11::GetCurrentDepthbuffer(GPUDebugBuffer &buffer) { - return framebufferManagerD3D11_->GetCurrentDepthbuffer(buffer); -} - -bool GPU_D3D11::GetCurrentStencilbuffer(GPUDebugBuffer &buffer) { - return framebufferManagerD3D11_->GetCurrentStencilbuffer(buffer); -} - bool GPU_D3D11::GetCurrentTexture(GPUDebugBuffer &buffer, int level) { if (!gstate.isTextureMapEnabled()) { return false; diff --git a/GPU/D3D11/GPU_D3D11.h b/GPU/D3D11/GPU_D3D11.h index a618462a57b5..115d1187936e 100644 --- a/GPU/D3D11/GPU_D3D11.h +++ b/GPU/D3D11/GPU_D3D11.h @@ -64,9 +64,6 @@ class GPU_D3D11 : public GPUCommon { } std::vector GetFramebufferList() override; - bool GetCurrentFramebuffer(GPUDebugBuffer &buffer, GPUDebugFramebufferType type, int maxRes = -1) override; - bool GetCurrentDepthbuffer(GPUDebugBuffer &buffer) override; - bool GetCurrentStencilbuffer(GPUDebugBuffer &buffer) override; bool GetCurrentTexture(GPUDebugBuffer &buffer, int level) override; bool GetCurrentClut(GPUDebugBuffer &buffer) override; bool GetOutputFramebuffer(GPUDebugBuffer &buffer) override; diff --git a/GPU/Directx9/FramebufferDX9.cpp b/GPU/Directx9/FramebufferDX9.cpp index 4a2e13be47d4..f1934ab8912e 100644 --- a/GPU/Directx9/FramebufferDX9.cpp +++ b/GPU/Directx9/FramebufferDX9.cpp @@ -632,7 +632,7 @@ static void DXSetViewport(float x, float y, float w, float h, float minZ, float void FramebufferManagerDX9::BlitFramebuffer(VirtualFramebuffer *dst, int dstX, int dstY, VirtualFramebuffer *src, int srcX, int srcY, int w, int h, int bpp) { if (!dst->fbo || !src->fbo || !useBufferedRendering_) { - // This can happen if they recently switched from non-buffered. + // This can happen if we recently switched from non-buffered. draw_->BindBackbufferAsRenderTarget(); return; } @@ -939,11 +939,7 @@ static void DXSetViewport(float x, float y, float w, float h, float minZ, float resized_ = true; } - bool FramebufferManagerDX9::GetCurrentFramebuffer(GPUDebugBuffer &buffer, GPUDebugFramebufferType type, int maxRes) { - u32 fb_address = type == GPU_DBG_FRAMEBUF_RENDER ? gstate.getFrameBufRawAddress() : displayFramebufPtr_; - int fb_stride = type == GPU_DBG_FRAMEBUF_RENDER ? gstate.FrameBufStride() : displayStride_; - GEBufferFormat fb_format = type == GPU_DBG_FRAMEBUF_RENDER ? gstate.FrameBufFormat() : displayFormat_; - + bool FramebufferManagerDX9::GetFramebuffer(u32 fb_address, int fb_stride, GEBufferFormat fb_format, GPUDebugBuffer &buffer, int maxRes) { VirtualFramebuffer *vfb = currentRenderVfb_; if (!vfb) { vfb = GetVFBAt(fb_address); @@ -1026,13 +1022,7 @@ static void DXSetViewport(float x, float y, float w, float h, float minZ, float return success; } - bool FramebufferManagerDX9::GetCurrentDepthbuffer(GPUDebugBuffer &buffer) { - u32 fb_address = gstate.getFrameBufRawAddress(); - int fb_stride = gstate.FrameBufStride(); - - u32 z_address = gstate.getDepthBufRawAddress(); - int z_stride = gstate.DepthBufStride(); - + bool FramebufferManagerDX9::GetDepthbuffer(u32 fb_address, int fb_stride, u32 z_address, int z_stride, GPUDebugBuffer &buffer) { VirtualFramebuffer *vfb = currentRenderVfb_; if (!vfb) { vfb = GetVFBAt(fb_address); @@ -1070,13 +1060,7 @@ static void DXSetViewport(float x, float y, float w, float h, float minZ, float return success; } - bool FramebufferManagerDX9::GetCurrentStencilbuffer(GPUDebugBuffer &buffer) { - u32 fb_address = gstate.getFrameBufRawAddress(); - int fb_stride = gstate.FrameBufStride(); - - u32 z_address = gstate.getDepthBufRawAddress(); - int z_stride = gstate.DepthBufStride(); - + bool FramebufferManagerDX9::GetStencilbuffer(u32 fb_address, int fb_stride, GPUDebugBuffer &buffer) { VirtualFramebuffer *vfb = currentRenderVfb_; if (!vfb) { vfb = GetVFBAt(fb_address); @@ -1084,7 +1068,7 @@ static void DXSetViewport(float x, float y, float w, float h, float minZ, float if (!vfb) { // If there's no vfb and we're drawing there, must be memory? - buffer = GPUDebugBuffer(Memory::GetPointer(z_address | 0x04000000), z_stride, 512, GPU_DBG_FORMAT_16BIT); + buffer = GPUDebugBuffer(Memory::GetPointer(vfb->z_address | 0x04000000), vfb->z_stride, 512, GPU_DBG_FORMAT_16BIT); return true; } diff --git a/GPU/Directx9/FramebufferDX9.h b/GPU/Directx9/FramebufferDX9.h index e86e0632b9cc..35da6ac32ad9 100644 --- a/GPU/Directx9/FramebufferDX9.h +++ b/GPU/Directx9/FramebufferDX9.h @@ -71,9 +71,9 @@ class FramebufferManagerDX9 : public FramebufferManagerCommon { virtual bool NotifyStencilUpload(u32 addr, int size, bool skipZero = false) override; - bool GetCurrentFramebuffer(GPUDebugBuffer &buffer, GPUDebugFramebufferType type, int maxRes); - bool GetCurrentDepthbuffer(GPUDebugBuffer &buffer); - bool GetCurrentStencilbuffer(GPUDebugBuffer &buffer); + bool GetFramebuffer(u32 fb_address, int fb_stride, GEBufferFormat format, GPUDebugBuffer &buffer, int maxRes); + bool GetDepthbuffer(u32 fb_address, int fb_stride, u32 z_address, int z_stride, GPUDebugBuffer &buffer) override; + bool GetStencilbuffer(u32 fb_address, int fb_stride, GPUDebugBuffer &buffer) override; bool GetOutputFramebuffer(GPUDebugBuffer &buffer); virtual void RebindFramebuffer() override; diff --git a/GPU/Directx9/GPU_DX9.cpp b/GPU/Directx9/GPU_DX9.cpp index 230ac35b42e5..62c920c39745 100644 --- a/GPU/Directx9/GPU_DX9.cpp +++ b/GPU/Directx9/GPU_DX9.cpp @@ -976,18 +976,6 @@ void GPU_DX9::DoState(PointerWrap &p) { } } -bool GPU_DX9::GetCurrentFramebuffer(GPUDebugBuffer &buffer, GPUDebugFramebufferType type, int maxRes) { - return framebufferManagerDX9_->GetCurrentFramebuffer(buffer, type, maxRes); -} - -bool GPU_DX9::GetCurrentDepthbuffer(GPUDebugBuffer &buffer) { - return framebufferManagerDX9_->GetCurrentDepthbuffer(buffer); -} - -bool GPU_DX9::GetCurrentStencilbuffer(GPUDebugBuffer &buffer) { - return framebufferManagerDX9_->GetCurrentStencilbuffer(buffer); -} - bool GPU_DX9::GetCurrentTexture(GPUDebugBuffer &buffer, int level) { if (!gstate.isTextureMapEnabled()) { return false; diff --git a/GPU/Directx9/GPU_DX9.h b/GPU/Directx9/GPU_DX9.h index e5f97a538903..a09831d59834 100644 --- a/GPU/Directx9/GPU_DX9.h +++ b/GPU/Directx9/GPU_DX9.h @@ -65,9 +65,6 @@ class GPU_DX9 : public GPUCommon { } std::vector GetFramebufferList() override; - bool GetCurrentFramebuffer(GPUDebugBuffer &buffer, GPUDebugFramebufferType type, int maxRes = -1) override; - bool GetCurrentDepthbuffer(GPUDebugBuffer &buffer) override; - bool GetCurrentStencilbuffer(GPUDebugBuffer &buffer) override; bool GetCurrentTexture(GPUDebugBuffer &buffer, int level) override; bool GetCurrentClut(GPUDebugBuffer &buffer) override; bool GetOutputFramebuffer(GPUDebugBuffer &buffer) override; diff --git a/GPU/GLES/FramebufferManagerGLES.h b/GPU/GLES/FramebufferManagerGLES.h index b98ccd52ed68..7675738a5ea9 100644 --- a/GPU/GLES/FramebufferManagerGLES.h +++ b/GPU/GLES/FramebufferManagerGLES.h @@ -87,9 +87,9 @@ class FramebufferManagerGLES : public FramebufferManagerCommon { bool NotifyStencilUpload(u32 addr, int size, bool skipZero = false) override; - bool GetFramebuffer(u32 fb_address, int fb_stride, GEBufferFormat format, GPUDebugBuffer &buffer, int maxRes); - bool GetDepthbuffer(u32 fb_address, int fb_stride, u32 z_address, int z_stride, GPUDebugBuffer &buffer); - bool GetStencilbuffer(u32 fb_address, int fb_stride, GPUDebugBuffer &buffer); + bool GetFramebuffer(u32 fb_address, int fb_stride, GEBufferFormat format, GPUDebugBuffer &buffer, int maxRes) override; + bool GetDepthbuffer(u32 fb_address, int fb_stride, u32 z_address, int z_stride, GPUDebugBuffer &buffer) override; + bool GetStencilbuffer(u32 fb_address, int fb_stride, GPUDebugBuffer &buffer) override; bool GetOutputFramebuffer(GPUDebugBuffer &buffer); virtual void RebindFramebuffer() override; diff --git a/GPU/GLES/GPU_GLES.cpp b/GPU/GLES/GPU_GLES.cpp index f4d5ae585da5..28d7192d1600 100644 --- a/GPU/GLES/GPU_GLES.cpp +++ b/GPU/GLES/GPU_GLES.cpp @@ -1230,30 +1230,6 @@ void GPU_GLES::DoState(PointerWrap &p) { } } -bool GPU_GLES::GetCurrentFramebuffer(GPUDebugBuffer &buffer, GPUDebugFramebufferType type, int maxRes) { - u32 fb_address = type == GPU_DBG_FRAMEBUF_RENDER ? gstate.getFrameBufRawAddress() : framebufferManagerGL_->DisplayFramebufAddr(); - int fb_stride = type == GPU_DBG_FRAMEBUF_RENDER ? gstate.FrameBufStride() : framebufferManagerGL_->DisplayFramebufStride(); - GEBufferFormat format = type == GPU_DBG_FRAMEBUF_RENDER ? gstate.FrameBufFormat() : framebufferManagerGL_->DisplayFramebufFormat(); - return framebufferManagerGL_->GetFramebuffer(fb_address, fb_stride, format, buffer, maxRes); -} - -bool GPU_GLES::GetCurrentDepthbuffer(GPUDebugBuffer &buffer) { - u32 fb_address = gstate.getFrameBufRawAddress(); - int fb_stride = gstate.FrameBufStride(); - - u32 z_address = gstate.getDepthBufRawAddress(); - int z_stride = gstate.DepthBufStride(); - - return framebufferManagerGL_->GetDepthbuffer(fb_address, fb_stride, z_address, z_stride, buffer); -} - -bool GPU_GLES::GetCurrentStencilbuffer(GPUDebugBuffer &buffer) { - u32 fb_address = gstate.getFrameBufRawAddress(); - int fb_stride = gstate.FrameBufStride(); - - return framebufferManagerGL_->GetStencilbuffer(fb_address, fb_stride, buffer); -} - bool GPU_GLES::GetCurrentTexture(GPUDebugBuffer &buffer, int level) { if (!gstate.isTextureMapEnabled()) { return false; diff --git a/GPU/GLES/GPU_GLES.h b/GPU/GLES/GPU_GLES.h index a90d1c646972..31132ba586f5 100644 --- a/GPU/GLES/GPU_GLES.h +++ b/GPU/GLES/GPU_GLES.h @@ -67,9 +67,6 @@ class GPU_GLES : public GPUCommon { } std::vector GetFramebufferList() override; - bool GetCurrentFramebuffer(GPUDebugBuffer &buffer, GPUDebugFramebufferType type, int maxRes) override; - bool GetCurrentDepthbuffer(GPUDebugBuffer &buffer) override; - bool GetCurrentStencilbuffer(GPUDebugBuffer &buffer) override; bool GetCurrentTexture(GPUDebugBuffer &buffer, int level) override; bool GetCurrentClut(GPUDebugBuffer &buffer) override; bool GetOutputFramebuffer(GPUDebugBuffer &buffer) override; diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index efdb4646f525..d75f0d70cf6c 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -2116,3 +2116,27 @@ bool GPUCommon::PerformStencilUpload(u32 dest, int size) { void GPUCommon::PerformStencilUploadInternal(u32 dest, int size) { framebufferManager_->NotifyStencilUpload(dest, size); } + +bool GPUCommon::GetCurrentFramebuffer(GPUDebugBuffer &buffer, GPUDebugFramebufferType type, int maxRes) { + u32 fb_address = type == GPU_DBG_FRAMEBUF_RENDER ? gstate.getFrameBufRawAddress() : framebufferManager_->DisplayFramebufAddr(); + int fb_stride = type == GPU_DBG_FRAMEBUF_RENDER ? gstate.FrameBufStride() : framebufferManager_->DisplayFramebufStride(); + GEBufferFormat format = type == GPU_DBG_FRAMEBUF_RENDER ? gstate.FrameBufFormat() : framebufferManager_->DisplayFramebufFormat(); + return framebufferManager_->GetFramebuffer(fb_address, fb_stride, format, buffer, maxRes); +} + +bool GPUCommon::GetCurrentDepthbuffer(GPUDebugBuffer &buffer) { + u32 fb_address = gstate.getFrameBufRawAddress(); + int fb_stride = gstate.FrameBufStride(); + + u32 z_address = gstate.getDepthBufRawAddress(); + int z_stride = gstate.DepthBufStride(); + + return framebufferManager_->GetDepthbuffer(fb_address, fb_stride, z_address, z_stride, buffer); +} + +bool GPUCommon::GetCurrentStencilbuffer(GPUDebugBuffer &buffer) { + u32 fb_address = gstate.getFrameBufRawAddress(); + int fb_stride = gstate.FrameBufStride(); + + return framebufferManager_->GetStencilbuffer(fb_address, fb_stride, buffer); +} diff --git a/GPU/GPUCommon.h b/GPU/GPUCommon.h index 30164340309f..ca8bc4dec845 100644 --- a/GPU/GPUCommon.h +++ b/GPU/GPUCommon.h @@ -162,6 +162,10 @@ class GPUCommon : public GPUThreadEventQueue, public GPUDebugInterface { // From GPUDebugInterface. bool GetCurrentDisplayList(DisplayList &list) override; + bool GetCurrentFramebuffer(GPUDebugBuffer &buffer, GPUDebugFramebufferType type, int maxRes) override; + bool GetCurrentDepthbuffer(GPUDebugBuffer &buffer) override; + bool GetCurrentStencilbuffer(GPUDebugBuffer &buffer) override; + std::vector ActiveDisplayLists() override; void ResetListPC(int listID, u32 pc) override; void ResetListStall(int listID, u32 stall) override; diff --git a/GPU/Software/SoftGpu.cpp b/GPU/Software/SoftGpu.cpp index e4dae6d0c686..776873afc040 100644 --- a/GPU/Software/SoftGpu.cpp +++ b/GPU/Software/SoftGpu.cpp @@ -838,8 +838,7 @@ bool SoftGPU::FramebufferDirty() { return true; } -bool SoftGPU::GetCurrentFramebuffer(GPUDebugBuffer &buffer, GPUDebugFramebufferType type, int maxRes) -{ +bool SoftGPU::GetCurrentFramebuffer(GPUDebugBuffer &buffer, GPUDebugFramebufferType type, int maxRes) { int x1 = gstate.getRegionX1(); int y1 = gstate.getRegionY1(); int x2 = gstate.getRegionX2() + 1; diff --git a/GPU/Vulkan/FramebufferVulkan.cpp b/GPU/Vulkan/FramebufferVulkan.cpp index b1fcff2d1c1d..c96955365007 100644 --- a/GPU/Vulkan/FramebufferVulkan.cpp +++ b/GPU/Vulkan/FramebufferVulkan.cpp @@ -1166,7 +1166,7 @@ void FramebufferManagerVulkan::Resized() { resized_ = true; } -bool FramebufferManagerVulkan::GetFramebuffer(u32 fb_address, int fb_stride, GEBufferFormat format, GPUDebugBuffer &buffer) { +bool FramebufferManagerVulkan::GetFramebuffer(u32 fb_address, int fb_stride, GEBufferFormat format, GPUDebugBuffer &buffer, int maxStride) { // TODO: Doing this synchronously will require stalling the pipeline. Maybe better // to do it callback-style? /* diff --git a/GPU/Vulkan/FramebufferVulkan.h b/GPU/Vulkan/FramebufferVulkan.h index b674bec25d0c..16b6f436306a 100644 --- a/GPU/Vulkan/FramebufferVulkan.h +++ b/GPU/Vulkan/FramebufferVulkan.h @@ -100,9 +100,9 @@ class FramebufferManagerVulkan : public FramebufferManagerCommon { bool NotifyStencilUpload(u32 addr, int size, bool skipZero = false) override; - bool GetFramebuffer(u32 fb_address, int fb_stride, GEBufferFormat format, GPUDebugBuffer &buffer); - bool GetDepthbuffer(u32 fb_address, int fb_stride, u32 z_address, int z_stride, GPUDebugBuffer &buffer); - bool GetStencilbuffer(u32 fb_address, int fb_stride, GPUDebugBuffer &buffer); + bool GetFramebuffer(u32 fb_address, int fb_stride, GEBufferFormat format, GPUDebugBuffer &buffer, int maxRes) override; + bool GetDepthbuffer(u32 fb_address, int fb_stride, u32 z_address, int z_stride, GPUDebugBuffer &buffer) override; + bool GetStencilbuffer(u32 fb_address, int fb_stride, GPUDebugBuffer &buffer) override; static bool GetOutputFramebuffer(GPUDebugBuffer &buffer); virtual void RebindFramebuffer() override; diff --git a/ext/native/thin3d/thin3d.h b/ext/native/thin3d/thin3d.h index 15f04676d8ee..05e07547ac6d 100644 --- a/ext/native/thin3d/thin3d.h +++ b/ext/native/thin3d/thin3d.h @@ -328,6 +328,7 @@ enum FBChannel { // Implementation specific FB_SURFACE_BIT = 32, // Used in conjunction with the others in D3D9 to get surfaces through get_api_texture + FB_VIEW_BIT = 64, // Used in conjunction with the others in D3D11 to get shader resource views through get_api_texture }; enum FBBlitFilter { diff --git a/ext/native/thin3d/thin3d_d3d11.cpp b/ext/native/thin3d/thin3d_d3d11.cpp index e2a51dccd316..7047b9ecfa14 100644 --- a/ext/native/thin3d/thin3d_d3d11.cpp +++ b/ext/native/thin3d/thin3d_d3d11.cpp @@ -1060,7 +1060,7 @@ Framebuffer *D3D11DrawContext::CreateFramebuffer(const FramebufferDesc &desc) { descColor.Height = desc.height; descColor.MipLevels = 1; descColor.ArraySize = 1; - descColor.Format = DXGI_FORMAT_B8G8R8A8_UNORM; + descColor.Format = DXGI_FORMAT_R8G8B8A8_UNORM; descColor.SampleDesc.Count = 1; descColor.SampleDesc.Quality = 0; descColor.Usage = D3D11_USAGE_DEFAULT; @@ -1213,8 +1213,15 @@ void D3D11DrawContext::BindBackbufferAsRenderTarget() { } uintptr_t D3D11DrawContext::GetFramebufferAPITexture(Framebuffer *fbo, int channelBit, int attachment) { - // D3D11Framebuffer *fb = (D3D11Framebuffer *)fbo; - return 0; + D3D11Framebuffer *fb = (D3D11Framebuffer *)fbo; + switch (channelBit) { + case FB_COLOR_BIT: return (uintptr_t)fb->colorTex; + case FB_DEPTH_BIT: return (uintptr_t)fb->depthStencilTex; + case FB_COLOR_BIT | FB_VIEW_BIT: return (uintptr_t)fb->colorRTView; + case FB_DEPTH_BIT | FB_VIEW_BIT: return (uintptr_t)fb->depthStencilRTView; + default: + return 0; + } } void D3D11DrawContext::GetFramebufferDimensions(Framebuffer *fbo, int *w, int *h) { From 68ba3070bcffadfcae84550cf0db209b8915a379 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Sat, 18 Feb 2017 00:27:32 +0100 Subject: [PATCH 2/3] D3D11: Add enough debug readback support to support savestate thumbnails --- GPU/Common/FramebufferCommon.h | 1 + GPU/D3D11/FramebufferManagerD3D11.cpp | 66 ++++++++++++++++++++++++++- GPU/D3D11/FramebufferManagerD3D11.h | 4 +- GPU/D3D11/GPU_D3D11.cpp | 4 -- GPU/D3D11/GPU_D3D11.h | 1 - GPU/Directx9/FramebufferDX9.h | 2 +- GPU/Directx9/GPU_DX9.cpp | 4 -- GPU/Directx9/GPU_DX9.h | 1 - GPU/GLES/FramebufferManagerGLES.h | 2 +- GPU/GLES/GPU_GLES.cpp | 4 -- GPU/GLES/GPU_GLES.h | 1 - GPU/Vulkan/FramebufferVulkan.h | 2 +- 12 files changed, 72 insertions(+), 20 deletions(-) diff --git a/GPU/Common/FramebufferCommon.h b/GPU/Common/FramebufferCommon.h index faafae74aa8d..a5c5324b7320 100644 --- a/GPU/Common/FramebufferCommon.h +++ b/GPU/Common/FramebufferCommon.h @@ -269,6 +269,7 @@ class FramebufferManagerCommon { virtual bool GetFramebuffer(u32 fb_address, int fb_stride, GEBufferFormat format, GPUDebugBuffer &buffer, int maxRes) = 0; virtual bool GetDepthbuffer(u32 fb_address, int fb_stride, u32 z_address, int z_stride, GPUDebugBuffer &buffer) = 0; virtual bool GetStencilbuffer(u32 fb_address, int fb_stride, GPUDebugBuffer &buffer) = 0; + virtual bool GetOutputFramebuffer(GPUDebugBuffer &buffer) = 0; protected: virtual void SetViewport2D(int x, int y, int w, int h) = 0; diff --git a/GPU/D3D11/FramebufferManagerD3D11.cpp b/GPU/D3D11/FramebufferManagerD3D11.cpp index 64fa1dd505f9..a1d4fb301a21 100644 --- a/GPU/D3D11/FramebufferManagerD3D11.cpp +++ b/GPU/D3D11/FramebufferManagerD3D11.cpp @@ -120,6 +120,7 @@ FramebufferManagerD3D11::FramebufferManagerD3D11(Draw::DrawContext *draw) } FramebufferManagerD3D11::~FramebufferManagerD3D11() { + packTexture_->Release(); // Drawing cleanup if (quadVertexShader_) quadVertexShader_->Release(); @@ -836,8 +837,71 @@ void FramebufferManagerD3D11::Resized() { resized_ = true; } +// Lots of this code could be shared (like the downsampling). bool FramebufferManagerD3D11::GetFramebuffer(u32 fb_address, int fb_stride, GEBufferFormat format, GPUDebugBuffer &buffer, int maxRes) { - return false; + VirtualFramebuffer *vfb = currentRenderVfb_; + if (!vfb) { + vfb = GetVFBAt(fb_address); + } + + if (!vfb) { + // If there's no vfb and we're drawing there, must be memory? + buffer = GPUDebugBuffer(Memory::GetPointer(fb_address | 0x04000000), fb_stride, 512, format); + return true; + } + + int w = vfb->renderWidth, h = vfb->renderHeight; + Draw::Framebuffer *fboForRead = nullptr; + if (vfb->fbo) { + if (maxRes > 0 && vfb->renderWidth > vfb->width * maxRes) { + w = vfb->width * maxRes; + h = vfb->height * maxRes; + + Draw::Framebuffer *tempFBO = GetTempFBO(w, h); + VirtualFramebuffer tempVfb = *vfb; + tempVfb.fbo = tempFBO; + tempVfb.bufferWidth = vfb->width; + tempVfb.bufferHeight = vfb->height; + tempVfb.renderWidth = w; + tempVfb.renderHeight = h; + BlitFramebuffer(&tempVfb, 0, 0, vfb, 0, 0, vfb->width, vfb->height, 0); + + fboForRead = tempFBO; + } else { + fboForRead = vfb->fbo; + } + } + + buffer.Allocate(w, h, GE_FORMAT_8888, !useBufferedRendering_, true); + + ID3D11Texture2D *packTex; + D3D11_TEXTURE2D_DESC packDesc{}; + packDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + packDesc.BindFlags = 0; + packDesc.Width = w; + packDesc.Height = h; + packDesc.ArraySize = 1; + packDesc.MipLevels = 1; + packDesc.Usage = D3D11_USAGE_STAGING; + packDesc.SampleDesc.Count = 1; + packDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + device_->CreateTexture2D(&packDesc, nullptr, &packTex); + + ID3D11Texture2D *nativeTex = (ID3D11Texture2D *)draw_->GetFramebufferAPITexture(fboForRead, Draw::FB_COLOR_BIT, 0); + context_->CopyResource(packTex, nativeTex); + + D3D11_MAPPED_SUBRESOURCE map; + context_->Map(packTex, 0, D3D11_MAP_READ, 0, &map); + + for (int y = 0; y < h; y++) { + uint8_t *dest = (uint8_t *)buffer.GetData() + y * w * 4; + const uint8_t *src = ((const uint8_t *)map.pData) + map.RowPitch * y; + memcpy(dest, src, 4 * w); + } + + context_->Unmap(packTex, 0); + packTex->Release(); + return true; } bool FramebufferManagerD3D11::GetDepthbuffer(u32 fb_address, int fb_stride, u32 z_address, int z_stride, GPUDebugBuffer &buffer) { diff --git a/GPU/D3D11/FramebufferManagerD3D11.h b/GPU/D3D11/FramebufferManagerD3D11.h index 6ea83585cf0c..5cf4afe8a3ad 100644 --- a/GPU/D3D11/FramebufferManagerD3D11.h +++ b/GPU/D3D11/FramebufferManagerD3D11.h @@ -72,7 +72,7 @@ class FramebufferManagerD3D11 : public FramebufferManagerCommon { bool GetFramebuffer(u32 fb_address, int fb_stride, GEBufferFormat format, GPUDebugBuffer &buffer, int maxRes) override; bool GetDepthbuffer(u32 fb_address, int fb_stride, u32 z_address, int z_stride, GPUDebugBuffer &buffer) override; bool GetStencilbuffer(u32 fb_address, int fb_stride, GPUDebugBuffer &buffer) override; - bool GetOutputFramebuffer(GPUDebugBuffer &buffer); + bool GetOutputFramebuffer(GPUDebugBuffer &buffer) override; virtual void RebindFramebuffer() override; @@ -136,6 +136,8 @@ class FramebufferManagerD3D11 : public FramebufferManagerCommon { ShaderManagerD3D11 *shaderManagerD3D11_; DrawEngineD3D11 *drawEngine_; + // 1:1 Readback texture, 512x512 fixed + // For larger debug readbacks, we create/destroy textures on the fly. ID3D11Texture2D *packTexture_; // Used by post-processing shader diff --git a/GPU/D3D11/GPU_D3D11.cpp b/GPU/D3D11/GPU_D3D11.cpp index 46b54f608825..2a54d64d3276 100644 --- a/GPU/D3D11/GPU_D3D11.cpp +++ b/GPU/D3D11/GPU_D3D11.cpp @@ -995,10 +995,6 @@ bool GPU_D3D11::GetCurrentClut(GPUDebugBuffer &buffer) { return textureCacheD3D11_->GetCurrentClutBuffer(buffer); } -bool GPU_D3D11::GetOutputFramebuffer(GPUDebugBuffer &buffer) { - return framebufferManagerD3D11_->GetOutputFramebuffer(buffer); -} - bool GPU_D3D11::GetCurrentSimpleVertices(int count, std::vector &vertices, std::vector &indices) { return drawEngine_.GetCurrentSimpleVertices(count, vertices, indices); } diff --git a/GPU/D3D11/GPU_D3D11.h b/GPU/D3D11/GPU_D3D11.h index 115d1187936e..f78d78113ab6 100644 --- a/GPU/D3D11/GPU_D3D11.h +++ b/GPU/D3D11/GPU_D3D11.h @@ -66,7 +66,6 @@ class GPU_D3D11 : public GPUCommon { bool GetCurrentTexture(GPUDebugBuffer &buffer, int level) override; bool GetCurrentClut(GPUDebugBuffer &buffer) override; - bool GetOutputFramebuffer(GPUDebugBuffer &buffer) override; bool GetCurrentSimpleVertices(int count, std::vector &vertices, std::vector &indices) override; typedef void (GPU_D3D11::*CmdFunc)(u32 op, u32 diff); diff --git a/GPU/Directx9/FramebufferDX9.h b/GPU/Directx9/FramebufferDX9.h index 35da6ac32ad9..80a560b36125 100644 --- a/GPU/Directx9/FramebufferDX9.h +++ b/GPU/Directx9/FramebufferDX9.h @@ -74,7 +74,7 @@ class FramebufferManagerDX9 : public FramebufferManagerCommon { bool GetFramebuffer(u32 fb_address, int fb_stride, GEBufferFormat format, GPUDebugBuffer &buffer, int maxRes); bool GetDepthbuffer(u32 fb_address, int fb_stride, u32 z_address, int z_stride, GPUDebugBuffer &buffer) override; bool GetStencilbuffer(u32 fb_address, int fb_stride, GPUDebugBuffer &buffer) override; - bool GetOutputFramebuffer(GPUDebugBuffer &buffer); + bool GetOutputFramebuffer(GPUDebugBuffer &buffer) override; virtual void RebindFramebuffer() override; diff --git a/GPU/Directx9/GPU_DX9.cpp b/GPU/Directx9/GPU_DX9.cpp index 62c920c39745..d839a0671c31 100644 --- a/GPU/Directx9/GPU_DX9.cpp +++ b/GPU/Directx9/GPU_DX9.cpp @@ -1069,10 +1069,6 @@ bool GPU_DX9::GetCurrentClut(GPUDebugBuffer &buffer) { return textureCacheDX9_->GetCurrentClutBuffer(buffer); } -bool GPU_DX9::GetOutputFramebuffer(GPUDebugBuffer &buffer) { - return framebufferManagerDX9_->GetOutputFramebuffer(buffer); -} - bool GPU_DX9::GetCurrentSimpleVertices(int count, std::vector &vertices, std::vector &indices) { return drawEngine_.GetCurrentSimpleVertices(count, vertices, indices); } diff --git a/GPU/Directx9/GPU_DX9.h b/GPU/Directx9/GPU_DX9.h index a09831d59834..bc79df79db8b 100644 --- a/GPU/Directx9/GPU_DX9.h +++ b/GPU/Directx9/GPU_DX9.h @@ -67,7 +67,6 @@ class GPU_DX9 : public GPUCommon { bool GetCurrentTexture(GPUDebugBuffer &buffer, int level) override; bool GetCurrentClut(GPUDebugBuffer &buffer) override; - bool GetOutputFramebuffer(GPUDebugBuffer &buffer) override; bool GetCurrentSimpleVertices(int count, std::vector &vertices, std::vector &indices) override; typedef void (GPU_DX9::*CmdFunc)(u32 op, u32 diff); diff --git a/GPU/GLES/FramebufferManagerGLES.h b/GPU/GLES/FramebufferManagerGLES.h index 7675738a5ea9..260141d234e2 100644 --- a/GPU/GLES/FramebufferManagerGLES.h +++ b/GPU/GLES/FramebufferManagerGLES.h @@ -90,7 +90,7 @@ class FramebufferManagerGLES : public FramebufferManagerCommon { bool GetFramebuffer(u32 fb_address, int fb_stride, GEBufferFormat format, GPUDebugBuffer &buffer, int maxRes) override; bool GetDepthbuffer(u32 fb_address, int fb_stride, u32 z_address, int z_stride, GPUDebugBuffer &buffer) override; bool GetStencilbuffer(u32 fb_address, int fb_stride, GPUDebugBuffer &buffer) override; - bool GetOutputFramebuffer(GPUDebugBuffer &buffer); + bool GetOutputFramebuffer(GPUDebugBuffer &buffer) override; virtual void RebindFramebuffer() override; diff --git a/GPU/GLES/GPU_GLES.cpp b/GPU/GLES/GPU_GLES.cpp index 28d7192d1600..fc3454ec7dd2 100644 --- a/GPU/GLES/GPU_GLES.cpp +++ b/GPU/GLES/GPU_GLES.cpp @@ -1271,10 +1271,6 @@ bool GPU_GLES::GetCurrentClut(GPUDebugBuffer &buffer) { return textureCacheGL_->GetCurrentClutBuffer(buffer); } -bool GPU_GLES::GetOutputFramebuffer(GPUDebugBuffer &buffer) { - return framebufferManagerGL_->GetOutputFramebuffer(buffer); -} - bool GPU_GLES::GetCurrentSimpleVertices(int count, std::vector &vertices, std::vector &indices) { return drawEngine_.GetCurrentSimpleVertices(count, vertices, indices); } diff --git a/GPU/GLES/GPU_GLES.h b/GPU/GLES/GPU_GLES.h index 31132ba586f5..debbd688d8df 100644 --- a/GPU/GLES/GPU_GLES.h +++ b/GPU/GLES/GPU_GLES.h @@ -69,7 +69,6 @@ class GPU_GLES : public GPUCommon { bool GetCurrentTexture(GPUDebugBuffer &buffer, int level) override; bool GetCurrentClut(GPUDebugBuffer &buffer) override; - bool GetOutputFramebuffer(GPUDebugBuffer &buffer) override; bool GetCurrentSimpleVertices(int count, std::vector &vertices, std::vector &indices) override; bool DescribeCodePtr(const u8 *ptr, std::string &name) override; diff --git a/GPU/Vulkan/FramebufferVulkan.h b/GPU/Vulkan/FramebufferVulkan.h index 16b6f436306a..b424adccb97c 100644 --- a/GPU/Vulkan/FramebufferVulkan.h +++ b/GPU/Vulkan/FramebufferVulkan.h @@ -103,7 +103,7 @@ class FramebufferManagerVulkan : public FramebufferManagerCommon { bool GetFramebuffer(u32 fb_address, int fb_stride, GEBufferFormat format, GPUDebugBuffer &buffer, int maxRes) override; bool GetDepthbuffer(u32 fb_address, int fb_stride, u32 z_address, int z_stride, GPUDebugBuffer &buffer) override; bool GetStencilbuffer(u32 fb_address, int fb_stride, GPUDebugBuffer &buffer) override; - static bool GetOutputFramebuffer(GPUDebugBuffer &buffer); + bool GetOutputFramebuffer(GPUDebugBuffer &buffer) override; virtual void RebindFramebuffer() override; From e8396b10f9ca833cebed95235b6f309d142d5dac Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Sat, 18 Feb 2017 00:43:02 +0100 Subject: [PATCH 3/3] D3D11: Implement screenshots. --- GPU/D3D11/FramebufferManagerD3D11.cpp | 35 ++++++++++++++++++++++++++- GPU/GPUCommon.cpp | 4 +++ GPU/GPUCommon.h | 1 + ext/native/thin3d/thin3d.h | 2 ++ ext/native/thin3d/thin3d_d3d11.cpp | 13 +++++++--- 5 files changed, 50 insertions(+), 5 deletions(-) diff --git a/GPU/D3D11/FramebufferManagerD3D11.cpp b/GPU/D3D11/FramebufferManagerD3D11.cpp index a1d4fb301a21..1fd58c451119 100644 --- a/GPU/D3D11/FramebufferManagerD3D11.cpp +++ b/GPU/D3D11/FramebufferManagerD3D11.cpp @@ -913,5 +913,38 @@ bool FramebufferManagerD3D11::GetStencilbuffer(u32 fb_address, int fb_stride, GP } bool FramebufferManagerD3D11::GetOutputFramebuffer(GPUDebugBuffer &buffer) { - return false; + ID3D11Texture2D *backbuffer = (ID3D11Texture2D *)draw_->GetNativeObject(Draw::NativeObject::BACKBUFFER_COLOR_TEX); + D3D11_TEXTURE2D_DESC desc; + backbuffer->GetDesc(&desc); + int w = desc.Width; + int h = desc.Height; + buffer.Allocate(w, h, GE_FORMAT_8888, !useBufferedRendering_, true); + + ID3D11Texture2D *packTex; + D3D11_TEXTURE2D_DESC packDesc{}; + packDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + packDesc.BindFlags = 0; + packDesc.Width = w; + packDesc.Height = h; + packDesc.ArraySize = 1; + packDesc.MipLevels = 1; + packDesc.Usage = D3D11_USAGE_STAGING; + packDesc.SampleDesc.Count = 1; + packDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + device_->CreateTexture2D(&packDesc, nullptr, &packTex); + + context_->CopyResource(packTex, backbuffer); + + D3D11_MAPPED_SUBRESOURCE map; + context_->Map(packTex, 0, D3D11_MAP_READ, 0, &map); + + for (int y = 0; y < h; y++) { + uint8_t *dest = (uint8_t *)buffer.GetData() + y * w * 4; + const uint8_t *src = ((const uint8_t *)map.pData) + map.RowPitch * y; + memcpy(dest, src, 4 * w); + } + + context_->Unmap(packTex, 0); + packTex->Release(); + return true; } diff --git a/GPU/GPUCommon.cpp b/GPU/GPUCommon.cpp index d75f0d70cf6c..24c1255f65ae 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -2140,3 +2140,7 @@ bool GPUCommon::GetCurrentStencilbuffer(GPUDebugBuffer &buffer) { return framebufferManager_->GetStencilbuffer(fb_address, fb_stride, buffer); } + +bool GPUCommon::GetOutputFramebuffer(GPUDebugBuffer &buffer) { + return framebufferManager_->GetOutputFramebuffer(buffer); +} diff --git a/GPU/GPUCommon.h b/GPU/GPUCommon.h index ca8bc4dec845..14ddaa63fcc4 100644 --- a/GPU/GPUCommon.h +++ b/GPU/GPUCommon.h @@ -165,6 +165,7 @@ class GPUCommon : public GPUThreadEventQueue, public GPUDebugInterface { bool GetCurrentFramebuffer(GPUDebugBuffer &buffer, GPUDebugFramebufferType type, int maxRes) override; bool GetCurrentDepthbuffer(GPUDebugBuffer &buffer) override; bool GetCurrentStencilbuffer(GPUDebugBuffer &buffer) override; + bool GetOutputFramebuffer(GPUDebugBuffer &buffer) override; std::vector ActiveDisplayLists() override; void ResetListPC(int listID, u32 pc) override; diff --git a/ext/native/thin3d/thin3d.h b/ext/native/thin3d/thin3d.h index 05e07547ac6d..f907984c7b71 100644 --- a/ext/native/thin3d/thin3d.h +++ b/ext/native/thin3d/thin3d.h @@ -312,6 +312,8 @@ enum class NativeObject { DEVICE_EX, BACKBUFFER_COLOR_VIEW, BACKBUFFER_DEPTH_VIEW, + BACKBUFFER_COLOR_TEX, + BACKBUFFER_DEPTH_TEX, }; enum FBColorDepth { diff --git a/ext/native/thin3d/thin3d_d3d11.cpp b/ext/native/thin3d/thin3d_d3d11.cpp index 7047b9ecfa14..2bb6dbb33b90 100644 --- a/ext/native/thin3d/thin3d_d3d11.cpp +++ b/ext/native/thin3d/thin3d_d3d11.cpp @@ -100,6 +100,10 @@ class D3D11DrawContext : public DrawContext { return (uintptr_t)device_; case NativeObject::CONTEXT: return (uintptr_t)context_; + case NativeObject::BACKBUFFER_COLOR_TEX: + return (uintptr_t)bbRenderTargetTex_; + case NativeObject::BACKBUFFER_DEPTH_TEX: + return (uintptr_t)bbDepthStencilTex_; case NativeObject::BACKBUFFER_COLOR_VIEW: return (uintptr_t)bbRenderTargetView_; case NativeObject::BACKBUFFER_DEPTH_VIEW: @@ -119,6 +123,7 @@ class D3D11DrawContext : public DrawContext { ID3D11DeviceContext *context_; IDXGISwapChain *swapChain_ = nullptr; + ID3D11Texture2D *bbRenderTargetTex_ = nullptr; ID3D11RenderTargetView *bbRenderTargetView_ = nullptr; // Strictly speaking we don't need a depth buffer for the backbuffer. ID3D11Texture2D *bbDepthStencilTex_ = nullptr; @@ -237,6 +242,8 @@ void D3D11DrawContext::HandleEvent(Event ev) { curRenderTargetView_ = nullptr; curDepthStencilView_ = nullptr; } + bbRenderTargetTex_->Release(); + bbRenderTargetTex_ = nullptr; bbRenderTargetView_->Release(); bbRenderTargetView_ = nullptr; bbDepthStencilView_->Release(); @@ -251,12 +258,10 @@ void D3D11DrawContext::HandleEvent(Event ev) { GetRes(hWnd_, width, height); // Create a render target view ID3D11Texture2D* pBackBuffer = nullptr; - HRESULT hr = swapChain_->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast(&pBackBuffer)); + HRESULT hr = swapChain_->GetBuffer(0, __uuidof(ID3D11Texture2D), reinterpret_cast(&bbRenderTargetTex_)); if (FAILED(hr)) return; - - hr = device_->CreateRenderTargetView(pBackBuffer, nullptr, &bbRenderTargetView_); - pBackBuffer->Release(); + hr = device_->CreateRenderTargetView(bbRenderTargetTex_, nullptr, &bbRenderTargetView_); if (FAILED(hr)) return;