From 27d5c5a2d4c7e0e101a8ed4d693ea07a4eb7bfc4 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Tue, 7 Feb 2017 00:29:02 +0100 Subject: [PATCH] Unify NotifyRenderFramebufferSwitched --- GPU/Common/FramebufferCommon.cpp | 68 +++++++++++++++++++++++++++++ GPU/Common/FramebufferCommon.h | 3 +- GPU/Directx9/FramebufferDX9.cpp | 57 ------------------------ GPU/Directx9/FramebufferDX9.h | 3 +- GPU/GLES/FramebufferManagerGLES.cpp | 63 -------------------------- GPU/GLES/FramebufferManagerGLES.h | 3 +- GPU/Vulkan/FramebufferVulkan.cpp | 49 --------------------- GPU/Vulkan/FramebufferVulkan.h | 4 +- 8 files changed, 73 insertions(+), 177 deletions(-) diff --git a/GPU/Common/FramebufferCommon.cpp b/GPU/Common/FramebufferCommon.cpp index e1dbb95c82..27d80e2d57 100644 --- a/GPU/Common/FramebufferCommon.cpp +++ b/GPU/Common/FramebufferCommon.cpp @@ -19,6 +19,7 @@ #include #include "ext/native/thin3d/thin3d.h" +#include "gfx_es2/gpu_features.h" #include "i18n/i18n.h" #include "Common/Common.h" @@ -557,6 +558,73 @@ void FramebufferManagerCommon::NotifyRenderFramebufferUpdated(VirtualFramebuffer } } +void FramebufferManagerCommon::NotifyRenderFramebufferSwitched(VirtualFramebuffer *prevVfb, VirtualFramebuffer *vfb, bool isClearingDepth) { + if (ShouldDownloadFramebuffer(vfb) && !vfb->memoryUpdated) { + ReadFramebufferToMemory(vfb, true, 0, 0, vfb->width, vfb->height); + } else { + DownloadFramebufferOnSwitch(prevVfb); + } + textureCache_->ForgetLastTexture(); + + if (useBufferedRendering_) { + if (vfb->fbo) { + draw_->BindFramebufferAsRenderTarget(vfb->fbo); + } else { + // wtf? This should only happen very briefly when toggling bBufferedRendering + draw_->BindBackbufferAsRenderTarget(); + } + } else { + if (vfb->fbo) { + // wtf? This should only happen very briefly when toggling bBufferedRendering + textureCache_->NotifyFramebuffer(vfb->fb_address, vfb, NOTIFY_FB_DESTROYED); + delete vfb->fbo; + vfb->fbo = nullptr; + } + draw_->BindBackbufferAsRenderTarget(); + + // Let's ignore rendering to targets that have not (yet) been displayed. + if (vfb->usageFlags & FB_USAGE_DISPLAYED_FRAMEBUFFER) { + gstate_c.skipDrawReason &= ~SKIPDRAW_NON_DISPLAYED_FB; + } else { + gstate_c.skipDrawReason |= SKIPDRAW_NON_DISPLAYED_FB; + } + } + textureCache_->NotifyFramebuffer(vfb->fb_address, vfb, NOTIFY_FB_UPDATED); + + if (gl_extensions.IsGLES) { + // 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 (vfb->last_frame_render != gpuStats.numFlips) { + ClearBuffer(); + } + } + + // Copy depth pixel value from the read framebuffer to the draw framebuffer + if (prevVfb && !g_Config.bDisableSlowFramebufEffects) { + if (!prevVfb->fbo || !vfb->fbo || !useBufferedRendering_ || !prevVfb->depthUpdated || isClearingDepth) { + // If depth wasn't updated, then we're at least "two degrees" away from the data. + // This is an optimization: it probably doesn't need to be copied in this case. + } else { + BlitFramebufferDepth(prevVfb, vfb); + } + } + if (vfb->drawnFormat != vfb->format) { + // TODO: Might ultimately combine this with the resize step in DoSetRenderFrameBuffer(). + ReformatFramebufferFrom(vfb, vfb->drawnFormat); + } + + // ugly... + if (gstate_c.curRTWidth != vfb->width || gstate_c.curRTHeight != vfb->height) { + gstate_c.Dirty(DIRTY_PROJTHROUGHMATRIX); + } + if (gstate_c.curRTRenderWidth != vfb->renderWidth || gstate_c.curRTRenderHeight != vfb->renderHeight) { + gstate_c.Dirty(DIRTY_PROJMATRIX); + gstate_c.Dirty(DIRTY_PROJTHROUGHMATRIX); + } +} + void FramebufferManagerCommon::NotifyVideoUpload(u32 addr, int size, int width, GEBufferFormat fmt) { // Note: UpdateFromMemory() is still called later. // This is a special case where we have extra information prior to the invalidation. diff --git a/GPU/Common/FramebufferCommon.h b/GPU/Common/FramebufferCommon.h index af377a82e3..14d892d7b7 100644 --- a/GPU/Common/FramebufferCommon.h +++ b/GPU/Common/FramebufferCommon.h @@ -273,10 +273,11 @@ protected: void NotifyRenderFramebufferCreated(VirtualFramebuffer *vfb); void NotifyRenderFramebufferUpdated(VirtualFramebuffer *vfb, bool vfbFormatChanged); + void NotifyRenderFramebufferSwitched(VirtualFramebuffer *prevVfb, VirtualFramebuffer *vfb, bool isClearingDepth); virtual void ResizeFramebufFBO(VirtualFramebuffer *vfb, u16 w, u16 h, bool force = false, bool skipCopy = false) = 0; - virtual void NotifyRenderFramebufferSwitched(VirtualFramebuffer *prevVfb, VirtualFramebuffer *vfb, bool isClearingDepth) = 0; virtual void ReformatFramebufferFrom(VirtualFramebuffer *vfb, GEBufferFormat old) = 0; + virtual void BlitFramebufferDepth(VirtualFramebuffer *src, VirtualFramebuffer *dst) = 0; void ShowScreenResolution(); diff --git a/GPU/Directx9/FramebufferDX9.cpp b/GPU/Directx9/FramebufferDX9.cpp index 77eecdd914..a546c3638f 100644 --- a/GPU/Directx9/FramebufferDX9.cpp +++ b/GPU/Directx9/FramebufferDX9.cpp @@ -433,63 +433,6 @@ static void DXSetViewport(float x, float y, float w, float h, float minZ, float } } - void FramebufferManagerDX9::NotifyRenderFramebufferSwitched(VirtualFramebuffer *prevVfb, VirtualFramebuffer *vfb, bool isClearingDepth) { - if (ShouldDownloadFramebuffer(vfb) && !vfb->memoryUpdated) { - ReadFramebufferToMemory(vfb, true, 0, 0, vfb->width, vfb->height); - } else { - DownloadFramebufferOnSwitch(prevVfb); - } - textureCacheDX9_->ForgetLastTexture(); - - if (useBufferedRendering_) { - if (vfb->fbo) { - draw_->BindFramebufferAsRenderTarget(vfb->fbo); - } else { - // wtf? This should only happen very briefly when toggling bBufferedRendering - draw_->BindBackbufferAsRenderTarget(); - } - } else { - if (vfb->fbo) { - // wtf? This should only happen very briefly when toggling bBufferedRendering - textureCacheDX9_->NotifyFramebuffer(vfb->fb_address, vfb, NOTIFY_FB_DESTROYED); - delete vfb->fbo; - vfb->fbo = nullptr; - } - draw_->BindBackbufferAsRenderTarget(); - - // Let's ignore rendering to targets that have not (yet) been displayed. - if (vfb->usageFlags & FB_USAGE_DISPLAYED_FRAMEBUFFER) { - gstate_c.skipDrawReason &= ~SKIPDRAW_NON_DISPLAYED_FB; - } else { - gstate_c.skipDrawReason |= SKIPDRAW_NON_DISPLAYED_FB; - } - } - textureCacheDX9_->NotifyFramebuffer(vfb->fb_address, vfb, NOTIFY_FB_UPDATED); - - // Copy depth pixel value from the read framebuffer to the draw framebuffer - if (prevVfb && !g_Config.bDisableSlowFramebufEffects) { - if (!prevVfb->fbo || !vfb->fbo || !useBufferedRendering_ || !prevVfb->depthUpdated || isClearingDepth) { - // If depth wasn't updated, then we're at least "two degrees" away from the data. - // This is an optimization: it probably doesn't need to be copied in this case. - } else { - BlitFramebufferDepth(prevVfb, vfb); - } - } - if (vfb->drawnFormat != vfb->format) { - // TODO: Might ultimately combine this with the resize step in DoSetRenderFrameBuffer(). - ReformatFramebufferFrom(vfb, vfb->drawnFormat); - } - - // ugly... - if (gstate_c.curRTWidth != vfb->width || gstate_c.curRTHeight != vfb->height) { - gstate_c.Dirty(DIRTY_PROJTHROUGHMATRIX); - } - if (gstate_c.curRTRenderWidth != vfb->renderWidth || gstate_c.curRTRenderHeight != vfb->renderHeight) { - gstate_c.Dirty(DIRTY_PROJMATRIX); - gstate_c.Dirty(DIRTY_PROJTHROUGHMATRIX); - } - } - void FramebufferManagerDX9::ReformatFramebufferFrom(VirtualFramebuffer *vfb, GEBufferFormat old) { if (!useBufferedRendering_ || !vfb->fbo) { return; diff --git a/GPU/Directx9/FramebufferDX9.h b/GPU/Directx9/FramebufferDX9.h index 29f911f5a8..0497439299 100644 --- a/GPU/Directx9/FramebufferDX9.h +++ b/GPU/Directx9/FramebufferDX9.h @@ -66,7 +66,7 @@ public: void CopyDisplayToOutput(); void ReformatFramebufferFrom(VirtualFramebuffer *vfb, GEBufferFormat old) override; - void BlitFramebufferDepth(VirtualFramebuffer *src, VirtualFramebuffer *dst); + void BlitFramebufferDepth(VirtualFramebuffer *src, VirtualFramebuffer *dst) override; void BindFramebufferColor(int stage, VirtualFramebuffer *framebuffer, int flags); @@ -98,7 +98,6 @@ protected: // Used by ReadFramebufferToMemory and later framebuffer block copies void BlitFramebuffer(VirtualFramebuffer *dst, int dstX, int dstY, VirtualFramebuffer *src, int srcX, int srcY, int w, int h, int bpp) override; - void NotifyRenderFramebufferSwitched(VirtualFramebuffer *prevVfb, VirtualFramebuffer *vfb, bool isClearingDepth) override; bool CreateDownloadTempBuffer(VirtualFramebuffer *nvfb) override; void UpdateDownloadTempBuffer(VirtualFramebuffer *nvfb) override; diff --git a/GPU/GLES/FramebufferManagerGLES.cpp b/GPU/GLES/FramebufferManagerGLES.cpp index 5ffca54c89..34c2e2416f 100644 --- a/GPU/GLES/FramebufferManagerGLES.cpp +++ b/GPU/GLES/FramebufferManagerGLES.cpp @@ -583,69 +583,6 @@ void FramebufferManagerGLES::ResizeFramebufFBO(VirtualFramebuffer *vfb, u16 w, u } } -void FramebufferManagerGLES::NotifyRenderFramebufferSwitched(VirtualFramebuffer *prevVfb, VirtualFramebuffer *vfb, bool isClearingDepth) { - if (ShouldDownloadFramebuffer(vfb) && !vfb->memoryUpdated) { - ReadFramebufferToMemory(vfb, true, 0, 0, vfb->width, vfb->height); - } else { - DownloadFramebufferOnSwitch(prevVfb); - } - textureCacheGL_->ForgetLastTexture(); - - if (useBufferedRendering_) { - if (vfb->fbo) { - draw_->BindFramebufferAsRenderTarget(vfb->fbo); - } else { - // wtf? This should only happen very briefly when toggling bBufferedRendering - draw_->BindBackbufferAsRenderTarget(); - } - } else { - if (vfb->fbo) { - // wtf? This should only happen very briefly when toggling bBufferedRendering - textureCacheGL_->NotifyFramebuffer(vfb->fb_address, vfb, NOTIFY_FB_DESTROYED); - delete vfb->fbo; - vfb->fbo = nullptr; - } - draw_->BindBackbufferAsRenderTarget(); - - // Let's ignore rendering to targets that have not (yet) been displayed. - if (vfb->usageFlags & FB_USAGE_DISPLAYED_FRAMEBUFFER) { - gstate_c.skipDrawReason &= ~SKIPDRAW_NON_DISPLAYED_FB; - } else { - gstate_c.skipDrawReason |= SKIPDRAW_NON_DISPLAYED_FB; - } - } - textureCacheGL_->NotifyFramebuffer(vfb->fb_address, vfb, NOTIFY_FB_UPDATED); - - if (gl_extensions.IsGLES) { - // 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 (vfb->last_frame_render != gpuStats.numFlips) { - ClearBuffer(); - } - } - - // Copy depth pixel value from the read framebuffer to the draw framebuffer - if (prevVfb && !g_Config.bDisableSlowFramebufEffects) { - if (!prevVfb->fbo || !vfb->fbo || !useBufferedRendering_ || !prevVfb->depthUpdated || isClearingDepth) { - // If depth wasn't updated, then we're at least "two degrees" away from the data. - // This is an optimization: it probably doesn't need to be copied in this case. - } else { - BlitFramebufferDepth(prevVfb, vfb); - } - } - if (vfb->drawnFormat != vfb->format) { - // TODO: Might ultimately combine this with the resize step in DoSetRenderFrameBuffer(). - ReformatFramebufferFrom(vfb, vfb->drawnFormat); - } - - // ugly... - if ((gstate_c.curRTWidth != vfb->width || gstate_c.curRTHeight != vfb->height) && shaderManager_) { - gstate_c.Dirty(DIRTY_PROJTHROUGHMATRIX); - } -} - void FramebufferManagerGLES::SetLineWidth() { #ifndef USING_GLES2 if (g_Config.iInternalResolution == 0) { diff --git a/GPU/GLES/FramebufferManagerGLES.h b/GPU/GLES/FramebufferManagerGLES.h index f7ac095a0c..6a016da7e6 100644 --- a/GPU/GLES/FramebufferManagerGLES.h +++ b/GPU/GLES/FramebufferManagerGLES.h @@ -80,7 +80,7 @@ public: void SetLineWidth(); void ReformatFramebufferFrom(VirtualFramebuffer *vfb, GEBufferFormat old) override; - void BlitFramebufferDepth(VirtualFramebuffer *src, VirtualFramebuffer *dst); + void BlitFramebufferDepth(VirtualFramebuffer *src, VirtualFramebuffer *dst) override; // For use when texturing from a framebuffer. May create a duplicate if target. void BindFramebufferColor(int stage, u32 fbRawAddress, VirtualFramebuffer *framebuffer, int flags); @@ -111,7 +111,6 @@ protected: // Used by ReadFramebufferToMemory and later framebuffer block copies void BlitFramebuffer(VirtualFramebuffer *dst, int dstX, int dstY, VirtualFramebuffer *src, int srcX, int srcY, int w, int h, int bpp) override; - void NotifyRenderFramebufferSwitched(VirtualFramebuffer *prevVfb, VirtualFramebuffer *vfb, bool isClearingDepth) override; bool CreateDownloadTempBuffer(VirtualFramebuffer *nvfb) override; void UpdateDownloadTempBuffer(VirtualFramebuffer *nvfb) override; diff --git a/GPU/Vulkan/FramebufferVulkan.cpp b/GPU/Vulkan/FramebufferVulkan.cpp index 6281206a57..6ba67eaab8 100644 --- a/GPU/Vulkan/FramebufferVulkan.cpp +++ b/GPU/Vulkan/FramebufferVulkan.cpp @@ -624,55 +624,6 @@ void FramebufferManagerVulkan::ResizeFramebufFBO(VirtualFramebuffer *vfb, u16 w, */ } -void FramebufferManagerVulkan::NotifyRenderFramebufferSwitched(VirtualFramebuffer *prevVfb, VirtualFramebuffer *vfb, bool isClearingDepth) { - if (ShouldDownloadFramebuffer(vfb) && !vfb->memoryUpdated) { - ReadFramebufferToMemory(vfb, true, 0, 0, vfb->width, vfb->height); - } else { - DownloadFramebufferOnSwitch(prevVfb); - } - textureCacheVulkan_->ForgetLastTexture(); - - if (useBufferedRendering_) { - if (vfb->fbo) { - // vfb->fbo->GetColorImageView(); - } - } else { - if (vfb->fbo) { - // wtf? This should only happen very briefly when toggling bBufferedRendering - textureCacheVulkan_->NotifyFramebuffer(vfb->fb_address, vfb, NOTIFY_FB_DESTROYED); - delete vfb->fbo; - vfb->fbo = nullptr; - } - - // Let's ignore rendering to targets that have not (yet) been displayed. - if (vfb->usageFlags & FB_USAGE_DISPLAYED_FRAMEBUFFER) { - gstate_c.skipDrawReason &= ~SKIPDRAW_NON_DISPLAYED_FB; - } else { - gstate_c.skipDrawReason |= SKIPDRAW_NON_DISPLAYED_FB; - } - } - textureCacheVulkan_->NotifyFramebuffer(vfb->fb_address, vfb, NOTIFY_FB_UPDATED); - - // Copy depth pixel value from the read framebuffer to the draw framebuffer - if (prevVfb && !g_Config.bDisableSlowFramebufEffects) { - if (!prevVfb->fbo || !vfb->fbo || !useBufferedRendering_ || !prevVfb->depthUpdated || isClearingDepth) { - // If depth wasn't updated, then we're at least "two degrees" away from the data. - // This is an optimization: it probably doesn't need to be copied in this case. - } else { - BlitFramebufferDepth(prevVfb, vfb); - } - } - if (vfb->drawnFormat != vfb->format) { - // TODO: Might ultimately combine this with the resize step in DoSetRenderFrameBuffer(). - ReformatFramebufferFrom(vfb, vfb->drawnFormat); - } - - // ugly... - if ((gstate_c.curRTWidth != vfb->width || gstate_c.curRTHeight != vfb->height) && shaderManager_) { - gstate_c.Dirty(DIRTY_PROJMATRIX); - } -} - bool FramebufferManagerVulkan::NotifyStencilUpload(u32 addr, int size, bool skipZero) { // In Vulkan we should be able to simply copy the stencil data directly to a stencil buffer without // messing about with bitplane textures and the like. diff --git a/GPU/Vulkan/FramebufferVulkan.h b/GPU/Vulkan/FramebufferVulkan.h index a46db25177..04dfbf8692 100644 --- a/GPU/Vulkan/FramebufferVulkan.h +++ b/GPU/Vulkan/FramebufferVulkan.h @@ -98,7 +98,7 @@ public: int GetLineWidth(); void ReformatFramebufferFrom(VirtualFramebuffer *vfb, GEBufferFormat old) override; - void BlitFramebufferDepth(VirtualFramebuffer *src, VirtualFramebuffer *dst); + void BlitFramebufferDepth(VirtualFramebuffer *src, VirtualFramebuffer *dst) override; // For use when texturing from a framebuffer. May create a duplicate if target. VulkanTexture *GetFramebufferColor(u32 fbRawAddress, VirtualFramebuffer *framebuffer, int flags); @@ -140,8 +140,6 @@ protected: // Used by ReadFramebufferToMemory and later framebuffer block copies void BlitFramebuffer(VirtualFramebuffer *dst, int dstX, int dstY, VirtualFramebuffer *src, int srcX, int srcY, int w, int h, int bpp) override; - - void NotifyRenderFramebufferSwitched(VirtualFramebuffer *prevVfb, VirtualFramebuffer *vfb, bool isClearingDepth) override; bool CreateDownloadTempBuffer(VirtualFramebuffer *nvfb) override; void UpdateDownloadTempBuffer(VirtualFramebuffer *nvfb) override;