diff --git a/GPU/Common/FramebufferCommon.cpp b/GPU/Common/FramebufferCommon.cpp index 868f11818..d243c4430 100644 --- a/GPU/Common/FramebufferCommon.cpp +++ b/GPU/Common/FramebufferCommon.cpp @@ -768,6 +768,16 @@ VirtualFramebuffer *FramebufferManagerCommon::FindDownloadTempBuffer(VirtualFram nvfb->drawnWidth = vfb->drawnWidth; nvfb->drawnHeight = vfb->drawnHeight; nvfb->drawnFormat = vfb->format; + nvfb->colorDepth = vfb->colorDepth; + + if (!CreateDownloadTempBuffer(nvfb)) { + delete nvfb; + return nullptr; + } + + bvfbs_.push_back(nvfb); + } else { + UpdateDownloadTempBuffer(nvfb); } nvfb->usageFlags |= FB_USAGE_RENDERTARGET; diff --git a/GPU/Common/FramebufferCommon.h b/GPU/Common/FramebufferCommon.h index 28f9f0f82..6e34906b2 100644 --- a/GPU/Common/FramebufferCommon.h +++ b/GPU/Common/FramebufferCommon.h @@ -245,6 +245,8 @@ protected: bool ShouldDownloadFramebuffer(const VirtualFramebuffer *vfb) const; void FindTransferFramebuffers(VirtualFramebuffer *&dstBuffer, VirtualFramebuffer *&srcBuffer, u32 dstBasePtr, int dstStride, int &dstX, int &dstY, u32 srcBasePtr, int srcStride, int &srcX, int &srcY, int &srcWidth, int &srcHeight, int &dstWidth, int &dstHeight, int bpp) const; VirtualFramebuffer *FindDownloadTempBuffer(VirtualFramebuffer *vfb); + virtual bool CreateDownloadTempBuffer(VirtualFramebuffer *nvfb) = 0; + virtual void UpdateDownloadTempBuffer(VirtualFramebuffer *nvfb) = 0; void OptimizeDownloadRange(VirtualFramebuffer *vfb, int &x, int &y, int &w, int &h); void UpdateFramebufUsage(VirtualFramebuffer *vfb); diff --git a/GPU/Directx9/FramebufferDX9.cpp b/GPU/Directx9/FramebufferDX9.cpp index 121c9a2db..b3741bbf3 100644 --- a/GPU/Directx9/FramebufferDX9.cpp +++ b/GPU/Directx9/FramebufferDX9.cpp @@ -849,34 +849,34 @@ namespace DX9 { if (vfb) { // We'll pseudo-blit framebuffers here to get a resized version of vfb. VirtualFramebuffer *nvfb = FindDownloadTempBuffer(vfb); - - // Create a new fbo if none was found for the size - if (!nvfb->fbo_dx9) { - nvfb->colorDepth = FBO_8888; - - textureCache_->ForgetLastTexture(); - nvfb->fbo_dx9 = fbo_create(nvfb->width, nvfb->height, 1, true, (FBOColorDepth)nvfb->colorDepth); - if (!(nvfb->fbo_dx9)) { - ERROR_LOG(SCEGE, "Error creating FBO! %i x %i", nvfb->renderWidth, nvfb->renderHeight); - delete nvfb; - return; - } - - bvfbs_.push_back(nvfb); - fbo_bind_as_render_target(nvfb->fbo_dx9); - ClearBuffer(); - } else { - textureCache_->ForgetLastTexture(); - } - OptimizeDownloadRange(vfb, x, y, w, h); BlitFramebuffer(nvfb, x, y, vfb, x, y, w, h, 0); PackFramebufferDirectx9_(nvfb, x, y, w, h); + + textureCache_->ForgetLastTexture(); RebindFramebuffer(); } } + bool FramebufferManagerDX9::CreateDownloadTempBuffer(VirtualFramebuffer *nvfb) { + nvfb->colorDepth = FBO_8888; + + nvfb->fbo_dx9 = fbo_create(nvfb->width, nvfb->height, 1, true, (FBOColorDepth)nvfb->colorDepth); + if (!(nvfb->fbo_dx9)) { + ERROR_LOG(SCEGE, "Error creating FBO! %i x %i", nvfb->renderWidth, nvfb->renderHeight); + return false; + } + + fbo_bind_as_render_target(nvfb->fbo_dx9); + ClearBuffer(); + return true; + } + + void FramebufferManagerDX9::UpdateDownloadTempBuffer(VirtualFramebuffer *nvfb) { + // Nothing to do here. + } + 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. diff --git a/GPU/Directx9/FramebufferDX9.h b/GPU/Directx9/FramebufferDX9.h index 4b396988a..26612bd15 100644 --- a/GPU/Directx9/FramebufferDX9.h +++ b/GPU/Directx9/FramebufferDX9.h @@ -105,6 +105,8 @@ protected: virtual void NotifyRenderFramebufferCreated(VirtualFramebuffer *vfb) override; virtual void NotifyRenderFramebufferSwitched(VirtualFramebuffer *prevVfb, VirtualFramebuffer *vfb, bool isClearingDepth) override; virtual void NotifyRenderFramebufferUpdated(VirtualFramebuffer *vfb, bool vfbFormatChanged) override; + virtual bool CreateDownloadTempBuffer(VirtualFramebuffer *nvfb) override; + virtual void UpdateDownloadTempBuffer(VirtualFramebuffer *nvfb) override; private: void CompileDraw2DProgram(); diff --git a/GPU/GLES/Framebuffer.cpp b/GPU/GLES/Framebuffer.cpp index 8f0f5c3cc..93da39c3f 100644 --- a/GPU/GLES/Framebuffer.cpp +++ b/GPU/GLES/Framebuffer.cpp @@ -1217,59 +1217,6 @@ void FramebufferManager::ReadFramebufferToMemory(VirtualFramebuffer *vfb, bool s if (vfb) { // We'll pseudo-blit framebuffers here to get a resized version of vfb. VirtualFramebuffer *nvfb = FindDownloadTempBuffer(vfb); - - // Create a new fbo if none was found for the size - if (!nvfb->fbo) { - // When updating VRAM, it need to be exact format. - switch (vfb->format) { - case GE_FORMAT_4444: - nvfb->colorDepth = FBO_4444; - break; - case GE_FORMAT_5551: - nvfb->colorDepth = FBO_5551; - break; - case GE_FORMAT_565: - nvfb->colorDepth = FBO_565; - break; - case GE_FORMAT_8888: - default: - nvfb->colorDepth = FBO_8888; - break; - } - if (gstate_c.Supports(GPU_PREFER_CPU_DOWNLOAD)) { - nvfb->colorDepth = vfb->colorDepth; - } - - textureCache_->ForgetLastTexture(); - nvfb->fbo = fbo_create(nvfb->width, nvfb->height, 1, false, (FBOColorDepth)nvfb->colorDepth); - if (!(nvfb->fbo)) { - ERROR_LOG(SCEGE, "Error creating FBO! %i x %i", nvfb->renderWidth, nvfb->renderHeight); - delete nvfb; - return; - } - - bvfbs_.push_back(nvfb); - fbo_bind_as_render_target(nvfb->fbo); - ClearBuffer(); - glDisable(GL_DITHER); - } else { - textureCache_->ForgetLastTexture(); - - if (gl_extensions.IsGLES) { - if (nvfb->fbo) { - fbo_bind_as_render_target(nvfb->fbo); - } - - // Some tiled mobile GPUs benefit IMMENSELY from clearing an FBO before rendering - // to it. This broke stuff before, so now it only clears on the first use of an - // FBO in a frame. This means that some games won't be able to avoid the on-some-GPUs - // performance-crushing framebuffer reloads from RAM, but we'll have to live with that. - if (nvfb->last_frame_render != gpuStats.numFlips) { - ClearBuffer(); - } - } - } - OptimizeDownloadRange(vfb, x, y, w, h); BlitFramebuffer(nvfb, x, y, vfb, x, y, w, h, 0); @@ -1289,10 +1236,59 @@ void FramebufferManager::ReadFramebufferToMemory(VirtualFramebuffer *vfb, bool s } } + textureCache_->ForgetLastTexture(); RebindFramebuffer(); } } +bool FramebufferManager::CreateDownloadTempBuffer(VirtualFramebuffer *nvfb) { + // When updating VRAM, it need to be exact format. + if (!gstate_c.Supports(GPU_PREFER_CPU_DOWNLOAD)) { + switch (nvfb->format) { + case GE_FORMAT_4444: + nvfb->colorDepth = FBO_4444; + break; + case GE_FORMAT_5551: + nvfb->colorDepth = FBO_5551; + break; + case GE_FORMAT_565: + nvfb->colorDepth = FBO_565; + break; + case GE_FORMAT_8888: + default: + nvfb->colorDepth = FBO_8888; + break; + } + } + + nvfb->fbo = fbo_create(nvfb->width, nvfb->height, 1, false, (FBOColorDepth)nvfb->colorDepth); + if (!(nvfb->fbo)) { + ERROR_LOG(SCEGE, "Error creating FBO! %i x %i", nvfb->renderWidth, nvfb->renderHeight); + return false; + } + + fbo_bind_as_render_target(nvfb->fbo); + ClearBuffer(); + glDisable(GL_DITHER); + return true; +} + +void FramebufferManager::UpdateDownloadTempBuffer(VirtualFramebuffer *nvfb) { + if (gl_extensions.IsGLES) { + if (nvfb->fbo) { + fbo_bind_as_render_target(nvfb->fbo); + } + + // Some tiled mobile GPUs benefit IMMENSELY from clearing an FBO before rendering + // to it. This broke stuff before, so now it only clears on the first use of an + // FBO in a frame. This means that some games won't be able to avoid the on-some-GPUs + // performance-crushing framebuffer reloads from RAM, but we'll have to live with that. + if (nvfb->last_frame_render != gpuStats.numFlips) { + ClearBuffer(); + } + } +} + void FramebufferManager::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. diff --git a/GPU/GLES/Framebuffer.h b/GPU/GLES/Framebuffer.h index 94f7fc23b..bd494d11b 100644 --- a/GPU/GLES/Framebuffer.h +++ b/GPU/GLES/Framebuffer.h @@ -135,6 +135,8 @@ protected: virtual void NotifyRenderFramebufferCreated(VirtualFramebuffer *vfb) override; virtual void NotifyRenderFramebufferSwitched(VirtualFramebuffer *prevVfb, VirtualFramebuffer *vfb, bool isClearingDepth) override; virtual void NotifyRenderFramebufferUpdated(VirtualFramebuffer *vfb, bool vfbFormatChanged) override; + virtual bool CreateDownloadTempBuffer(VirtualFramebuffer *nvfb) override; + virtual void UpdateDownloadTempBuffer(VirtualFramebuffer *nvfb) override; private: void UpdatePostShaderUniforms(int bufferWidth, int bufferHeight, int renderWidth, int renderHeight);