From 26978ad7e07ea7529c8ac54a042d5e4fbdc0fece Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 13 Sep 2014 22:39:54 -0700 Subject: [PATCH] d3d: Allow blit to self in block transfers/etc. --- GPU/Directx9/FramebufferDX9.cpp | 49 ++++++++++++++++++++++++++++++++- GPU/Directx9/FramebufferDX9.h | 6 ++++ 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/GPU/Directx9/FramebufferDX9.cpp b/GPU/Directx9/FramebufferDX9.cpp index 77e8f3b709..2ef4a9ce94 100644 --- a/GPU/Directx9/FramebufferDX9.cpp +++ b/GPU/Directx9/FramebufferDX9.cpp @@ -130,6 +130,9 @@ namespace DX9 { if (drawPixelsTex_) { drawPixelsTex_->Release(); } + for (auto it = tempFBOs_.begin(), end = tempFBOs_.end(); it != end; ++it) { + fbo_destroy(it->second.fbo); + } for (auto it = offscreenSurfaces_.begin(), end = offscreenSurfaces_.end(); it != end; ++it) { it->second.surface->Release(); } @@ -529,6 +532,25 @@ namespace DX9 { } } + FBO *FramebufferManagerDX9::GetTempFBO(u16 w, u16 h, FBOColorDepth depth) { + u64 key = ((u64)depth << 32) | (w << 16) | h; + auto it = tempFBOs_.find(key); + if (it != tempFBOs_.end()) { + it->second.last_frame_used = gpuStats.numFlips; + return it->second.fbo; + } + + textureCache_->ForgetLastTexture(); + FBO *fbo = fbo_create(w, h, 1, false, depth); + if (!fbo) + return fbo; + fbo_bind_as_render_target(fbo); + ClearBuffer(); + const TempFBO info = {fbo, gpuStats.numFlips}; + tempFBOs_[key] = info; + return fbo; + } + LPDIRECT3DSURFACE9 FramebufferManagerDX9::GetOffscreenSurface(LPDIRECT3DSURFACE9 similarSurface) { D3DSURFACE_DESC desc; similarSurface->GetDesc(&desc); @@ -881,7 +903,17 @@ namespace DX9 { dstRect.right = std::min(dstRect.right, (LONG)desc.Width); dstRect.bottom = std::min(dstRect.bottom, (LONG)desc.Height); - HRESULT hr = fbo_blit_color(src->fbo, &srcRect, dst->fbo, &dstRect, D3DTEXF_POINT); + // Direct3D 9 doesn't support rect -> self. + FBO *srcFBO = src->fbo; + if (src == dst) { + FBO *tempFBO = GetTempFBO(src->renderWidth, src->renderHeight, (FBOColorDepth)src->colorDepth); + HRESULT hr = fbo_blit_color(src->fbo, &srcRect, tempFBO, &srcRect, D3DTEXF_POINT); + if (SUCCEEDED(hr)) { + srcFBO = tempFBO; + } + } + + HRESULT hr = fbo_blit_color(srcFBO, &srcRect, dst->fbo, &dstRect, D3DTEXF_POINT); if (FAILED(hr)) { ERROR_LOG_REPORT(G3D, "fbo_blit_color failed in blit: %08x (%08x -> %08x)", hr, src->fb_address, dst->fb_address); } @@ -1049,6 +1081,16 @@ namespace DX9 { } } + for (auto it = tempFBOs_.begin(); it != tempFBOs_.end(); ) { + int age = frameLastFramebufUsed_ - it->second.last_frame_used; + if (age > FBO_OLD_AGE) { + fbo_destroy(it->second.fbo); + tempFBOs_.erase(it++); + } else { + ++it; + } + } + for (auto it = offscreenSurfaces_.begin(); it != offscreenSurfaces_.end(); ) { int age = frameLastFramebufUsed_ - it->second.last_frame_used; if (age > FBO_OLD_AGE) { @@ -1091,6 +1133,11 @@ namespace DX9 { } bvfbs_.clear(); + for (auto it = tempFBOs_.begin(), end = tempFBOs_.end(); it != end; ++it) { + fbo_destroy(it->second.fbo); + } + tempFBOs_.clear(); + for (auto it = offscreenSurfaces_.begin(), end = offscreenSurfaces_.end(); it != end; ++it) { it->second.surface->Release(); } diff --git a/GPU/Directx9/FramebufferDX9.h b/GPU/Directx9/FramebufferDX9.h index c3c9e29e66..ada72ef752 100644 --- a/GPU/Directx9/FramebufferDX9.h +++ b/GPU/Directx9/FramebufferDX9.h @@ -85,6 +85,7 @@ public: virtual void RebindFramebuffer() override; + FBO *GetTempFBO(u16 w, u16 h, FBOColorDepth depth = FBO_8888); LPDIRECT3DSURFACE9 GetOffscreenSurface(LPDIRECT3DSURFACE9 similarSurface); protected: @@ -130,12 +131,17 @@ private: bool resized_; bool gameUsesSequentialCopies_; + struct TempFBO { + FBO *fbo; + int last_frame_used; + }; struct OffscreenSurface { LPDIRECT3DSURFACE9 surface; int last_frame_used; }; std::vector bvfbs_; // blitting FBOs + std::map tempFBOs_; std::map offscreenSurfaces_; #if 0