From 1ab9293cb3071f41a271193ff5db7a3b64829ea5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 3 Aug 2022 15:41:17 +0200 Subject: [PATCH] Convert FramebufferBlit from the GL backend to use thin3d --- GPU/Common/FramebufferManagerCommon.cpp | 104 ++++++++++++++++++++++++ GPU/Common/FramebufferManagerCommon.h | 7 +- GPU/D3D11/FramebufferManagerD3D11.cpp | 35 -------- GPU/D3D11/FramebufferManagerD3D11.h | 4 - GPU/GLES/FramebufferManagerGLES.cpp | 85 ------------------- GPU/GLES/FramebufferManagerGLES.h | 3 - 6 files changed, 110 insertions(+), 128 deletions(-) diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index 3c6315e863..52c328b90d 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -2560,3 +2560,107 @@ void FramebufferManagerCommon::DrawActiveTexture(float x, float y, float w, floa gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS | DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE); } + +void FramebufferManagerCommon::BlitFramebuffer(VirtualFramebuffer *dst, int dstX, int dstY, VirtualFramebuffer *src, int srcX, int srcY, int w, int h, int bpp, const char *tag) { + if (!dst->fbo || !src->fbo || !useBufferedRendering_) { + // This can happen if they recently switched from non-buffered. + if (useBufferedRendering_) { + draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "BlitFramebuffer"); + } + return; + } + + bool useBlit = draw_->GetDeviceCaps().framebufferBlitSupported; + bool useCopy = draw_->GetDeviceCaps().framebufferCopySupported; + if (dst == currentRenderVfb_) { + // If already bound, using either a blit or a copy is unlikely to be an optimization. + useBlit = false; + useCopy = false; + } + + float srcXFactor = useBlit ? src->renderScaleFactor : 1.0f; + float srcYFactor = useBlit ? src->renderScaleFactor : 1.0f; + const int srcBpp = src->format == GE_FORMAT_8888 ? 4 : 2; + if (srcBpp != bpp && bpp != 0) { + srcXFactor = (srcXFactor * bpp) / srcBpp; + } + int srcX1 = srcX * srcXFactor; + int srcX2 = (srcX + w) * srcXFactor; + int srcY1 = srcY * srcYFactor; + int srcY2 = (srcY + h) * srcYFactor; + + float dstXFactor = useBlit ? dst->renderScaleFactor : 1.0f; + float dstYFactor = useBlit ? dst->renderScaleFactor : 1.0f; + const int dstBpp = dst->format == GE_FORMAT_8888 ? 4 : 2; + if (dstBpp != bpp && bpp != 0) { + dstXFactor = (dstXFactor * bpp) / dstBpp; + } + int dstX1 = dstX * dstXFactor; + int dstX2 = (dstX + w) * dstXFactor; + int dstY1 = dstY * dstYFactor; + int dstY2 = (dstY + h) * dstYFactor; + + if (src == dst && srcX == dstX && srcY == dstY) { + // Let's just skip a copy where the destination is equal to the source. + WARN_LOG_REPORT_ONCE(blitSame, G3D, "Skipped blit with equal dst and src"); + return; + } + + if (useCopy) { + // glBlitFramebuffer can clip, but glCopyImageSubData is more restricted. + // In case the src goes outside, we just skip the optimization in that case. + const bool sameSize = dstX2 - dstX1 == srcX2 - srcX1 && dstY2 - dstY1 == srcY2 - srcY1; + const bool srcInsideBounds = srcX2 <= src->renderWidth && srcY2 <= src->renderHeight; + const bool dstInsideBounds = dstX2 <= dst->renderWidth && dstY2 <= dst->renderHeight; + const bool xOverlap = src == dst && srcX2 > dstX1 && srcX1 < dstX2; + const bool yOverlap = src == dst && srcY2 > dstY1 && srcY1 < dstY2; + if (sameSize && srcInsideBounds && dstInsideBounds && !(xOverlap && yOverlap)) { + draw_->CopyFramebufferImage(src->fbo, 0, srcX1, srcY1, 0, dst->fbo, 0, dstX1, dstY1, 0, dstX2 - dstX1, dstY2 - dstY1, 1, Draw::FB_COLOR_BIT, tag); + return; + } + } + + if (useBlit) { + draw_->BlitFramebuffer(src->fbo, srcX1, srcY1, srcX2, srcY2, dst->fbo, dstX1, dstY1, dstX2, dstY2, Draw::FB_COLOR_BIT, Draw::FB_BLIT_NEAREST, tag); + } else { + BlitUsingRaster(src->fbo, srcX1, srcY1, srcX2, srcY2, dst->fbo, dstX1, dstY1, dstX2, dstY2, false); + } + + gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_BLEND_STATE | DIRTY_RASTER_STATE); +} + +void FramebufferManagerCommon::BlitUsingRaster( + Draw::Framebuffer *src, float srcX1, float srcY1, float srcX2, float srcY2, + Draw::Framebuffer *dest, float destX1, float destY1, float destX2, float destY2, + bool linearFilter) { + + int destW, destH, srcW, srcH; + draw_->GetFramebufferDimensions(src, &srcW, &srcH); + draw_->GetFramebufferDimensions(dest, &destW, &destH); + + if (srcW == destW && srcH == destH && destX2 - destX1 == srcX2 - srcX1 && destY2 - destY1 == srcY2 - srcY1) { + // Optimize to a copy + draw_->CopyFramebufferImage(src, 0, (int)srcX1, (int)srcY1, 0, dest, 0, (int)destX1, (int)destY1, 0, (int)(srcX2 - srcX1), (int)(srcY2 - srcY1), 1, Draw::FB_COLOR_BIT, "BlitUsingRaster"); + return; + } + + float dX = 1.0f / (float)destW; + float dY = 1.0f / (float)destH; + float sX = 1.0f / (float)srcW; + float sY = 1.0f / (float)srcH; + Draw2DVertex vtx[4] = { + { -1.0f + 2.0f * dX * destX1, -(1.0f - 2.0f * dY * destY1), sX * srcX1, sY * srcY1 }, + { -1.0f + 2.0f * dX * destX2, -(1.0f - 2.0f * dY * destY1), sX * srcX2, sY * srcY1 }, + { -1.0f + 2.0f * dX * destX1, -(1.0f - 2.0f * dY * destY2), sX * srcX1, sY * srcY2 }, + { -1.0f + 2.0f * dX * destX2, -(1.0f - 2.0f * dY * destY2), sX * srcX2, sY * srcY2 }, + }; + + // Unbind the texture first to avoid the D3D11 hazard check (can't set render target to things bound as textures and vice versa, not even temporarily). + draw_->BindTexture(0, nullptr); + draw_->BindFramebufferAsRenderTarget(dest, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "BlitUsingRaster"); + draw_->BindFramebufferAsTexture(src, 0, Draw::FB_COLOR_BIT, 0); + + DrawStrip2D(nullptr, vtx, 4, linearFilter); + + gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE); +} diff --git a/GPU/Common/FramebufferManagerCommon.h b/GPU/Common/FramebufferManagerCommon.h index 8fc8717ba9..2f09440b56 100644 --- a/GPU/Common/FramebufferManagerCommon.h +++ b/GPU/Common/FramebufferManagerCommon.h @@ -363,7 +363,12 @@ protected: virtual void DecimateFBOs(); // keeping it virtual to let D3D do a little extra // Used by ReadFramebufferToMemory and later framebuffer block copies - virtual void BlitFramebuffer(VirtualFramebuffer *dst, int dstX, int dstY, VirtualFramebuffer *src, int srcX, int srcY, int w, int h, int bpp, const char *tag) = 0; + virtual void BlitFramebuffer(VirtualFramebuffer *dst, int dstX, int dstY, VirtualFramebuffer *src, int srcX, int srcY, int w, int h, int bpp, const char *tag); + + void BlitUsingRaster( + Draw::Framebuffer *src, float srcX1, float srcY1, float srcX2, float srcY2, + Draw::Framebuffer *dest, float destX1, float destY1, float destX2, float destY2, bool linearFilter); + void CopyFramebufferForColorTexture(VirtualFramebuffer *dst, VirtualFramebuffer *src, int flags); void EstimateDrawingSize(u32 fb_address, GEBufferFormat fb_format, int viewport_width, int viewport_height, int region_width, int region_height, int scissor_width, int scissor_height, int fb_stride, int &drawing_width, int &drawing_height); diff --git a/GPU/D3D11/FramebufferManagerD3D11.cpp b/GPU/D3D11/FramebufferManagerD3D11.cpp index b5b7b4187e..72622d3ee6 100644 --- a/GPU/D3D11/FramebufferManagerD3D11.cpp +++ b/GPU/D3D11/FramebufferManagerD3D11.cpp @@ -198,41 +198,6 @@ static void CopyPixelDepthOnly(u32 *dstp, const u32 *srcp, size_t c) { } } -void FramebufferManagerD3D11::SimpleBlit( - Draw::Framebuffer *dest, float destX1, float destY1, float destX2, float destY2, - Draw::Framebuffer *src, float srcX1, float srcY1, float srcX2, float srcY2, bool linearFilter) { - - int destW, destH, srcW, srcH; - draw_->GetFramebufferDimensions(src, &srcW, &srcH); - draw_->GetFramebufferDimensions(dest, &destW, &destH); - - if (srcW == destW && srcH == destH && destX2 - destX1 == srcX2 - srcX1 && destY2 - destY1 == srcY2 - srcY1) { - // Optimize to a copy - draw_->CopyFramebufferImage(src, 0, (int)srcX1, (int)srcY1, 0, dest, 0, (int)destX1, (int)destY1, 0, (int)(srcX2 - srcX1), (int)(srcY2 - srcY1), 1, Draw::FB_COLOR_BIT, "SimpleBlit"); - return; - } - - float dX = 1.0f / (float)destW; - float dY = 1.0f / (float)destH; - float sX = 1.0f / (float)srcW; - float sY = 1.0f / (float)srcH; - Draw2DVertex vtx[4] = { - { -1.0f + 2.0f * dX * destX1, -(1.0f - 2.0f * dY * destY1), sX * srcX1, sY * srcY1 }, - { -1.0f + 2.0f * dX * destX2, -(1.0f - 2.0f * dY * destY1), sX * srcX2, sY * srcY1 }, - { -1.0f + 2.0f * dX * destX1, -(1.0f - 2.0f * dY * destY2), sX * srcX1, sY * srcY2 }, - { -1.0f + 2.0f * dX * destX2, -(1.0f - 2.0f * dY * destY2), sX * srcX2, sY * srcY2 }, - }; - - // Unbind the texture first to avoid the D3D11 hazard check (can't set render target to things bound as textures and vice versa, not even temporarily). - draw_->BindTexture(0, nullptr); - draw_->BindFramebufferAsRenderTarget(dest, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "SimpleBlit"); - draw_->BindFramebufferAsTexture(src, 0, Draw::FB_COLOR_BIT, 0); - - DrawStrip2D(nullptr, vtx, 4, linearFilter); - - gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE); -} - void FramebufferManagerD3D11::BlitFramebuffer(VirtualFramebuffer *dst, int dstX, int dstY, VirtualFramebuffer *src, int srcX, int srcY, int w, int h, int bpp, const char *tag) { if (!dst->fbo || !src->fbo || !useBufferedRendering_) { // This can happen if they recently switched from non-buffered. diff --git a/GPU/D3D11/FramebufferManagerD3D11.h b/GPU/D3D11/FramebufferManagerD3D11.h index 38d0d6623b..2d37fb26e9 100644 --- a/GPU/D3D11/FramebufferManagerD3D11.h +++ b/GPU/D3D11/FramebufferManagerD3D11.h @@ -54,10 +54,6 @@ protected: private: void Bind2DShader() override; void PackDepthbuffer(VirtualFramebuffer *vfb, int x, int y, int w, int h); - void SimpleBlit( - Draw::Framebuffer *dest, float destX1, float destY1, float destX2, float destY2, - Draw::Framebuffer *src, float srcX1, float srcY1, float srcX2, float srcY2, - bool linearFilter); ID3D11Device *device_; ID3D11DeviceContext *context_; diff --git a/GPU/GLES/FramebufferManagerGLES.cpp b/GPU/GLES/FramebufferManagerGLES.cpp index 0e8077e60f..8d1bcc629d 100644 --- a/GPU/GLES/FramebufferManagerGLES.cpp +++ b/GPU/GLES/FramebufferManagerGLES.cpp @@ -174,91 +174,6 @@ void FramebufferManagerGLES::UpdateDownloadTempBuffer(VirtualFramebuffer *nvfb) } } -void FramebufferManagerGLES::BlitFramebuffer(VirtualFramebuffer *dst, int dstX, int dstY, VirtualFramebuffer *src, int srcX, int srcY, int w, int h, int bpp, const char *tag) { - if (!dst->fbo || !src->fbo || !useBufferedRendering_) { - // This can happen if they recently switched from non-buffered. - if (useBufferedRendering_) - draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "BlitFramebuffer"); - return; - } - - bool useBlit = draw_->GetDeviceCaps().framebufferBlitSupported; - bool useCopy = draw_->GetDeviceCaps().framebufferCopySupported; - if (dst == currentRenderVfb_) { - // If already bound, using either a blit or a copy is unlikely to be an optimization. - useBlit = false; - useCopy = false; - } - - float srcXFactor = useBlit ? src->renderScaleFactor : 1.0f; - float srcYFactor = useBlit ? src->renderScaleFactor : 1.0f; - const int srcBpp = src->format == GE_FORMAT_8888 ? 4 : 2; - if (srcBpp != bpp && bpp != 0) { - srcXFactor = (srcXFactor * bpp) / srcBpp; - } - int srcX1 = srcX * srcXFactor; - int srcX2 = (srcX + w) * srcXFactor; - int srcY1 = srcY * srcYFactor; - int srcY2 = (srcY + h) * srcYFactor; - - float dstXFactor = useBlit ? dst->renderScaleFactor : 1.0f; - float dstYFactor = useBlit ? dst->renderScaleFactor : 1.0f; - const int dstBpp = dst->format == GE_FORMAT_8888 ? 4 : 2; - if (dstBpp != bpp && bpp != 0) { - dstXFactor = (dstXFactor * bpp) / dstBpp; - } - int dstX1 = dstX * dstXFactor; - int dstX2 = (dstX + w) * dstXFactor; - int dstY1 = dstY * dstYFactor; - int dstY2 = (dstY + h) * dstYFactor; - - if (src == dst && srcX == dstX && srcY == dstY) { - // Let's just skip a copy where the destination is equal to the source. - WARN_LOG_REPORT_ONCE(blitSame, G3D, "Skipped blit with equal dst and src"); - return; - } - - if (useCopy && draw_->GetDeviceCaps().framebufferCopySupported) { - // glBlitFramebuffer can clip, but glCopyImageSubData is more restricted. - // In case the src goes outside, we just skip the optimization in that case. - const bool sameSize = dstX2 - dstX1 == srcX2 - srcX1 && dstY2 - dstY1 == srcY2 - srcY1; - const bool srcInsideBounds = srcX2 <= src->renderWidth && srcY2 <= src->renderHeight; - const bool dstInsideBounds = dstX2 <= dst->renderWidth && dstY2 <= dst->renderHeight; - const bool xOverlap = src == dst && srcX2 > dstX1 && srcX1 < dstX2; - const bool yOverlap = src == dst && srcY2 > dstY1 && srcY1 < dstY2; - if (sameSize && srcInsideBounds && dstInsideBounds && !(xOverlap && yOverlap)) { - draw_->CopyFramebufferImage(src->fbo, 0, srcX1, srcY1, 0, dst->fbo, 0, dstX1, dstY1, 0, dstX2 - dstX1, dstY2 - dstY1, 1, Draw::FB_COLOR_BIT, tag); - return; - } - } - - if (useBlit) { - draw_->BlitFramebuffer(src->fbo, srcX1, srcY1, srcX2, srcY2, dst->fbo, dstX1, dstY1, dstX2, dstY2, Draw::FB_COLOR_BIT, Draw::FB_BLIT_NEAREST, tag); - } else { - // TODO: Use thin3d for this, instead of dirtying up the code here. - draw_->BindFramebufferAsRenderTarget(dst->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, tag); - draw_->BindFramebufferAsTexture(src->fbo, 0, Draw::FB_COLOR_BIT, 0); - - // Make sure our 2D drawing program is ready. Compiles only if not already compiled. - CompileDraw2DProgram(); - - render_->SetViewport({ 0, 0, (float)dst->renderWidth, (float)dst->renderHeight, 0, 1.0f }); - render_->SetStencilDisabled(); - render_->SetDepth(false, false, GL_ALWAYS); - render_->SetNoBlendAndMask(0xF); - - // The first four coordinates are relative to the 6th and 7th arguments of DrawActiveTexture. - // Should maybe revamp that interface. - float srcW = src->bufferWidth; - float srcH = src->bufferHeight; - render_->BindProgram(draw2dprogram_); - DrawActiveTexture(dstX1, dstY1, w * dstXFactor, h * dstYFactor, dst->bufferWidth, dst->bufferHeight, srcX1 / srcW, srcY1 / srcH, srcX2 / srcW, srcY2 / srcH, ROTATION_LOCKED_HORIZONTAL, DRAWTEX_NEAREST); - textureCache_->ForgetLastTexture(); - } - - gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_BLEND_STATE | DIRTY_RASTER_STATE); -} - void FramebufferManagerGLES::EndFrame() { } diff --git a/GPU/GLES/FramebufferManagerGLES.h b/GPU/GLES/FramebufferManagerGLES.h index fc69c77341..349b5a23e6 100644 --- a/GPU/GLES/FramebufferManagerGLES.h +++ b/GPU/GLES/FramebufferManagerGLES.h @@ -50,9 +50,6 @@ public: bool GetOutputFramebuffer(GPUDebugBuffer &buffer) override; 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, const char *tag) override; - void UpdateDownloadTempBuffer(VirtualFramebuffer *nvfb) override; private: