diff --git a/Common/GPU/D3D11/thin3d_d3d11.cpp b/Common/GPU/D3D11/thin3d_d3d11.cpp index 3b9837fbe1..0b10980c0f 100644 --- a/Common/GPU/D3D11/thin3d_d3d11.cpp +++ b/Common/GPU/D3D11/thin3d_d3d11.cpp @@ -1623,13 +1623,25 @@ bool D3D11DrawContext::CopyFramebufferToMemorySync(Framebuffer *src, int channel } break; case FB_STENCIL_BIT: - _assert_(destFormat == DataFormat::S8); - for (int y = 0; y < bh; y++) { - uint8_t *destStencil = (uint8_t *)pixels + y * pixelStride; - const uint32_t *src = (const uint32_t *)(srcWithOffset + map.RowPitch * y); - for (int x = 0; x < bw; x++) { - destStencil[x] = src[x] >> 24; + if (srcFormat == destFormat) { + // Can just memcpy when it matches no matter the format! + uint8_t *dst = (uint8_t *)pixels; + const uint8_t *src = (const uint8_t *)srcWithOffset; + for (int y = 0; y < bh; ++y) { + memcpy(dst, src, bw * DataFormatSizeInBytes(srcFormat)); + dst += pixelStride * DataFormatSizeInBytes(srcFormat); + src += map.RowPitch; } + } else if (destFormat == DataFormat::S8) { + for (int y = 0; y < bh; y++) { + uint8_t *destStencil = (uint8_t *)pixels + y * pixelStride; + const uint32_t *src = (const uint32_t *)(srcWithOffset + map.RowPitch * y); + for (int x = 0; x < bw; x++) { + destStencil[x] = src[x] >> 24; + } + } + } else { + _assert_(false); } break; } diff --git a/Common/GPU/D3D9/thin3d_d3d9.cpp b/Common/GPU/D3D9/thin3d_d3d9.cpp index 04bec49896..11e9f08012 100644 --- a/Common/GPU/D3D9/thin3d_d3d9.cpp +++ b/Common/GPU/D3D9/thin3d_d3d9.cpp @@ -528,6 +528,7 @@ public: // Not implemented } bool BlitFramebuffer(Framebuffer *src, int srcX1, int srcY1, int srcX2, int srcY2, Framebuffer *dst, int dstX1, int dstY1, int dstX2, int dstY2, int channelBits, FBBlitFilter filter, const char *tag) override; + bool CopyFramebufferToMemorySync(Framebuffer *src, int channelBits, int x, int y, int w, int h, Draw::DataFormat format, void *pixels, int pixelStride, const char *tag) override; // These functions should be self explanatory. void BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp, const char *tag) override; @@ -1400,6 +1401,108 @@ bool D3D9Context::BlitFramebuffer(Framebuffer *srcfb, int srcX1, int srcY1, int return SUCCEEDED(device_->StretchRect(srcSurf, &srcRect, dstSurf, &dstRect, (filter == FB_BLIT_LINEAR && channelBits == FB_COLOR_BIT) ? D3DTEXF_LINEAR : D3DTEXF_POINT)); } +bool D3D9Context::CopyFramebufferToMemorySync(Framebuffer *src, int channelBits, int bx, int by, int bw, int bh, Draw::DataFormat destFormat, void *pixels, int pixelStride, const char *tag) { + D3D9Framebuffer *fb = (D3D9Framebuffer *)src; + + if (fb) { + if (bx + bw > fb->Width()) { + bw -= (bx + bw) - fb->Width(); + } + if (by + bh > fb->Height()) { + bh -= (by + bh) - fb->Height(); + } + } + + if (bh <= 0 || bw <= 0) + return true; + + DataFormat srcFormat = Draw::DataFormat::R8G8B8A8_UNORM; + if (channelBits != FB_COLOR_BIT) { + srcFormat = Draw::DataFormat::D24_S8; + if (!supportsINTZ) + return false; + } + + D3DSURFACE_DESC desc; + D3DLOCKED_RECT locked; + RECT rect = { (LONG)bx, (LONG)by, (LONG)bw, (LONG)bh }; + + LPDIRECT3DSURFACE9 offscreen = nullptr; + HRESULT hr = E_UNEXPECTED; + if (channelBits == FB_COLOR_BIT) { + fb->tex->GetLevelDesc(0, &desc); + + hr = device_->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &offscreen, nullptr); + if (SUCCEEDED(hr)) { + hr = device_->GetRenderTargetData(fb->surf, offscreen); + if (SUCCEEDED(hr)) { + hr = offscreen->LockRect(&locked, &rect, D3DLOCK_READONLY); + } + } + } else { + fb->depthstenciltex->GetLevelDesc(0, &desc); + hr = fb->depthstenciltex->LockRect(0, &locked, &rect, D3DLOCK_READONLY); + } + + if (SUCCEEDED(hr)) { + switch (channelBits) { + case FB_COLOR_BIT: + // Pixel size always 4 here because we always request BGRA8888. + ConvertFromBGRA8888((uint8_t *)pixels, (const uint8_t *)locked.pBits, pixelStride, locked.Pitch / sizeof(uint32_t), bw, bh, destFormat); + break; + case FB_DEPTH_BIT: + if (srcFormat == destFormat) { + // Can just memcpy when it matches no matter the format! + uint8_t *dst = (uint8_t *)pixels; + const uint8_t *src = (const uint8_t *)locked.pBits; + for (int y = 0; y < bh; ++y) { + memcpy(dst, src, bw * DataFormatSizeInBytes(srcFormat)); + dst += pixelStride * DataFormatSizeInBytes(srcFormat); + src += locked.Pitch; + } + } else if (destFormat == DataFormat::D32F) { + ConvertToD32F((uint8_t *)pixels, (const uint8_t *)locked.pBits, pixelStride, locked.Pitch / sizeof(uint32_t), bw, bh, srcFormat); + } else if (destFormat == DataFormat::D16) { + ConvertToD16((uint8_t *)pixels, (const uint8_t *)locked.pBits, pixelStride, locked.Pitch / sizeof(uint32_t), bw, bh, srcFormat); + } else { + _assert_(false); + } + break; + case FB_STENCIL_BIT: + if (srcFormat == destFormat) { + uint8_t *dst = (uint8_t *)pixels; + const uint8_t *src = (const uint8_t *)locked.pBits; + for (int y = 0; y < bh; ++y) { + memcpy(dst, src, bw * DataFormatSizeInBytes(srcFormat)); + dst += pixelStride * DataFormatSizeInBytes(srcFormat); + src += locked.Pitch; + } + } else if (destFormat == DataFormat::S8) { + for (int y = 0; y < bh; y++) { + uint8_t *destStencil = (uint8_t *)pixels + y * pixelStride; + const uint32_t *src = (const uint32_t *)((const uint8_t *)locked.pBits + locked.Pitch * y); + for (int x = 0; x < bw; x++) { + destStencil[x] = src[x] >> 24; + } + } + } else { + _assert_(false); + } + break; + } + } + + if (channelBits != FB_COLOR_BIT) { + fb->depthstenciltex->UnlockRect(0); + } + if (offscreen) { + offscreen->UnlockRect(); + offscreen->Release(); + } + + return SUCCEEDED(hr); +} + void D3D9Context::HandleEvent(Event ev, int width, int height, void *param1, void *param2) { switch (ev) { case Event::LOST_BACKBUFFER: diff --git a/GPU/Directx9/FramebufferManagerDX9.cpp b/GPU/Directx9/FramebufferManagerDX9.cpp index ef3af4c41c..421b01cbd2 100644 --- a/GPU/Directx9/FramebufferManagerDX9.cpp +++ b/GPU/Directx9/FramebufferManagerDX9.cpp @@ -243,158 +243,3 @@ } offscreenSurfaces_.clear(); } - - 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); - } - - if (!vfb) { - if (!Memory::IsValidAddress(fb_address)) - return false; - // If there's no vfb and we're drawing there, must be memory? - buffer = GPUDebugBuffer(Memory::GetPointerWrite(fb_address), fb_stride, 512, fb_format); - return true; - } - LPDIRECT3DSURFACE9 renderTarget = vfb->fbo ? (LPDIRECT3DSURFACE9)draw_->GetFramebufferAPITexture(vfb->fbo, Draw::FB_COLOR_BIT | Draw::FB_SURFACE_BIT, 0) : nullptr; - bool success = false; - if (renderTarget) { - Draw::Framebuffer *tempFBO = nullptr; - int w = vfb->renderWidth, h = vfb->renderHeight; - - if (maxRes > 0 && vfb->renderWidth > vfb->width * maxRes) { - // Let's resize. We must stretch to a render target first. - w = vfb->width * maxRes; - h = vfb->height * maxRes; - tempFBO = draw_->CreateFramebuffer({ w, h, 1, 1, false }); - if (draw_->BlitFramebuffer(vfb->fbo, 0, 0, vfb->renderWidth, vfb->renderHeight, tempFBO, 0, 0, w, h, Draw::FB_COLOR_BIT, g_Config.iBufFilter == SCALE_LINEAR ? Draw::FB_BLIT_LINEAR : Draw::FB_BLIT_NEAREST, "GetFramebuffer")) { - renderTarget = (LPDIRECT3DSURFACE9)draw_->GetFramebufferAPITexture(tempFBO, Draw::FB_COLOR_BIT | Draw::FB_SURFACE_BIT, 0); - } - } - - LPDIRECT3DSURFACE9 offscreen = GetOffscreenSurface(renderTarget, vfb); - if (offscreen) { - success = GetRenderTargetFramebuffer(renderTarget, offscreen, w, h, buffer); - } - } - - return success; - } - - bool FramebufferManagerDX9::GetOutputFramebuffer(GPUDebugBuffer &buffer) { - LPDIRECT3DSURFACE9 renderTarget = nullptr; - HRESULT hr = device_->GetRenderTarget(0, &renderTarget); - bool success = false; - if (renderTarget && SUCCEEDED(hr)) { - D3DSURFACE_DESC desc; - renderTarget->GetDesc(&desc); - - LPDIRECT3DSURFACE9 offscreen = nullptr; - HRESULT hr = device_->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &offscreen, NULL); - if (offscreen && SUCCEEDED(hr)) { - success = GetRenderTargetFramebuffer(renderTarget, offscreen, PSP_CoreParameter().pixelWidth, PSP_CoreParameter().pixelHeight, buffer); - offscreen->Release(); - } - renderTarget->Release(); - } - return success; - } - - bool FramebufferManagerDX9::GetRenderTargetFramebuffer(LPDIRECT3DSURFACE9 renderTarget, LPDIRECT3DSURFACE9 offscreen, int w, int h, GPUDebugBuffer &buffer) { - D3DSURFACE_DESC desc; - renderTarget->GetDesc(&desc); - - bool success = false; - HRESULT hr = device_->GetRenderTargetData(renderTarget, offscreen); - if (SUCCEEDED(hr)) { - D3DLOCKED_RECT locked; - RECT rect = {0, 0, w, h}; - hr = offscreen->LockRect(&locked, &rect, D3DLOCK_READONLY); - if (SUCCEEDED(hr)) { - // TODO: Handle the other formats? We don't currently create them, I think. - buffer.Allocate(locked.Pitch / 4, desc.Height, GPU_DBG_FORMAT_8888_BGRA, false); - memcpy(buffer.GetData(), locked.pBits, locked.Pitch * desc.Height); - offscreen->UnlockRect(); - success = true; - } - } - - return success; - } - - 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); - } - - if (!vfb) { - // If there's no vfb and we're drawing there, must be memory? - buffer = GPUDebugBuffer(Memory::GetPointerWrite(z_address), z_stride, 512, GPU_DBG_FORMAT_16BIT); - return true; - } - - bool success = false; - 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)) { - 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); - memcpy(buffer.GetData(), locked.pBits, locked.Pitch * desc.Height); - success = true; - tex->UnlockRect(0); - } - } - - return success; - } - - bool FramebufferManagerDX9::GetStencilbuffer(u32 fb_address, int fb_stride, GPUDebugBuffer &buffer) { - VirtualFramebuffer *vfb = currentRenderVfb_; - if (!vfb) { - vfb = GetVFBAt(fb_address); - } - - if (!vfb) { - if (!Memory::IsValidAddress(fb_address)) - return false; - // If there's no vfb and we're drawing there, must be memory? - // TODO: Actually get the stencil. - buffer = GPUDebugBuffer(Memory::GetPointerWrite(fb_address), fb_stride, 512, GPU_DBG_FORMAT_8888); - return true; - } - - bool success = false; - 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)) { - GPUDebugBufferFormat fmt = GPU_DBG_FORMAT_24X_8BIT; - int pixelSize = 4; - - buffer.Allocate(locked.Pitch / pixelSize, desc.Height, fmt, false); - memcpy(buffer.GetData(), locked.pBits, locked.Pitch * desc.Height); - success = true; - tex->UnlockRect(0); - } - } - - return success; - } diff --git a/GPU/Directx9/FramebufferManagerDX9.h b/GPU/Directx9/FramebufferManagerDX9.h index cb0a8ff37f..5a79b25e1f 100644 --- a/GPU/Directx9/FramebufferManagerDX9.h +++ b/GPU/Directx9/FramebufferManagerDX9.h @@ -39,11 +39,6 @@ public: void DestroyAllFBOs() override; - 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) override; - LPDIRECT3DSURFACE9 GetOffscreenSurface(LPDIRECT3DSURFACE9 similarSurface, VirtualFramebuffer *vfb); LPDIRECT3DSURFACE9 GetOffscreenSurface(D3DFORMAT fmt, u32 w, u32 h); @@ -52,7 +47,6 @@ protected: 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_;