diff --git a/Core/CoreParameter.h b/Core/CoreParameter.h index a4e542bf02..abfb9e40e6 100644 --- a/Core/CoreParameter.h +++ b/Core/CoreParameter.h @@ -66,11 +66,12 @@ struct CoreParameter { std::string *collectEmuLog = nullptr; bool headLess; // Try to avoid messageboxes etc - // Internal PSP resolution + // Internal PSP rendering resolution and scale factor. + int renderScaleFactor; int renderWidth; int renderHeight; - // Actual pixel output resolution (for use by glViewport and the like) + // Actual output resolution in pixels. int pixelWidth; int pixelHeight; diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index b83bef2098..6d0744dea9 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -77,6 +77,7 @@ bool FramebufferManagerCommon::UpdateSize() { renderWidth_ = (float)PSP_CoreParameter().renderWidth; renderHeight_ = (float)PSP_CoreParameter().renderHeight; + renderScaleFactor_ = (float)PSP_CoreParameter().renderScaleFactor; pixelWidth_ = PSP_CoreParameter().pixelWidth; pixelHeight_ = PSP_CoreParameter().pixelHeight; bloomHack_ = g_Config.iBloomHack; @@ -340,14 +341,6 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(const Frame } } - float renderWidthFactor = renderWidth_ / 480.0f; - float renderHeightFactor = renderHeight_ / 272.0f; - - if (PSP_CoreParameter().compat.flags().Force04154000Download && params.fb_address == 0x04154000) { - renderWidthFactor = 1.0; - renderHeightFactor = 1.0; - } - // None found? Create one. if (!vfb) { vfb = new VirtualFramebuffer{}; @@ -356,28 +349,28 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(const Frame vfb->fb_stride = params.fb_stride; vfb->z_address = params.z_address; vfb->z_stride = params.z_stride; + + // The other width/height parameters are set in ResizeFramebufFBO below. vfb->width = drawing_width; vfb->height = drawing_height; vfb->newWidth = drawing_width; vfb->newHeight = drawing_height; vfb->lastFrameNewSize = gpuStats.numFlips; - vfb->renderWidth = (u16)(drawing_width * renderWidthFactor); - vfb->renderHeight = (u16)(drawing_height * renderHeightFactor); - vfb->bufferWidth = drawing_width; - vfb->bufferHeight = drawing_height; vfb->format = params.fmt; vfb->drawnFormat = params.fmt; vfb->usageFlags = FB_USAGE_RENDERTARGET; - SetColorUpdated(vfb, skipDrawReason); u32 byteSize = ColorBufferByteSize(vfb); if (Memory::IsVRAMAddress(params.fb_address) && params.fb_address + byteSize > framebufRangeEnd_) { framebufRangeEnd_ = params.fb_address + byteSize; } + // This is where we actually create the framebuffer. The true is "force". ResizeFramebufFBO(vfb, drawing_width, drawing_height, true); NotifyRenderFramebufferCreated(vfb); + SetColorUpdated(vfb, skipDrawReason); + INFO_LOG(FRAMEBUF, "Creating FBO for %08x (z: %08x) : %i x %i x %i", vfb->fb_address, vfb->z_address, vfb->width, vfb->height, vfb->format); vfb->last_frame_render = gpuStats.numFlips; @@ -1046,6 +1039,7 @@ void FramebufferManagerCommon::DecimateFBOs() { } } +// Requires width/height to be set already. void FramebufferManagerCommon::ResizeFramebufFBO(VirtualFramebuffer *vfb, int w, int h, bool force, bool skipCopy) { _dbg_assert_(w > 0); _dbg_assert_(h > 0); @@ -1067,7 +1061,32 @@ void FramebufferManagerCommon::ResizeFramebufFBO(VirtualFramebuffer *vfb, int w, vfb->bufferHeight = std::max((int)vfb->bufferHeight, h); } - SetRenderSize(vfb); + bool force1x = false; + switch (bloomHack_) { + case 1: + force1x = vfb->bufferWidth <= 128 || vfb->bufferHeight <= 64; + break; + case 2: + force1x = vfb->bufferWidth <= 256 || vfb->bufferHeight <= 128; + break; + case 3: + force1x = vfb->bufferWidth < 480 || vfb->bufferWidth > 800 || vfb->bufferHeight < 272; // GOW uses 864x272 + break; + } + + if (PSP_CoreParameter().compat.flags().Force04154000Download && vfb->fb_address == 0x04154000) { + force1x = true; + } + + if (force1x && g_Config.iInternalResolution != 1) { + vfb->renderScaleFactor = 1.0f; + vfb->renderWidth = vfb->bufferWidth; + vfb->renderHeight = vfb->bufferHeight; + } else { + vfb->renderScaleFactor = renderScaleFactor_; + vfb->renderWidth = (u16)(vfb->bufferWidth * renderScaleFactor_); + vfb->renderHeight = (u16)(vfb->bufferHeight * renderScaleFactor_); + } // During hardware rendering, we always render at full color depth even if the game wouldn't on real hardware. // It's not worth the trouble trying to support lower bit-depth rendering, just @@ -1655,35 +1674,6 @@ void FramebufferManagerCommon::NotifyBlockTransferAfter(u32 dstBasePtr, int dstS } } -void FramebufferManagerCommon::SetRenderSize(VirtualFramebuffer *vfb) { - float renderWidthFactor = renderWidth_ / 480.0f; - float renderHeightFactor = renderHeight_ / 272.0f; - bool force1x = false; - switch (bloomHack_) { - case 1: - force1x = vfb->bufferWidth <= 128 || vfb->bufferHeight <= 64; - break; - case 2: - force1x = vfb->bufferWidth <= 256 || vfb->bufferHeight <= 128; - break; - case 3: - force1x = vfb->bufferWidth < 480 || vfb->bufferWidth > 800 || vfb->bufferHeight < 272; // GOW uses 864x272 - break; - } - - if (PSP_CoreParameter().compat.flags().Force04154000Download && vfb->fb_address == 0x04154000) { - force1x = true; - } - - if (force1x && g_Config.iInternalResolution != 1) { - vfb->renderWidth = vfb->bufferWidth; - vfb->renderHeight = vfb->bufferHeight; - } else { - vfb->renderWidth = (u16)(vfb->bufferWidth * renderWidthFactor); - vfb->renderHeight = (u16)(vfb->bufferHeight * renderHeightFactor); - } -} - void FramebufferManagerCommon::SetSafeSize(u16 w, u16 h) { VirtualFramebuffer *vfb = currentRenderVfb_; if (vfb) { @@ -1695,10 +1685,11 @@ void FramebufferManagerCommon::SetSafeSize(u16 w, u16 h) { void FramebufferManagerCommon::Resized() { gstate_c.skipDrawReason &= ~SKIPDRAW_NON_DISPLAYED_FB; - int w, h; - presentation_->CalculateRenderResolution(&w, &h, &postShaderIsUpscalingFilter_, &postShaderIsSupersampling_); + int w, h, scaleFactor; + presentation_->CalculateRenderResolution(&w, &h, &scaleFactor, &postShaderIsUpscalingFilter_, &postShaderIsSupersampling_); PSP_CoreParameter().renderWidth = w; PSP_CoreParameter().renderHeight = h; + PSP_CoreParameter().renderScaleFactor = scaleFactor; if (UpdateSize()) { DestroyAllFBOs(); @@ -1736,6 +1727,11 @@ void FramebufferManagerCommon::DestroyAllFBOs() { tempFB.second.fbo->Release(); } tempFBOs_.clear(); + + for (auto iter : fbosToDelete_) { + iter->Release(); + } + fbosToDelete_.clear(); } Draw::Framebuffer *FramebufferManagerCommon::GetTempFBO(TempFBO reason, u16 w, u16 h) { diff --git a/GPU/Common/FramebufferManagerCommon.h b/GPU/Common/FramebufferManagerCommon.h index 905bdaed14..3df8b69acf 100644 --- a/GPU/Common/FramebufferManagerCommon.h +++ b/GPU/Common/FramebufferManagerCommon.h @@ -61,21 +61,24 @@ struct VirtualFramebuffer { u16 width; u16 height; - // renderWidth/renderHeight: The scaled size we render at. May be scaled to render at higher resolutions. - // The physical buffer may be larger than renderWidth/renderHeight. - u16 renderWidth; - u16 renderHeight; - - // bufferWidth/bufferHeight: The pre-scaling size of the buffer itself. May only be bigger than width/height. + // bufferWidth/bufferHeight: The pre-scaling size of the buffer itself. May only be bigger than or equal to width/height. // Actual physical buffer is this size times the render resolution multiplier. // The buffer may be used to render a width or height from 0 to these values without being recreated. u16 bufferWidth; u16 bufferHeight; + // renderWidth/renderHeight: The scaled size we render at. May be scaled to render at higher resolutions. + // The physical buffer may be larger than renderWidth/renderHeight. + u16 renderWidth; + u16 renderHeight; + + float renderScaleFactor; + u16 usageFlags; u16 newWidth; u16 newHeight; + int lastFrameNewSize; Draw::Framebuffer *fbo; @@ -396,9 +399,10 @@ protected: bool gameUsesSequentialCopies_ = false; - // Sampled in BeginFrame for safety. + // Sampled in BeginFrame/UpdateSize for safety. float renderWidth_ = 0.0f; float renderHeight_ = 0.0f; + float renderScaleFactor_ = 1.0f; int pixelWidth_; int pixelHeight_; int bloomHack_ = 0; diff --git a/GPU/Common/PresentationCommon.cpp b/GPU/Common/PresentationCommon.cpp index e4b966ff6f..58233a6d29 100644 --- a/GPU/Common/PresentationCommon.cpp +++ b/GPU/Common/PresentationCommon.cpp @@ -729,7 +729,7 @@ void PresentationCommon::CopyToOutput(OutputFlags flags, int uvRotation, float u draw_->BindPipeline(nullptr); } -void PresentationCommon::CalculateRenderResolution(int *width, int *height, bool *upscaling, bool *ssaa) { +void PresentationCommon::CalculateRenderResolution(int *width, int *height, int *scaleFactor, bool *upscaling, bool *ssaa) { // Check if postprocessing shader is doing upscaling as it requires native resolution std::vector shaderInfo; if (!g_Config.vPostShaderNames.empty() && g_Config.vPostShaderNames[0] != "Off") { @@ -776,4 +776,6 @@ void PresentationCommon::CalculateRenderResolution(int *width, int *height, bool *width = 480 * zoom; *height = 272 * zoom; } + + *scaleFactor = zoom; } diff --git a/GPU/Common/PresentationCommon.h b/GPU/Common/PresentationCommon.h index 0102c3fbcf..959e516d5f 100644 --- a/GPU/Common/PresentationCommon.h +++ b/GPU/Common/PresentationCommon.h @@ -100,7 +100,7 @@ public: void SourceFramebuffer(Draw::Framebuffer *fb, int bufferWidth, int bufferHeight); void CopyToOutput(OutputFlags flags, int uvRotation, float u0, float v0, float u1, float v1); - void CalculateRenderResolution(int *width, int *height, bool *upscaling, bool *ssaa); + void CalculateRenderResolution(int *width, int *height, int *scaleFactor, bool *upscaling, bool *ssaa); protected: void CreateDeviceObjects(); diff --git a/GPU/D3D11/FramebufferManagerD3D11.cpp b/GPU/D3D11/FramebufferManagerD3D11.cpp index 5e2e716e32..2a90aaa4e4 100644 --- a/GPU/D3D11/FramebufferManagerD3D11.cpp +++ b/GPU/D3D11/FramebufferManagerD3D11.cpp @@ -420,8 +420,8 @@ void FramebufferManagerD3D11::BlitFramebuffer(VirtualFramebuffer *dst, int dstX, return; } - float srcXFactor = (float)src->renderWidth / (float)src->bufferWidth; - float srcYFactor = (float)src->renderHeight / (float)src->bufferHeight; + float srcXFactor = src->renderScaleFactor; + float srcYFactor = src->renderScaleFactor; const int srcBpp = src->format == GE_FORMAT_8888 ? 4 : 2; if (srcBpp != bpp && bpp != 0) { srcXFactor = (srcXFactor * bpp) / srcBpp; @@ -431,8 +431,8 @@ void FramebufferManagerD3D11::BlitFramebuffer(VirtualFramebuffer *dst, int dstX, int srcY1 = srcY * srcYFactor; int srcY2 = (srcY + h) * srcYFactor; - float dstXFactor = (float)dst->renderWidth / (float)dst->bufferWidth; - float dstYFactor = (float)dst->renderHeight / (float)dst->bufferHeight; + float dstXFactor = dst->renderScaleFactor; + float dstYFactor = dst->renderScaleFactor; const int dstBpp = dst->format == GE_FORMAT_8888 ? 4 : 2; if (dstBpp != bpp && bpp != 0) { dstXFactor = (dstXFactor * bpp) / dstBpp; diff --git a/GPU/Directx9/FramebufferManagerDX9.cpp b/GPU/Directx9/FramebufferManagerDX9.cpp index 776cdcf7f3..951406c80d 100644 --- a/GPU/Directx9/FramebufferManagerDX9.cpp +++ b/GPU/Directx9/FramebufferManagerDX9.cpp @@ -383,8 +383,8 @@ static const D3DVERTEXELEMENT9 g_FramebufferVertexElements[] = { return; } - float srcXFactor = (float)src->renderWidth / (float)src->bufferWidth; - float srcYFactor = (float)src->renderHeight / (float)src->bufferHeight; + float srcXFactor = (float)src->renderScaleFactor; + float srcYFactor = (float)src->renderScaleFactor; const int srcBpp = src->format == GE_FORMAT_8888 ? 4 : 2; if (srcBpp != bpp && bpp != 0) { srcXFactor = (srcXFactor * bpp) / srcBpp; @@ -394,8 +394,8 @@ static const D3DVERTEXELEMENT9 g_FramebufferVertexElements[] = { int srcY1 = srcY * srcYFactor; int srcY2 = (srcY + h) * srcYFactor; - float dstXFactor = (float)dst->renderWidth / (float)dst->bufferWidth; - float dstYFactor = (float)dst->renderHeight / (float)dst->bufferHeight; + float dstXFactor = (float)dst->renderScaleFactor; + float dstYFactor = (float)dst->renderScaleFactor; const int dstBpp = dst->format == GE_FORMAT_8888 ? 4 : 2; if (dstBpp != bpp && bpp != 0) { dstXFactor = (dstXFactor * bpp) / dstBpp; diff --git a/GPU/GLES/FramebufferManagerGLES.cpp b/GPU/GLES/FramebufferManagerGLES.cpp index c0fd949930..192ed1df28 100644 --- a/GPU/GLES/FramebufferManagerGLES.cpp +++ b/GPU/GLES/FramebufferManagerGLES.cpp @@ -315,8 +315,8 @@ void FramebufferManagerGLES::BlitFramebuffer(VirtualFramebuffer *dst, int dstX, bool useBlit = gstate_c.Supports(GPU_SUPPORTS_FRAMEBUFFER_BLIT); - float srcXFactor = useBlit ? (float)src->renderWidth / (float)src->bufferWidth : 1.0f; - float srcYFactor = useBlit ? (float)src->renderHeight / (float)src->bufferHeight : 1.0f; + 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; @@ -326,8 +326,8 @@ void FramebufferManagerGLES::BlitFramebuffer(VirtualFramebuffer *dst, int dstX, int srcY1 = srcY * srcYFactor; int srcY2 = (srcY + h) * srcYFactor; - float dstXFactor = useBlit ? (float)dst->renderWidth / (float)dst->bufferWidth : 1.0f; - float dstYFactor = useBlit ? (float)dst->renderHeight / (float)dst->bufferHeight : 1.0f; + 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; diff --git a/GPU/Vulkan/FramebufferManagerVulkan.cpp b/GPU/Vulkan/FramebufferManagerVulkan.cpp index 8acc1cbe2f..d04021ff58 100644 --- a/GPU/Vulkan/FramebufferManagerVulkan.cpp +++ b/GPU/Vulkan/FramebufferManagerVulkan.cpp @@ -261,7 +261,6 @@ void FramebufferManagerVulkan::ReformatFramebufferFrom(VirtualFramebuffer *vfb, // We have to bind here instead of clear, since it can be that no framebuffer is bound. // The backend can sometimes directly optimize it to a clear. draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::CLEAR, Draw::RPAction::KEEP, Draw::RPAction::CLEAR }, "ReformatFramebuffer"); - // draw_->Clear(Draw::FBChannel::FB_COLOR_BIT | Draw::FBChannel::FB_STENCIL_BIT, 0, 0.0f, 0); // Need to dirty anything that has command buffer dynamic state, in case we started a new pass above. // Should find a way to feed that information back, maybe... Or simply correct the issue in the rendermanager. @@ -339,8 +338,10 @@ void FramebufferManagerVulkan::BlitFramebuffer(VirtualFramebuffer *dst, int dstX return; } - float srcXFactor = (float)src->renderWidth / (float)src->bufferWidth; - float srcYFactor = (float)src->renderHeight / (float)src->bufferHeight; + float srcXFactor = (float)src->renderScaleFactor; + float srcYFactor = (float)src->renderScaleFactor; + + // Some games use wrong-format block transfers. Simulate that. const int srcBpp = src->format == GE_FORMAT_8888 ? 4 : 2; if (srcBpp != bpp && bpp != 0) { srcXFactor = (srcXFactor * bpp) / srcBpp; @@ -350,8 +351,8 @@ void FramebufferManagerVulkan::BlitFramebuffer(VirtualFramebuffer *dst, int dstX int srcY1 = srcY * srcYFactor; int srcY2 = (srcY + h) * srcYFactor; - float dstXFactor = (float)dst->renderWidth / (float)dst->bufferWidth; - float dstYFactor = (float)dst->renderHeight / (float)dst->bufferHeight; + float dstXFactor = (float)dst->renderScaleFactor; + float dstYFactor = (float)dst->renderScaleFactor; const int dstBpp = dst->format == GE_FORMAT_8888 ? 4 : 2; if (dstBpp != bpp && bpp != 0) { dstXFactor = (dstXFactor * bpp) / dstBpp; @@ -367,8 +368,6 @@ void FramebufferManagerVulkan::BlitFramebuffer(VirtualFramebuffer *dst, int dstX return; } - // BlitFramebuffer can clip, but CopyFramebufferImage 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; diff --git a/headless/Headless.cpp b/headless/Headless.cpp index fb80436d73..1dc70e488d 100644 --- a/headless/Headless.cpp +++ b/headless/Headless.cpp @@ -358,6 +358,7 @@ int main(int argc, const char* argv[]) coreParameter.startBreak = false; coreParameter.printfEmuLog = !autoCompare; coreParameter.headLess = true; + coreParameter.renderScaleFactor = 1; coreParameter.renderWidth = 480; coreParameter.renderHeight = 272; coreParameter.pixelWidth = 480;