From 33bc286baaafe31b2b564dd5d5574307cbd9e921 Mon Sep 17 00:00:00 2001 From: iwubcode Date: Sun, 6 Aug 2017 23:05:42 -0500 Subject: [PATCH] Remove old XFB logic --- Source/Core/VideoBackends/D3D/CMakeLists.txt | 2 - Source/Core/VideoBackends/D3D/D3D.vcxproj | 2 - .../VideoBackends/D3D/D3D.vcxproj.filters | 6 - .../VideoBackends/D3D/FramebufferManager.cpp | 54 --- .../VideoBackends/D3D/FramebufferManager.h | 18 - Source/Core/VideoBackends/D3D/Render.cpp | 5 - Source/Core/VideoBackends/D3D/XFBEncoder.cpp | 367 ------------------ Source/Core/VideoBackends/D3D/XFBEncoder.h | 46 --- .../VideoBackends/Null/FramebufferManager.h | 33 -- Source/Core/VideoBackends/Null/Null.vcxproj | 1 - .../Core/VideoBackends/Null/NullBackend.cpp | 4 +- .../VideoBackends/OGL/FramebufferManager.cpp | 73 ---- .../VideoBackends/OGL/FramebufferManager.h | 20 - Source/Core/VideoBackends/OGL/Render.cpp | 156 +------- Source/Core/VideoBackends/OGL/Render.h | 21 - .../VideoBackends/OGL/TextureConverter.cpp | 149 ------- .../Core/VideoBackends/OGL/TextureConverter.h | 5 - .../Vulkan/FramebufferManager.cpp | 89 ----- .../VideoBackends/Vulkan/FramebufferManager.h | 25 -- Source/Core/VideoBackends/Vulkan/Renderer.cpp | 356 ----------------- Source/Core/VideoBackends/Vulkan/Renderer.h | 66 ---- .../VideoCommon/FramebufferManagerBase.cpp | 140 +------ .../Core/VideoCommon/FramebufferManagerBase.h | 60 --- Source/Core/VideoCommon/RenderBase.cpp | 31 -- Source/Core/VideoCommon/RenderBase.h | 2 - 25 files changed, 4 insertions(+), 1727 deletions(-) delete mode 100644 Source/Core/VideoBackends/D3D/XFBEncoder.cpp delete mode 100644 Source/Core/VideoBackends/D3D/XFBEncoder.h delete mode 100644 Source/Core/VideoBackends/Null/FramebufferManager.h diff --git a/Source/Core/VideoBackends/D3D/CMakeLists.txt b/Source/Core/VideoBackends/D3D/CMakeLists.txt index 953f8737e5..3811ce6a0d 100644 --- a/Source/Core/VideoBackends/D3D/CMakeLists.txt +++ b/Source/Core/VideoBackends/D3D/CMakeLists.txt @@ -38,8 +38,6 @@ set(SRCS VertexShaderCache.cpp VertexShaderCache.h VideoBackend.h - XFBEncoder.cpp - XFBEncoder.h ) set(LIBS diff --git a/Source/Core/VideoBackends/D3D/D3D.vcxproj b/Source/Core/VideoBackends/D3D/D3D.vcxproj index ff63898039..50c8ea0fcd 100644 --- a/Source/Core/VideoBackends/D3D/D3D.vcxproj +++ b/Source/Core/VideoBackends/D3D/D3D.vcxproj @@ -55,7 +55,6 @@ - @@ -76,7 +75,6 @@ - diff --git a/Source/Core/VideoBackends/D3D/D3D.vcxproj.filters b/Source/Core/VideoBackends/D3D/D3D.vcxproj.filters index e3138ff28f..f544ae67db 100644 --- a/Source/Core/VideoBackends/D3D/D3D.vcxproj.filters +++ b/Source/Core/VideoBackends/D3D/D3D.vcxproj.filters @@ -57,9 +57,6 @@ Render - - Render - Render @@ -114,9 +111,6 @@ Render - - Render - Render diff --git a/Source/Core/VideoBackends/D3D/FramebufferManager.cpp b/Source/Core/VideoBackends/D3D/FramebufferManager.cpp index 3ecd3119f8..4bd5a3fd60 100644 --- a/Source/Core/VideoBackends/D3D/FramebufferManager.cpp +++ b/Source/Core/VideoBackends/D3D/FramebufferManager.cpp @@ -16,12 +16,10 @@ #include "VideoBackends/D3D/PixelShaderCache.h" #include "VideoBackends/D3D/Render.h" #include "VideoBackends/D3D/VertexShaderCache.h" -#include "VideoBackends/D3D/XFBEncoder.h" #include "VideoCommon/VideoConfig.h" namespace DX11 { -static XFBEncoder s_xfbEncoder; static bool s_integer_efb_render_target = false; FramebufferManager::Efb FramebufferManager::m_efb; @@ -282,15 +280,11 @@ FramebufferManager::FramebufferManager(int target_width, int target_height) m_efb.resolved_color_tex = nullptr; m_efb.resolved_depth_tex = nullptr; } - - s_xfbEncoder.Init(); s_integer_efb_render_target = false; } FramebufferManager::~FramebufferManager() { - s_xfbEncoder.Shutdown(); - SAFE_RELEASE(m_efb.color_tex); SAFE_RELEASE(m_efb.color_int_rtv); SAFE_RELEASE(m_efb.color_temp_tex); @@ -304,52 +298,4 @@ FramebufferManager::~FramebufferManager() SAFE_RELEASE(m_efb.resolved_depth_tex); } -void FramebufferManager::CopyToRealXFB(u32 xfbAddr, u32 fbStride, u32 fbHeight, - const EFBRectangle& sourceRc, float Gamma) -{ - u8* dst = Memory::GetPointer(xfbAddr); - - // The destination stride can differ from the copy region width, in which case the pixels - // outside the copy region should not be written to. - s_xfbEncoder.Encode(dst, static_cast(sourceRc.GetWidth()), fbHeight, sourceRc, Gamma); -} - -std::unique_ptr FramebufferManager::CreateXFBSource(unsigned int target_width, - unsigned int target_height, - unsigned int layers) -{ - return std::make_unique( - D3DTexture2D::Create(target_width, target_height, - (D3D11_BIND_FLAG)(D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE), - D3D11_USAGE_DEFAULT, DXGI_FORMAT_R8G8B8A8_UNORM, 1, layers), - layers); -} - -std::pair FramebufferManager::GetTargetSize() const -{ - return std::make_pair(m_target_width, m_target_height); -} - -void XFBSource::CopyEFB(float Gamma) -{ - g_renderer->ResetAPIState(); // reset any game specific settings - - // Copy EFB data to XFB and restore render target again - const D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, (float)texWidth, (float)texHeight); - const D3D11_RECT rect = CD3D11_RECT(0, 0, texWidth, texHeight); - - D3D::context->RSSetViewports(1, &vp); - D3D::context->OMSetRenderTargets(1, &tex->GetRTV(), nullptr); - D3D::SetPointCopySampler(); - - D3D::drawShadedTexQuad( - FramebufferManager::GetEFBColorTexture()->GetSRV(), &rect, g_renderer->GetTargetWidth(), - g_renderer->GetTargetHeight(), PixelShaderCache::GetColorCopyProgram(true), - VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout(), - GeometryShaderCache::GetCopyGeometryShader(), Gamma); - - FramebufferManager::BindEFBRenderTarget(); - g_renderer->RestoreAPIState(); -} - } // namespace DX11 diff --git a/Source/Core/VideoBackends/D3D/FramebufferManager.h b/Source/Core/VideoBackends/D3D/FramebufferManager.h index 96e76118ee..f8767a2c5d 100644 --- a/Source/Core/VideoBackends/D3D/FramebufferManager.h +++ b/Source/Core/VideoBackends/D3D/FramebufferManager.h @@ -46,16 +46,6 @@ namespace DX11 // There may be multiple XFBs in GameCube RAM. This is the maximum number to // virtualize. -struct XFBSource : public XFBSourceBase -{ - XFBSource(D3DTexture2D* _tex, int slices) : tex(_tex), m_slices(slices) {} - ~XFBSource() { tex->Release(); } - void CopyEFB(float Gamma) override; - - D3DTexture2D* const tex; - const int m_slices; -}; - class FramebufferManager : public FramebufferManagerBase { public: @@ -79,14 +69,6 @@ public: static void BindEFBRenderTarget(bool bind_depth = true); private: - std::unique_ptr CreateXFBSource(unsigned int target_width, - unsigned int target_height, - unsigned int layers) override; - std::pair GetTargetSize() const override; - - void CopyToRealXFB(u32 xfbAddr, u32 fbStride, u32 fbHeight, const EFBRectangle& sourceRc, - float Gamma) override; - static struct Efb { D3DTexture2D* color_tex; diff --git a/Source/Core/VideoBackends/D3D/Render.cpp b/Source/Core/VideoBackends/D3D/Render.cpp index e49dc4053a..18aec69490 100644 --- a/Source/Core/VideoBackends/D3D/Render.cpp +++ b/Source/Core/VideoBackends/D3D/Render.cpp @@ -610,11 +610,6 @@ void Renderer::SetBlendingState(const BlendingState& state) // This function has the final picture. We adjust the aspect ratio here. void Renderer::SwapImpl(AbstractTexture* texture, const EFBRectangle& rc, u64 ticks, float Gamma) { - if (!m_xfb_written) - { - Core::Callback_VideoCopiedToXFB(false); - } - ResetAPIState(); // Prepare to copy the XFBs to our backbuffer diff --git a/Source/Core/VideoBackends/D3D/XFBEncoder.cpp b/Source/Core/VideoBackends/D3D/XFBEncoder.cpp deleted file mode 100644 index 696c5c35e0..0000000000 --- a/Source/Core/VideoBackends/D3D/XFBEncoder.cpp +++ /dev/null @@ -1,367 +0,0 @@ -// Copyright 2011 Dolphin Emulator Project -// Licensed under GPLv2+ -// Refer to the license.txt file included. - -#include "VideoBackends/D3D/XFBEncoder.h" -#include "Common/CommonTypes.h" -#include "Common/Logging/Log.h" -#include "Common/MsgHandler.h" -#include "VideoBackends/D3D/D3DBase.h" -#include "VideoBackends/D3D/D3DBlob.h" -#include "VideoBackends/D3D/D3DShader.h" -#include "VideoBackends/D3D/D3DState.h" -#include "VideoBackends/D3D/FramebufferManager.h" -#include "VideoBackends/D3D/Render.h" - -namespace DX11 -{ -union XFBEncodeParams -{ - struct - { - FLOAT Width; // Width and height of encoded XFB in luma pixels - FLOAT Height; - FLOAT TexLeft; // Normalized tex coordinates of XFB source area in EFB texture - FLOAT TexTop; - FLOAT TexRight; - FLOAT TexBottom; - FLOAT Gamma; - }; - // Constant buffers must be a multiple of 16 bytes in size - u8 pad[32]; // Pad to the next multiple of 16 -}; - -static const char XFB_ENCODE_VS[] = - "// dolphin-emu XFB encoder vertex shader\n" - - "cbuffer cbParams : register(b0)\n" - "{\n" - "struct\n" // Should match XFBEncodeParams above - "{\n" - "float Width;\n" - "float Height;\n" - "float TexLeft;\n" - "float TexTop;\n" - "float TexRight;\n" - "float TexBottom;\n" - "float Gamma;\n" - "} Params;\n" - "}\n" - - "struct Output\n" - "{\n" - "float4 Pos : SV_Position;\n" - "float2 Coord : ENCODECOORD;\n" - "};\n" - - "Output main(in float2 Pos : POSITION)\n" - "{\n" - "Output result;\n" - "result.Pos = float4(2*Pos.x-1, -2*Pos.y+1, 0, 1);\n" - "result.Coord = Pos * float2(floor(Params.Width/2), Params.Height);\n" - "return result;\n" - "}\n"; - -static const char XFB_ENCODE_PS[] = - "// dolphin-emu XFB encoder pixel shader\n" - - "cbuffer cbParams : register(b0)\n" - "{\n" - "struct\n" // Should match XFBEncodeParams above - "{\n" - "float Width;\n" - "float Height;\n" - "float TexLeft;\n" - "float TexTop;\n" - "float TexRight;\n" - "float TexBottom;\n" - "float Gamma;\n" - "} Params;\n" - "}\n" - - "Texture2DArray EFBTexture : register(t0);\n" - "sampler EFBSampler : register(s0);\n" - - // GameCube/Wii uses the BT.601 standard algorithm for converting to YCbCr; see - // - "static const float3x4 RGB_TO_YCBCR = float3x4(\n" - "0.257, 0.504, 0.098, 16.0/255.0,\n" - "-0.148, -0.291, 0.439, 128.0/255.0,\n" - "0.439, -0.368, -0.071, 128.0/255.0\n" - ");\n" - - "float3 SampleEFB(float2 coord)\n" - "{\n" - "float2 texCoord = lerp(float2(Params.TexLeft,Params.TexTop), " - "float2(Params.TexRight,Params.TexBottom), coord / float2(Params.Width,Params.Height));\n" - "return EFBTexture.Sample(EFBSampler, float3(texCoord, 0.0)).rgb;\n" - "}\n" - - "void main(out float4 ocol0 : SV_Target, in float4 Pos : SV_Position, in float2 Coord : " - "ENCODECOORD)\n" - "{\n" - // Multiplying X by 2, moves pixel centers from (x+0.5) to (2x+1) instead of (2x+0.5), so - // subtract 0.5 to compensate - "float2 baseCoord = Coord * float2(2,1) - float2(0.5,0);\n" - // FIXME: Shall we apply gamma here, or apply it below to the Y components? - // Be careful if you apply it to Y! The Y components are in the range (16..235) / 255. - "float3 sampleL = pow(abs(SampleEFB(baseCoord+float2(-1,0))), Params.Gamma);\n" // Left - "float3 sampleM = pow(abs(SampleEFB(baseCoord)), Params.Gamma);\n" // Middle - "float3 sampleR = pow(abs(SampleEFB(baseCoord+float2(1,0))), Params.Gamma);\n" // Right - - "float3 yuvL = mul(RGB_TO_YCBCR, float4(sampleL,1));\n" - "float3 yuvM = mul(RGB_TO_YCBCR, float4(sampleM,1));\n" - "float3 yuvR = mul(RGB_TO_YCBCR, float4(sampleR,1));\n" - - // The Y components correspond to two EFB pixels, while the U and V are - // made from a blend of three EFB pixels. - "float y0 = yuvM.r;\n" - "float y1 = yuvR.r;\n" - "float u0 = 0.25*yuvL.g + 0.5*yuvM.g + 0.25*yuvR.g;\n" - "float v0 = 0.25*yuvL.b + 0.5*yuvM.b + 0.25*yuvR.b;\n" - - "ocol0 = float4(y0, u0, y1, v0);\n" - "}\n"; - -static const D3D11_INPUT_ELEMENT_DESC QUAD_LAYOUT_DESC[] = { - {"POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0}}; - -static const struct QuadVertex -{ - float posX; - float posY; -} QUAD_VERTS[4] = {{0, 0}, {1, 0}, {0, 1}, {1, 1}}; - -XFBEncoder::XFBEncoder() - : m_out(nullptr), m_outRTV(nullptr), m_outStage(nullptr), m_encodeParams(nullptr), - m_quad(nullptr), m_vShader(nullptr), m_quadLayout(nullptr), m_pShader(nullptr), - m_xfbEncodeBlendState(nullptr), m_xfbEncodeDepthState(nullptr), m_xfbEncodeRastState(nullptr), - m_efbSampler(nullptr) -{ -} - -void XFBEncoder::Init() -{ - HRESULT hr; - - // Create output texture - - // The pixel shader can generate one YUYV entry per pixel. One YUYV entry - // is created for every two EFB pixels. - D3D11_TEXTURE2D_DESC t2dd = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM, MAX_XFB_WIDTH / 2, - MAX_XFB_HEIGHT, 1, 1, D3D11_BIND_RENDER_TARGET); - hr = D3D::device->CreateTexture2D(&t2dd, nullptr, &m_out); - CHECK(SUCCEEDED(hr), "create xfb encoder output texture"); - D3D::SetDebugObjectName(m_out, "xfb encoder output texture"); - - // Create output render target view - - D3D11_RENDER_TARGET_VIEW_DESC rtvd = CD3D11_RENDER_TARGET_VIEW_DESC( - m_out, D3D11_RTV_DIMENSION_TEXTURE2D, DXGI_FORMAT_R8G8B8A8_UNORM); - hr = D3D::device->CreateRenderTargetView(m_out, &rtvd, &m_outRTV); - CHECK(SUCCEEDED(hr), "create xfb encoder output texture rtv"); - D3D::SetDebugObjectName(m_outRTV, "xfb encoder output rtv"); - - // Create output staging buffer - - t2dd.Usage = D3D11_USAGE_STAGING; - t2dd.BindFlags = 0; - t2dd.CPUAccessFlags = D3D11_CPU_ACCESS_READ; - hr = D3D::device->CreateTexture2D(&t2dd, nullptr, &m_outStage); - CHECK(SUCCEEDED(hr), "create xfb encoder output staging buffer"); - D3D::SetDebugObjectName(m_outStage, "xfb encoder output staging buffer"); - - // Create constant buffer for uploading params to shaders - - D3D11_BUFFER_DESC bd = CD3D11_BUFFER_DESC(sizeof(XFBEncodeParams), D3D11_BIND_CONSTANT_BUFFER); - hr = D3D::device->CreateBuffer(&bd, nullptr, &m_encodeParams); - CHECK(SUCCEEDED(hr), "create xfb encode params buffer"); - D3D::SetDebugObjectName(m_encodeParams, "xfb encoder params buffer"); - - // Create vertex quad - - bd = CD3D11_BUFFER_DESC(sizeof(QUAD_VERTS), D3D11_BIND_VERTEX_BUFFER, D3D11_USAGE_IMMUTABLE); - D3D11_SUBRESOURCE_DATA srd = {QUAD_VERTS, 0, 0}; - - hr = D3D::device->CreateBuffer(&bd, &srd, &m_quad); - CHECK(SUCCEEDED(hr), "create xfb encode quad vertex buffer"); - D3D::SetDebugObjectName(m_quad, "xfb encoder quad vertex buffer"); - - // Create vertex shader - - D3DBlob* bytecode = nullptr; - if (!D3D::CompileVertexShader(XFB_ENCODE_VS, &bytecode)) - { - ERROR_LOG(VIDEO, "XFB encode vertex shader failed to compile"); - return; - } - - hr = D3D::device->CreateVertexShader(bytecode->Data(), bytecode->Size(), nullptr, &m_vShader); - CHECK(SUCCEEDED(hr), "create xfb encode vertex shader"); - D3D::SetDebugObjectName(m_vShader, "xfb encoder vertex shader"); - - // Create input layout for vertex quad using bytecode from vertex shader - - hr = D3D::device->CreateInputLayout(QUAD_LAYOUT_DESC, - sizeof(QUAD_LAYOUT_DESC) / sizeof(D3D11_INPUT_ELEMENT_DESC), - bytecode->Data(), bytecode->Size(), &m_quadLayout); - CHECK(SUCCEEDED(hr), "create xfb encode quad vertex layout"); - D3D::SetDebugObjectName(m_quadLayout, "xfb encoder quad layout"); - - bytecode->Release(); - - // Create pixel shader - - m_pShader = D3D::CompileAndCreatePixelShader(XFB_ENCODE_PS); - if (!m_pShader) - { - ERROR_LOG(VIDEO, "XFB encode pixel shader failed to compile"); - return; - } - D3D::SetDebugObjectName(m_pShader, "xfb encoder pixel shader"); - - // Create blend state - - D3D11_BLEND_DESC bld = CD3D11_BLEND_DESC(CD3D11_DEFAULT()); - hr = D3D::device->CreateBlendState(&bld, &m_xfbEncodeBlendState); - CHECK(SUCCEEDED(hr), "create xfb encode blend state"); - D3D::SetDebugObjectName(m_xfbEncodeBlendState, "xfb encoder blend state"); - - // Create depth state - - D3D11_DEPTH_STENCIL_DESC dsd = CD3D11_DEPTH_STENCIL_DESC(CD3D11_DEFAULT()); - dsd.DepthEnable = FALSE; - hr = D3D::device->CreateDepthStencilState(&dsd, &m_xfbEncodeDepthState); - CHECK(SUCCEEDED(hr), "create xfb encode depth state"); - D3D::SetDebugObjectName(m_xfbEncodeDepthState, "xfb encoder depth state"); - - // Create rasterizer state - - D3D11_RASTERIZER_DESC rd = CD3D11_RASTERIZER_DESC(CD3D11_DEFAULT()); - rd.CullMode = D3D11_CULL_NONE; - rd.DepthClipEnable = FALSE; - hr = D3D::device->CreateRasterizerState(&rd, &m_xfbEncodeRastState); - CHECK(SUCCEEDED(hr), "create xfb encode rasterizer state"); - D3D::SetDebugObjectName(m_xfbEncodeRastState, "xfb encoder rast state"); - - // Create EFB texture sampler - - D3D11_SAMPLER_DESC sd = CD3D11_SAMPLER_DESC(CD3D11_DEFAULT()); - sd.Filter = D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT; - hr = D3D::device->CreateSamplerState(&sd, &m_efbSampler); - CHECK(SUCCEEDED(hr), "create xfb encode texture sampler"); - D3D::SetDebugObjectName(m_efbSampler, "xfb encoder texture sampler"); -} - -void XFBEncoder::Shutdown() -{ - SAFE_RELEASE(m_efbSampler); - SAFE_RELEASE(m_xfbEncodeRastState); - SAFE_RELEASE(m_xfbEncodeDepthState); - SAFE_RELEASE(m_xfbEncodeBlendState); - SAFE_RELEASE(m_pShader); - SAFE_RELEASE(m_quadLayout); - SAFE_RELEASE(m_vShader); - SAFE_RELEASE(m_quad); - SAFE_RELEASE(m_encodeParams); - SAFE_RELEASE(m_outStage); - SAFE_RELEASE(m_outRTV); - SAFE_RELEASE(m_out); -} - -void XFBEncoder::Encode(u8* dst, u32 width, u32 height, const EFBRectangle& srcRect, float gamma) -{ - HRESULT hr; - - // Reset API - - g_renderer->ResetAPIState(); - - // Set up all the state for XFB encoding - - D3D::stateman->SetPixelShader(m_pShader); - D3D::stateman->SetVertexShader(m_vShader); - D3D::stateman->SetGeometryShader(nullptr); - - D3D::stateman->PushBlendState(m_xfbEncodeBlendState); - D3D::stateman->PushDepthState(m_xfbEncodeDepthState); - D3D::stateman->PushRasterizerState(m_xfbEncodeRastState); - - D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, FLOAT(width / 2), FLOAT(height)); - D3D::context->RSSetViewports(1, &vp); - - D3D::stateman->SetInputLayout(m_quadLayout); - D3D::stateman->SetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); - UINT stride = sizeof(QuadVertex); - UINT offset = 0; - D3D::stateman->SetVertexBuffer(m_quad, stride, offset); - - TargetRectangle targetRect = g_renderer->ConvertEFBRectangle(srcRect); - - XFBEncodeParams params = {0}; - params.Width = FLOAT(width); - params.Height = FLOAT(height); - params.TexLeft = FLOAT(targetRect.left) / g_renderer->GetTargetWidth(); - params.TexTop = FLOAT(targetRect.top) / g_renderer->GetTargetHeight(); - params.TexRight = FLOAT(targetRect.right) / g_renderer->GetTargetWidth(); - params.TexBottom = FLOAT(targetRect.bottom) / g_renderer->GetTargetHeight(); - params.Gamma = gamma; - D3D::context->UpdateSubresource(m_encodeParams, 0, nullptr, ¶ms, 0, 0); - - D3D::context->OMSetRenderTargets(1, &m_outRTV, nullptr); - - ID3D11ShaderResourceView* pEFB = FramebufferManager::GetResolvedEFBColorTexture()->GetSRV(); - - D3D::stateman->SetVertexConstants(m_encodeParams); - D3D::stateman->SetPixelConstants(m_encodeParams); - D3D::stateman->SetTexture(0, pEFB); - D3D::stateman->SetSampler(0, m_efbSampler); - - // Encode! - - D3D::stateman->Apply(); - D3D::context->Draw(4, 0); - - // Copy to staging buffer - - D3D11_BOX srcBox = CD3D11_BOX(0, 0, 0, width / 2, height, 1); - D3D::context->CopySubresourceRegion(m_outStage, 0, 0, 0, 0, m_out, 0, &srcBox); - - // Clean up state - - D3D::context->OMSetRenderTargets(0, nullptr, nullptr); - - D3D::stateman->SetSampler(0, nullptr); - D3D::stateman->SetTexture(0, nullptr); - D3D::stateman->SetPixelConstants(nullptr); - D3D::stateman->SetVertexConstants(nullptr); - - D3D::stateman->SetPixelShader(nullptr); - D3D::stateman->SetVertexShader(nullptr); - - D3D::stateman->PopRasterizerState(); - D3D::stateman->PopDepthState(); - D3D::stateman->PopBlendState(); - - // Transfer staging buffer to GameCube/Wii RAM - - D3D11_MAPPED_SUBRESOURCE map = {0}; - hr = D3D::context->Map(m_outStage, 0, D3D11_MAP_READ, 0, &map); - CHECK(SUCCEEDED(hr), "map staging buffer"); - - u8* src = (u8*)map.pData; - for (unsigned int y = 0; y < height; ++y) - { - memcpy(dst, src, 2 * width); - dst += bpmem.copyMipMapStrideChannels * 32; - src += map.RowPitch; - } - - D3D::context->Unmap(m_outStage, 0); - - // Restore API - g_renderer->RestoreAPIState(); - D3D::stateman->Apply(); // force unbind efb texture as shader resource - FramebufferManager::BindEFBRenderTarget(); -} -} diff --git a/Source/Core/VideoBackends/D3D/XFBEncoder.h b/Source/Core/VideoBackends/D3D/XFBEncoder.h deleted file mode 100644 index 91da877b8b..0000000000 --- a/Source/Core/VideoBackends/D3D/XFBEncoder.h +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2011 Dolphin Emulator Project -// Licensed under GPLv2+ -// Refer to the license.txt file included. - -#pragma once - -#include "VideoCommon/VideoCommon.h" - -struct ID3D11Texture2D; -struct ID3D11RenderTargetView; -struct ID3D11Buffer; -struct ID3D11VertexShader; -struct ID3D11PixelShader; -struct ID3D11InputLayout; -struct ID3D11BlendState; -struct ID3D11DepthStencilState; -struct ID3D11RasterizerState; -struct ID3D11SamplerState; - -namespace DX11 -{ -class XFBEncoder -{ -public: - XFBEncoder(); - - void Init(); - void Shutdown(); - - void Encode(u8* dst, u32 width, u32 height, const EFBRectangle& srcRect, float gamma); - -private: - ID3D11Texture2D* m_out; - ID3D11RenderTargetView* m_outRTV; - ID3D11Texture2D* m_outStage; - ID3D11Buffer* m_encodeParams; - ID3D11Buffer* m_quad; - ID3D11VertexShader* m_vShader; - ID3D11InputLayout* m_quadLayout; - ID3D11PixelShader* m_pShader; - ID3D11BlendState* m_xfbEncodeBlendState; - ID3D11DepthStencilState* m_xfbEncodeDepthState; - ID3D11RasterizerState* m_xfbEncodeRastState; - ID3D11SamplerState* m_efbSampler; -}; -} diff --git a/Source/Core/VideoBackends/Null/FramebufferManager.h b/Source/Core/VideoBackends/Null/FramebufferManager.h deleted file mode 100644 index 0419ee36f8..0000000000 --- a/Source/Core/VideoBackends/Null/FramebufferManager.h +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2015 Dolphin Emulator Project -// Licensed under GPLv2+ -// Refer to the license.txt file included. - -#pragma once - -#include - -#include "Common/CommonTypes.h" -#include "VideoCommon/FramebufferManagerBase.h" - -class XFBSource : public XFBSourceBase -{ -public: - void CopyEFB(float gamma) override {} -}; - -class FramebufferManager : public FramebufferManagerBase -{ -public: - std::unique_ptr CreateXFBSource(unsigned int target_width, - unsigned int target_height, - unsigned int layers) override - { - return std::make_unique(); - } - - std::pair GetTargetSize() const override { return std::make_pair(0, 0); } - void CopyToRealXFB(u32 xfb_addr, u32 fb_stride, u32 fb_height, const EFBRectangle& source_rc, - float gamma = 1.0f) override - { - } -}; diff --git a/Source/Core/VideoBackends/Null/Null.vcxproj b/Source/Core/VideoBackends/Null/Null.vcxproj index 178575ef81..664488035e 100644 --- a/Source/Core/VideoBackends/Null/Null.vcxproj +++ b/Source/Core/VideoBackends/Null/Null.vcxproj @@ -43,7 +43,6 @@ - diff --git a/Source/Core/VideoBackends/Null/NullBackend.cpp b/Source/Core/VideoBackends/Null/NullBackend.cpp index 2a52fe7172..1bb8d6248e 100644 --- a/Source/Core/VideoBackends/Null/NullBackend.cpp +++ b/Source/Core/VideoBackends/Null/NullBackend.cpp @@ -7,7 +7,6 @@ // This backend tries not to do anything in the backend, // but everything in VideoCommon. -#include "VideoBackends/Null/FramebufferManager.h" #include "VideoBackends/Null/PerfQuery.h" #include "VideoBackends/Null/Render.h" #include "VideoBackends/Null/ShaderCache.h" @@ -15,6 +14,7 @@ #include "VideoBackends/Null/VertexManager.h" #include "VideoBackends/Null/VideoBackend.h" +#include "VideoCommon/FramebufferManagerBase.h" #include "VideoCommon/VideoBackendBase.h" #include "VideoCommon/VideoCommon.h" #include "VideoCommon/VideoConfig.h" @@ -68,7 +68,7 @@ void VideoBackend::Video_Prepare() g_renderer = std::make_unique(); g_vertex_manager = std::make_unique(); g_perf_query = std::make_unique(); - g_framebuffer_manager = std::make_unique(); + g_framebuffer_manager = std::make_unique(); g_texture_cache = std::make_unique(); VertexShaderCache::s_instance = std::make_unique(); GeometryShaderCache::s_instance = std::make_unique(); diff --git a/Source/Core/VideoBackends/OGL/FramebufferManager.cpp b/Source/Core/VideoBackends/OGL/FramebufferManager.cpp index 77ef205f2a..a670a47111 100644 --- a/Source/Core/VideoBackends/OGL/FramebufferManager.cpp +++ b/Source/Core/VideoBackends/OGL/FramebufferManager.cpp @@ -33,7 +33,6 @@ bool FramebufferManager::m_enable_stencil_buffer; GLenum FramebufferManager::m_textureType; std::vector FramebufferManager::m_efbFramebuffer; -GLuint FramebufferManager::m_xfbFramebuffer; GLuint FramebufferManager::m_efbColor; GLuint FramebufferManager::m_efbDepth; GLuint FramebufferManager::m_efbColorSwap; // for hot swap when reinterpreting EFB pixel formats @@ -110,7 +109,6 @@ bool FramebufferManager::HasStencilBuffer() FramebufferManager::FramebufferManager(int targetWidth, int targetHeight, int msaaSamples, bool enable_stencil_buffer) { - m_xfbFramebuffer = 0; m_efbColor = 0; m_efbDepth = 0; m_efbColorSwap = 0; @@ -189,9 +187,6 @@ FramebufferManager::FramebufferManager(int targetWidth, int targetHeight, int ms CreateTexture(m_textureType, depth_internal_format, depth_pixel_format, depth_data_type); m_efbColorSwap = CreateTexture(m_textureType, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE); - // Create XFB framebuffer; targets will be created elsewhere. - glGenFramebuffers(1, &m_xfbFramebuffer); - // Bind target textures to EFB framebuffer. glGenFramebuffers(m_EFBLayers, m_efbFramebuffer.data()); BindLayeredTexture(m_efbColor, m_efbFramebuffer, GL_COLOR_ATTACHMENT0, m_textureType); @@ -419,9 +414,6 @@ FramebufferManager::~FramebufferManager() m_efbFramebuffer.clear(); m_resolvedFramebuffer.clear(); - glDeleteFramebuffers(1, &m_xfbFramebuffer); - m_xfbFramebuffer = 0; - glObj[0] = m_resolvedColorTexture; glObj[1] = m_resolvedDepthTexture; glDeleteTextures(2, glObj); @@ -527,21 +519,6 @@ void FramebufferManager::ResolveEFBStencilTexture() glBindFramebuffer(GL_FRAMEBUFFER, m_efbFramebuffer[0]); } -void FramebufferManager::CopyToRealXFB(u32 xfbAddr, u32 fbStride, u32 fbHeight, - const EFBRectangle& sourceRc, float Gamma) -{ -/* u8* xfb_in_ram = Memory::GetPointer(xfbAddr); - if (!xfb_in_ram) - { - WARN_LOG(VIDEO, "Tried to copy to invalid XFB address"); - return; - } - - TargetRectangle targetRc = g_renderer->ConvertEFBRectangle(sourceRc); - TextureConverter::EncodeToRamYUYV(ResolveAndGetRenderTarget(sourceRc), targetRc, xfb_in_ram, - sourceRc.GetWidth(), fbStride, fbHeight);*/ -} - GLuint FramebufferManager::GetResolvedFramebuffer() { if (m_msaaSamples <= 1) @@ -610,56 +587,6 @@ void FramebufferManager::ReinterpretPixelData(unsigned int convtype) g_renderer->RestoreAPIState(); } -XFBSource::~XFBSource() -{ - glDeleteTextures(1, &texture); -} - -void XFBSource::CopyEFB(float Gamma) -{ - g_renderer->ResetAPIState(); - - // Copy EFB data to XFB and restore render target again - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, FramebufferManager::GetXFBFramebuffer()); - - for (int i = 0; i < m_layers; i++) - { - // Bind EFB and texture layer - glBindFramebuffer(GL_READ_FRAMEBUFFER, FramebufferManager::GetEFBFramebuffer(i)); - glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, 0, i); - - glBlitFramebuffer(0, 0, texWidth, texHeight, 0, 0, texWidth, texHeight, GL_COLOR_BUFFER_BIT, - GL_NEAREST); - } - - // Return to EFB. - FramebufferManager::SetFramebuffer(0); - - g_renderer->RestoreAPIState(); -} - -std::unique_ptr FramebufferManager::CreateXFBSource(unsigned int target_width, - unsigned int target_height, - unsigned int layers) -{ - GLuint texture; - - glGenTextures(1, &texture); - - glActiveTexture(GL_TEXTURE9); - glBindTexture(GL_TEXTURE_2D_ARRAY, texture); - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_LEVEL, 0); - glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA, target_width, target_height, layers, 0, GL_RGBA, - GL_UNSIGNED_BYTE, nullptr); - - return std::make_unique(texture, layers); -} - -std::pair FramebufferManager::GetTargetSize() const -{ - return std::make_pair(m_targetWidth, m_targetHeight); -} - void FramebufferManager::PokeEFB(EFBAccessType type, const EfbPokeData* points, size_t num_points) { g_renderer->ResetAPIState(); diff --git a/Source/Core/VideoBackends/OGL/FramebufferManager.h b/Source/Core/VideoBackends/OGL/FramebufferManager.h index 1d3626af36..f68556bf90 100644 --- a/Source/Core/VideoBackends/OGL/FramebufferManager.h +++ b/Source/Core/VideoBackends/OGL/FramebufferManager.h @@ -48,17 +48,6 @@ namespace OGL { -struct XFBSource : public XFBSourceBase -{ - XFBSource(GLuint tex, int layers) : texture(tex), m_layers(layers) {} - ~XFBSource(); - - void CopyEFB(float Gamma) override; - - const GLuint texture; - const int m_layers; -}; - class FramebufferManager : public FramebufferManagerBase { public: @@ -76,7 +65,6 @@ public: { return (layer < m_EFBLayers) ? m_efbFramebuffer[layer] : m_efbFramebuffer.back(); } - static GLuint GetXFBFramebuffer() { return m_xfbFramebuffer; } // Resolved framebuffer is only used in MSAA mode. static GLuint GetResolvedFramebuffer(); static void SetFramebuffer(GLuint fb); @@ -108,13 +96,6 @@ private: GLenum data_type); void BindLayeredTexture(GLuint texture, const std::vector& framebuffers, GLenum attachment, GLenum texture_type); - std::unique_ptr CreateXFBSource(unsigned int target_width, - unsigned int target_height, - unsigned int layers) override; - std::pair GetTargetSize() const override; - - void CopyToRealXFB(u32 xfbAddr, u32 fbStride, u32 fbHeight, const EFBRectangle& sourceRc, - float Gamma) override; static int m_targetWidth; static int m_targetHeight; @@ -122,7 +103,6 @@ private: static GLenum m_textureType; static std::vector m_efbFramebuffer; - static GLuint m_xfbFramebuffer; static GLuint m_efbColor; static GLuint m_efbDepth; static GLuint diff --git a/Source/Core/VideoBackends/OGL/Render.cpp b/Source/Core/VideoBackends/OGL/Render.cpp index e426b97ef6..655b69cb4e 100644 --- a/Source/Core/VideoBackends/OGL/Render.cpp +++ b/Source/Core/VideoBackends/OGL/Render.cpp @@ -790,12 +790,7 @@ Renderer::Renderer() ClearEFBCache(); } -Renderer::~Renderer() -{ - FlushFrameDump(); - //FinishFrameData(); - DestroyFrameDumpResources(); -} +Renderer::~Renderer() = default; void Renderer::Shutdown() { @@ -1360,27 +1355,6 @@ void Renderer::SwapImpl(AbstractTexture* texture, const EFBRectangle& rc, u64 ti glBindFramebuffer(GL_FRAMEBUFFER, 0); BlitScreen(sourceRc, flipped_trc, xfb_texture->GetRawTexIdentifier(), xfb_texture->GetConfig().width, xfb_texture->GetConfig().height); - // The FlushFrameDump call here is necessary even after frame dumping is stopped. - // If left out, screenshots are "one frame" behind, as an extra frame is dumped and buffered. - /*FlushFrameDump(); - if (IsFrameDumping()) - { - // Currently, we only use the off-screen buffer as a frame dump source if full-resolution - // frame dumping is enabled, saving the need for an extra copy. In the future, this could - // be extended to be used for surfaceless contexts as well. - bool use_offscreen_buffer = g_ActiveConfig.bInternalResolutionFrameDumps; - if (use_offscreen_buffer) - { - // DumpFrameUsingFBO resets GL_FRAMEBUFFER, so change back to the window for drawing OSD. - DumpFrameUsingFBO(sourceRc, ticks); - } - else - { - // GL_READ_FRAMEBUFFER is set by GL_FRAMEBUFFER in DrawFrame -> Draw{EFB,VirtualXFB,RealXFB}. - DumpFrame(flipped_trc, ticks); - } - }*/ - // Finish up the current frame, print some stats SetWindowSize(xfb_texture->GetConfig().width, xfb_texture->GetConfig().height); @@ -1509,134 +1483,6 @@ void Renderer::DrawEFB(GLuint framebuffer, const TargetRectangle& target_rc, BlitScreen(source_rc, target_rc, tex, m_target_width, m_target_height); } -void Renderer::FlushFrameDump() -{ - /*if (!m_last_frame_exported) - return; - - FinishFrameData(); - glBindBuffer(GL_PIXEL_PACK_BUFFER, m_frame_dumping_pbo[0]); - m_frame_pbo_is_mapped[0] = true; - void* data = glMapBufferRange( - GL_PIXEL_PACK_BUFFER, 0, m_last_frame_width[0] * m_last_frame_height[0] * 4, GL_MAP_READ_BIT); - DumpFrameData(reinterpret_cast(data), m_last_frame_width[0], m_last_frame_height[0], - m_last_frame_width[0] * 4, m_last_frame_state, true); - glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); - m_last_frame_exported = false;*/ -} - -void Renderer::DumpFrame(const TargetRectangle& flipped_trc, u64 ticks) -{ - if (!m_frame_dumping_pbo[0]) - { - glGenBuffers(2, m_frame_dumping_pbo.data()); - glBindBuffer(GL_PIXEL_PACK_BUFFER, m_frame_dumping_pbo[0]); - } - else - { - FlushFrameDump(); - std::swap(m_frame_dumping_pbo[0], m_frame_dumping_pbo[1]); - std::swap(m_frame_pbo_is_mapped[0], m_frame_pbo_is_mapped[1]); - std::swap(m_last_frame_width[0], m_last_frame_width[1]); - std::swap(m_last_frame_height[0], m_last_frame_height[1]); - glBindBuffer(GL_PIXEL_PACK_BUFFER, m_frame_dumping_pbo[0]); - if (m_frame_pbo_is_mapped[0]) - glUnmapBuffer(GL_PIXEL_PACK_BUFFER); - m_frame_pbo_is_mapped[0] = false; - } - - if (flipped_trc.GetWidth() != m_last_frame_width[0] || - flipped_trc.GetHeight() != m_last_frame_height[0]) - { - m_last_frame_width[0] = flipped_trc.GetWidth(); - m_last_frame_height[0] = flipped_trc.GetHeight(); - glBufferData(GL_PIXEL_PACK_BUFFER, m_last_frame_width[0] * m_last_frame_height[0] * 4, nullptr, - GL_STREAM_READ); - } - - m_last_frame_state = AVIDump::FetchState(ticks); - m_last_frame_exported = true; - - glPixelStorei(GL_PACK_ALIGNMENT, 1); - glReadPixels(flipped_trc.left, flipped_trc.bottom, m_last_frame_width[0], m_last_frame_height[0], - GL_RGBA, GL_UNSIGNED_BYTE, 0); - glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); -} - -void Renderer::DumpFrameUsingFBO(const TargetRectangle& source_rc, u64 ticks) -{ - // This needs to be converted to the GL bottom-up window coordinate system. - TargetRectangle render_rc = CalculateFrameDumpDrawRectangle(); - std::swap(render_rc.top, render_rc.bottom); - - // Ensure the render texture meets the size requirements of the draw area. - u32 render_width = static_cast(render_rc.GetWidth()); - u32 render_height = static_cast(render_rc.GetHeight()); - PrepareFrameDumpRenderTexture(render_width, render_height); - - // Ensure the alpha channel of the render texture is blank. The frame dump backend expects - // that the alpha is set to 1.0 for all pixels. - glBindFramebuffer(GL_FRAMEBUFFER, m_frame_dump_render_framebuffer); - glClearColor(0.0f, 0.0f, 0.0f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT); - - // Render the frame into the frame dump render texture. Disable alpha writes in case the - // post-processing shader writes a non-1.0 value. - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE); - DrawEFB(m_frame_dump_render_framebuffer, render_rc, source_rc); - - // Copy frame to output buffer. This assumes that GL_FRAMEBUFFER has been set. - DumpFrame(render_rc, ticks); - - // Restore state after drawing. This isn't the game state, it's the state set by ResetAPIState. - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - glBindFramebuffer(GL_FRAMEBUFFER, 0); -} - -void Renderer::PrepareFrameDumpRenderTexture(u32 width, u32 height) -{ - // Ensure framebuffer exists (we lazily allocate it in case frame dumping isn't used). - // Or, resize texture if it isn't large enough to accommodate the current frame. - if (m_frame_dump_render_texture != 0 && m_frame_dump_render_framebuffer != 0 && - m_frame_dump_render_texture_width >= width && m_frame_dump_render_texture_height >= height) - { - return; - } - - // Recreate texture objects. - if (m_frame_dump_render_texture != 0) - glDeleteTextures(1, &m_frame_dump_render_texture); - if (m_frame_dump_render_framebuffer != 0) - glDeleteFramebuffers(1, &m_frame_dump_render_framebuffer); - - glGenTextures(1, &m_frame_dump_render_texture); - glActiveTexture(GL_TEXTURE9); - glBindTexture(GL_TEXTURE_2D, m_frame_dump_render_texture); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); - - glGenFramebuffers(1, &m_frame_dump_render_framebuffer); - FramebufferManager::SetFramebuffer(m_frame_dump_render_framebuffer); - FramebufferManager::FramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, - m_frame_dump_render_texture, 0); - - m_frame_dump_render_texture_width = width; - m_frame_dump_render_texture_height = height; - OGLTexture::SetStage(); -} - -void Renderer::DestroyFrameDumpResources() -{ - if (m_frame_dump_render_framebuffer) - glDeleteFramebuffers(1, &m_frame_dump_render_framebuffer); - if (m_frame_dump_render_texture) - glDeleteTextures(1, &m_frame_dump_render_texture); - if (m_frame_dumping_pbo[0]) - glDeleteBuffers(2, m_frame_dumping_pbo.data()); -} - // ALWAYS call RestoreAPIState for each ResetAPIState call you're doing void Renderer::ResetAPIState() { diff --git a/Source/Core/VideoBackends/OGL/Render.h b/Source/Core/VideoBackends/OGL/Render.h index d71ad15bd1..78d680fbd2 100644 --- a/Source/Core/VideoBackends/OGL/Render.h +++ b/Source/Core/VideoBackends/OGL/Render.h @@ -4,7 +4,6 @@ #pragma once -#include #include #include "Common/GL/GLUtil.h" @@ -116,25 +115,5 @@ private: void BlitScreen(TargetRectangle src, TargetRectangle dst, GLuint src_texture, int src_width, int src_height); - - void FlushFrameDump(); - void DumpFrame(const TargetRectangle& flipped_trc, u64 ticks); - void DumpFrameUsingFBO(const TargetRectangle& source_rc, u64 ticks); - - // Frame dumping framebuffer, we render to this, then read it back - void PrepareFrameDumpRenderTexture(u32 width, u32 height); - void DestroyFrameDumpResources(); - GLuint m_frame_dump_render_texture = 0; - GLuint m_frame_dump_render_framebuffer = 0; - u32 m_frame_dump_render_texture_width = 0; - u32 m_frame_dump_render_texture_height = 0; - - // avi dumping state to delay one frame - std::array m_frame_dumping_pbo = {}; - std::array m_frame_pbo_is_mapped = {}; - std::array m_last_frame_width = {}; - std::array m_last_frame_height = {}; - bool m_last_frame_exported = false; - AVIDump::Frame m_last_frame_state; }; } diff --git a/Source/Core/VideoBackends/OGL/TextureConverter.cpp b/Source/Core/VideoBackends/OGL/TextureConverter.cpp index 1fb55c8d24..a2460bf935 100644 --- a/Source/Core/VideoBackends/OGL/TextureConverter.cpp +++ b/Source/Core/VideoBackends/OGL/TextureConverter.cpp @@ -41,11 +41,6 @@ static GLuint s_dstTexture = 0; // for encoding to RAM const int renderBufferWidth = EFB_WIDTH * 4; const int renderBufferHeight = 1024; -static SHADER s_rgbToYuyvProgram; -static int s_rgbToYuyvUniform_loc; - -static SHADER s_yuyvToRgbProgram; - struct EncodingProgram { SHADER program; @@ -56,87 +51,6 @@ static std::map s_encoding_programs; static GLuint s_PBO = 0; // for readback with different strides -static void CreatePrograms() -{ - /* TODO: Accuracy Improvements - * - * This shader doesn't really match what the GameCube does internally in the - * copy pipeline. - * 1. It uses OpenGL's built in filtering when yscaling, someone could work - * out how the copypipeline does it's filtering and implement it correctly - * in this shader. - * 2. Deflickering isn't implemented, a futher filtering over 3 lines. - * Isn't really needed on non-interlaced monitors (and would lower quality; - * But hey, accuracy!) - * 3. Flipper's YUYV conversion implements a 3 pixel horizontal blur on the - * UV channels, centering the U channel on the Left pixel and the V channel - * on the Right pixel. - * The current implementation Centers both UV channels at the same place - * inbetween the two Pixels, and only blurs over these two pixels. - */ - // Output is BGRA because that is slightly faster than RGBA. - const char* VProgramRgbToYuyv = - "out vec2 uv0;\n" - "uniform vec4 copy_position;\n" // left, top, right, bottom - "SAMPLER_BINDING(9) uniform sampler2DArray samp9;\n" - "void main()\n" - "{\n" - " vec2 rawpos = vec2(gl_VertexID&1, gl_VertexID&2);\n" - " gl_Position = vec4(rawpos*2.0-1.0, 0.0, 1.0);\n" - " uv0 = mix(copy_position.xy, copy_position.zw, rawpos) / vec2(textureSize(samp9, 0).xy);\n" - "}\n"; - const char* FProgramRgbToYuyv = - "SAMPLER_BINDING(9) uniform sampler2DArray samp9;\n" - "in vec2 uv0;\n" - "out vec4 ocol0;\n" - "void main()\n" - "{\n" - " vec3 c0 = texture(samp9, vec3(uv0 - dFdx(uv0) * 0.25, 0.0)).rgb;\n" - " vec3 c1 = texture(samp9, vec3(uv0 + dFdx(uv0) * 0.25, 0.0)).rgb;\n" - " vec3 c01 = (c0 + c1) * 0.5;\n" - " vec3 y_const = vec3(0.257,0.504,0.098);\n" - " vec3 u_const = vec3(-0.148,-0.291,0.439);\n" - " vec3 v_const = vec3(0.439,-0.368,-0.071);\n" - " vec4 const3 = vec4(0.0625,0.5,0.0625,0.5);\n" - " ocol0 = vec4(dot(c1,y_const),dot(c01,u_const),dot(c0,y_const),dot(c01, v_const)) + " - "const3;\n" - "}\n"; - ProgramShaderCache::CompileShader(s_rgbToYuyvProgram, VProgramRgbToYuyv, FProgramRgbToYuyv); - s_rgbToYuyvUniform_loc = glGetUniformLocation(s_rgbToYuyvProgram.glprogid, "copy_position"); - - /* TODO: Accuracy Improvements - * - * The YVYU to RGB conversion here matches the RGB to YUYV done above, but - * if a game modifies or adds images to the XFB then it should be using the - * same algorithm as the flipper, and could result in slight color inaccuracies - * when run back through this shader. - */ - const char* VProgramYuyvToRgb = "void main()\n" - "{\n" - " vec2 rawpos = vec2(gl_VertexID&1, gl_VertexID&2);\n" - " gl_Position = vec4(rawpos*2.0-1.0, 0.0, 1.0);\n" - "}\n"; - const char* FProgramYuyvToRgb = "SAMPLER_BINDING(9) uniform sampler2D samp9;\n" - "in vec2 uv0;\n" - "out vec4 ocol0;\n" - "void main()\n" - "{\n" - " ivec2 uv = ivec2(gl_FragCoord.xy);\n" - // We switch top/bottom here. TODO: move this to screen blit. - " ivec2 ts = textureSize(samp9, 0);\n" - " vec4 c0 = texelFetch(samp9, ivec2(uv.x>>1, ts.y-uv.y-1), 0);\n" - " float y = mix(c0.r, c0.b, (uv.x & 1) == 1);\n" - " float yComp = 1.164 * (y - 0.0625);\n" - " float uComp = c0.g - 0.5;\n" - " float vComp = c0.a - 0.5;\n" - " ocol0 = vec4(yComp + (1.596 * vComp),\n" - " yComp - (0.813 * vComp) - (0.391 * uComp),\n" - " yComp + (2.018 * uComp),\n" - " 1.0);\n" - "}\n"; - ProgramShaderCache::CompileShader(s_yuyvToRgbProgram, VProgramYuyvToRgb, FProgramYuyvToRgb); -} - static EncodingProgram& GetOrCreateEncodingShader(const EFBCopyParams& params) { auto iter = s_encoding_programs.find(params); @@ -191,8 +105,6 @@ void Init() FramebufferManager::SetFramebuffer(0); glGenBuffers(1, &s_PBO); - - CreatePrograms(); } void Shutdown() @@ -202,9 +114,6 @@ void Shutdown() glDeleteBuffers(1, &s_PBO); glDeleteFramebuffers(2, s_texConvFrameBuffer); - s_rgbToYuyvProgram.Destroy(); - s_yuyvToRgbProgram.Destroy(); - for (auto& program : s_encoding_programs) program.second.program.Destroy(); s_encoding_programs.clear(); @@ -297,64 +206,6 @@ void EncodeToRamFromTexture(u8* dest_ptr, const EFBCopyParams& params, u32 nativ g_renderer->RestoreAPIState(); } -void EncodeToRamYUYV(GLuint srcTexture, const TargetRectangle& sourceRc, u8* destAddr, u32 dstWidth, - u32 dstStride, u32 dstHeight) -{ - g_renderer->ResetAPIState(); - - s_rgbToYuyvProgram.Bind(); - - glUniform4f(s_rgbToYuyvUniform_loc, static_cast(sourceRc.left), - static_cast(sourceRc.top), static_cast(sourceRc.right), - static_cast(sourceRc.bottom)); - - // We enable linear filtering, because the GameCube does filtering in the vertical direction when - // yscale is enabled. - // Otherwise we get jaggies when a game uses yscaling (most PAL games) - EncodeToRamUsingShader(srcTexture, destAddr, dstWidth * 2, dstHeight, dstStride, true, 1.0f); - FramebufferManager::SetFramebuffer(0); - OGLTexture::DisableStage(0); - g_renderer->RestoreAPIState(); -} - -// Should be scale free. -void DecodeToTexture(u32 xfbAddr, int srcWidth, int srcHeight, GLuint destTexture) -{ - u8* srcAddr = Memory::GetPointer(xfbAddr); - if (!srcAddr) - { - WARN_LOG(VIDEO, "Tried to decode from invalid memory address"); - return; - } - - g_renderer->ResetAPIState(); // reset any game specific settings - - OpenGL_BindAttributelessVAO(); - - // switch to texture converter frame buffer - // attach destTexture as color destination - FramebufferManager::SetFramebuffer(s_texConvFrameBuffer[1]); - FramebufferManager::FramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_ARRAY, - destTexture, 0); - - // activate source texture - // set srcAddr as data for source texture - glActiveTexture(GL_TEXTURE9); - glBindTexture(GL_TEXTURE_2D, s_srcTexture); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, srcWidth / 2, srcHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, - srcAddr); - g_sampler_cache->BindNearestSampler(9); - - glViewport(0, 0, srcWidth, srcHeight); - s_yuyvToRgbProgram.Bind(); - - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - - FramebufferManager::SetFramebuffer(0); - - g_renderer->RestoreAPIState(); -} - } // namespace } // namespace OGL diff --git a/Source/Core/VideoBackends/OGL/TextureConverter.h b/Source/Core/VideoBackends/OGL/TextureConverter.h index 3b535752a3..baed715a7e 100644 --- a/Source/Core/VideoBackends/OGL/TextureConverter.h +++ b/Source/Core/VideoBackends/OGL/TextureConverter.h @@ -20,11 +20,6 @@ namespace TextureConverter void Init(); void Shutdown(); -void EncodeToRamYUYV(GLuint srcTexture, const TargetRectangle& sourceRc, u8* destAddr, u32 dstWidth, - u32 dstStride, u32 dstHeight); - -void DecodeToTexture(u32 xfbAddr, int srcWidth, int srcHeight, GLuint destTexture); - // returns size of the encoded data (in bytes) void EncodeToRamFromTexture(u8* dest_ptr, const EFBCopyParams& params, u32 native_width, u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride, diff --git a/Source/Core/VideoBackends/Vulkan/FramebufferManager.cpp b/Source/Core/VideoBackends/Vulkan/FramebufferManager.cpp index c23c19b544..305f0343f7 100644 --- a/Source/Core/VideoBackends/Vulkan/FramebufferManager.cpp +++ b/Source/Core/VideoBackends/Vulkan/FramebufferManager.cpp @@ -1377,93 +1377,4 @@ void FramebufferManager::DestroyPokeShaders() } } -std::unique_ptr FramebufferManager::CreateXFBSource(unsigned int target_width, - unsigned int target_height, - unsigned int layers) -{ - TextureConfig config; - config.width = target_width; - config.height = target_height; - config.layers = layers; - config.rendertarget = true; - auto texture = TextureCache::GetInstance()->CreateTexture(config); - if (!texture) - { - PanicAlert("Failed to create texture for XFB source"); - return nullptr; - } - - return std::make_unique(std::move(texture)); -} - -void FramebufferManager::CopyToRealXFB(u32 xfb_addr, u32 fb_stride, u32 fb_height, - const EFBRectangle& source_rc, float gamma) -{ - // Pending/batched EFB pokes should be included in the copied image. - FlushEFBPokes(); - - // Schedule early command-buffer execution. - StateTracker::GetInstance()->EndRenderPass(); - StateTracker::GetInstance()->OnReadback(); - - // GPU EFB textures -> Guest memory - u8* xfb_ptr = Memory::GetPointer(xfb_addr); - _assert_(xfb_ptr); - - // source_rc is in native coordinates, so scale it to the internal resolution. - TargetRectangle scaled_rc = g_renderer->ConvertEFBRectangle(source_rc); - VkRect2D scaled_rc_vk = { - {scaled_rc.left, scaled_rc.top}, - {static_cast(scaled_rc.GetWidth()), static_cast(scaled_rc.GetHeight())}}; - Texture2D* src_texture = ResolveEFBColorTexture(scaled_rc_vk); - - // The destination stride can differ from the copy region width, in which case the pixels - // outside the copy region should not be written to. - TextureCache::GetInstance()->GetTextureConverter()->EncodeTextureToMemoryYUYV( - xfb_ptr, static_cast(source_rc.GetWidth()), fb_stride, fb_height, src_texture, - scaled_rc); - - // If we sourced directly from the EFB framebuffer, restore it to a color attachment. - if (src_texture == m_efb_color_texture.get()) - { - src_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); - } -} - -XFBSource::XFBSource(std::unique_ptr texture) - : XFBSourceBase(), m_texture(std::move(texture)) -{ -} - -XFBSource::~XFBSource() -{ -} - -VKTexture* XFBSource::GetTexture() const -{ - return static_cast(m_texture.get()); -} - -void XFBSource::CopyEFB(float gamma) -{ - // Pending/batched EFB pokes should be included in the copied image. - FramebufferManager::GetInstance()->FlushEFBPokes(); - - // Virtual XFB, copy EFB at native resolution to m_texture - MathUtil::Rectangle rect(0, 0, static_cast(texWidth), static_cast(texHeight)); - VkRect2D vk_rect = {{rect.left, rect.top}, - {static_cast(rect.GetWidth()), static_cast(rect.GetHeight())}}; - - Texture2D* src_texture = FramebufferManager::GetInstance()->ResolveEFBColorTexture(vk_rect); - static_cast(m_texture.get())->CopyRectangleFromTexture(src_texture, rect, rect); - - // If we sourced directly from the EFB framebuffer, restore it to a color attachment. - if (src_texture == FramebufferManager::GetInstance()->GetEFBColorTexture()) - { - src_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); - } -} - } // namespace Vulkan diff --git a/Source/Core/VideoBackends/Vulkan/FramebufferManager.h b/Source/Core/VideoBackends/Vulkan/FramebufferManager.h index 3f2a251662..0c1a160728 100644 --- a/Source/Core/VideoBackends/Vulkan/FramebufferManager.h +++ b/Source/Core/VideoBackends/Vulkan/FramebufferManager.h @@ -44,14 +44,6 @@ public: VkSampleCountFlagBits GetEFBSamples() const; MultisamplingState GetEFBMultisamplingState() const; - std::unique_ptr CreateXFBSource(unsigned int target_width, - unsigned int target_height, - unsigned int layers) override; - - // GPU EFB textures -> Guest - void CopyToRealXFB(u32 xfb_addr, u32 fb_stride, u32 fb_height, const EFBRectangle& source_rc, - float gamma = 1.0f) override; - void ResizeEFBTextures(); // Recompile shaders, use when MSAA mode changes. @@ -168,21 +160,4 @@ private: VkShaderModule m_poke_fragment_shader = VK_NULL_HANDLE; }; -// The XFB source class simply wraps a texture cache entry. -// All the required functionality is provided by TextureCache. -class XFBSource final : public XFBSourceBase -{ -public: - explicit XFBSource(std::unique_ptr texture); - ~XFBSource(); - - VKTexture* GetTexture() const; - - // Used for virtual XFB - void CopyEFB(float gamma) override; - -private: - std::unique_ptr m_texture; -}; - } // namespace Vulkan diff --git a/Source/Core/VideoBackends/Vulkan/Renderer.cpp b/Source/Core/VideoBackends/Vulkan/Renderer.cpp index ce77fb68fd..af0bfba451 100644 --- a/Source/Core/VideoBackends/Vulkan/Renderer.cpp +++ b/Source/Core/VideoBackends/Vulkan/Renderer.cpp @@ -61,11 +61,6 @@ Renderer::~Renderer() { UpdateActiveConfig(); - // Ensure all frames are written to frame dump at shutdown. - if (m_frame_dumping_active) - EndFrameDumping(); - - DestroyFrameDumpResources(); DestroyShaders(); DestroySemaphores(); } @@ -491,12 +486,6 @@ void Renderer::SwapImpl(AbstractTexture* texture, const EFBRectangle& rc, u64 ti // Pending/batched EFB pokes should be included in the final image. FramebufferManager::GetInstance()->FlushEFBPokes(); - // Check that we actually have an image to render in XFB-on modes. - if (!m_xfb_written) - { - Core::Callback_VideoCopiedToXFB(false); - } - auto* xfb_texture = static_cast(texture); // End the current render pass. @@ -563,90 +552,6 @@ void Renderer::SwapImpl(AbstractTexture* texture, const EFBRectangle& rc, u64 ti g_shader_cache->RetrieveAsyncShaders(); } -void Renderer::TransitionBuffersForSwap(const TargetRectangle& scaled_rect, - const XFBSourceBase* const* xfb_sources, u32 xfb_count) -{ - VkCommandBuffer command_buffer = g_command_buffer_mgr->GetCurrentCommandBuffer(); - - // Drawing XFB sources, so transition all of them. - // Don't need the EFB, so leave it as-is. - for (u32 i = 0; i < xfb_count; i++) - { - const XFBSource* xfb_source = static_cast(xfb_sources[i]); - xfb_source->GetTexture()->GetRawTexIdentifier()->TransitionToLayout( - command_buffer, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - } -} - -void Renderer::DrawFrame(VkRenderPass render_pass, const TargetRectangle& target_rect, - const TargetRectangle& scaled_efb_rect, u32 xfb_addr, - const XFBSourceBase* const* xfb_sources, u32 xfb_count, u32 fb_width, - u32 fb_stride, u32 fb_height) -{ -} - -void Renderer::DrawEFB(VkRenderPass render_pass, const TargetRectangle& target_rect, - const TargetRectangle& scaled_efb_rect) -{ - // Transition the EFB render target to a shader resource. - Texture2D* efb_color_texture = - g_ActiveConfig.iMultisamples > 1 ? - FramebufferManager::GetInstance()->GetResolvedEFBColorTexture() : - FramebufferManager::GetInstance()->GetEFBColorTexture(); - - // Copy EFB -> backbuffer - BlitScreen(render_pass, target_rect, scaled_efb_rect, efb_color_texture); -} - -void Renderer::DrawVirtualXFB(VkRenderPass render_pass, const TargetRectangle& target_rect, - u32 xfb_addr, const XFBSourceBase* const* xfb_sources, u32 xfb_count, - u32 fb_width, u32 fb_stride, u32 fb_height) -{ - for (u32 i = 0; i < xfb_count; ++i) - { - const XFBSource* xfb_source = static_cast(xfb_sources[i]); - TargetRectangle source_rect = xfb_source->sourceRc; - TargetRectangle draw_rect; - - int xfb_width = static_cast(xfb_source->srcWidth); - int xfb_height = static_cast(xfb_source->srcHeight); - int h_offset = (static_cast(xfb_source->srcAddr) - static_cast(xfb_addr)) / - (static_cast(fb_stride) * 2); - draw_rect.top = - target_rect.top + h_offset * target_rect.GetHeight() / static_cast(fb_height); - draw_rect.bottom = - target_rect.top + - (h_offset + xfb_height) * target_rect.GetHeight() / static_cast(fb_height); - draw_rect.left = target_rect.left + - (target_rect.GetWidth() - - xfb_width * target_rect.GetWidth() / static_cast(fb_stride)) / - 2; - draw_rect.right = target_rect.left + - (target_rect.GetWidth() + - xfb_width * target_rect.GetWidth() / static_cast(fb_stride)) / - 2; - - source_rect.right -= Renderer::EFBToScaledX(fb_stride - fb_width); - BlitScreen(render_pass, draw_rect, source_rect, - xfb_source->GetTexture()->GetRawTexIdentifier()); - } -} - -void Renderer::DrawRealXFB(VkRenderPass render_pass, const TargetRectangle& target_rect, - const XFBSourceBase* const* xfb_sources, u32 xfb_count, u32 fb_width, - u32 fb_stride, u32 fb_height) -{ - for (u32 i = 0; i < xfb_count; ++i) - { - const XFBSource* xfb_source = static_cast(xfb_sources[i]); - TargetRectangle source_rect = xfb_source->sourceRc; - TargetRectangle draw_rect = target_rect; - source_rect.right -= fb_stride - fb_width; - BlitScreen(render_pass, draw_rect, source_rect, - xfb_source->GetTexture()->GetRawTexIdentifier()); - } -} - void Renderer::DrawScreen(VKTexture* xfb_texture) { VkResult res; @@ -718,173 +623,6 @@ void Renderer::DrawScreen(VKTexture* xfb_texture) VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); } -bool Renderer::DrawFrameDump(const TargetRectangle& scaled_efb_rect, u32 xfb_addr, - const XFBSourceBase* const* xfb_sources, u32 xfb_count, u32 fb_width, - u32 fb_stride, u32 fb_height, u64 ticks) -{ - TargetRectangle target_rect = CalculateFrameDumpDrawRectangle(); - u32 width = std::max(1u, static_cast(target_rect.GetWidth())); - u32 height = std::max(1u, static_cast(target_rect.GetHeight())); - if (!ResizeFrameDumpBuffer(width, height)) - return false; - - // If there was a previous frame dumped, we'll still be in TRANSFER_SRC layout. - m_frame_dump_render_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); - - VkClearValue clear_value = {{{0.0f, 0.0f, 0.0f, 1.0f}}}; - VkClearRect clear_rect = {{{0, 0}, {width, height}}, 0, 1}; - VkClearAttachment clear_attachment = {VK_IMAGE_ASPECT_COLOR_BIT, 0, clear_value}; - VkRenderPassBeginInfo info = { - VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, - nullptr, - FramebufferManager::GetInstance()->GetColorCopyForReadbackRenderPass(), - m_frame_dump_framebuffer, - {{0, 0}, {width, height}}, - 1, - &clear_value}; - vkCmdBeginRenderPass(g_command_buffer_mgr->GetCurrentCommandBuffer(), &info, - VK_SUBPASS_CONTENTS_INLINE); - vkCmdClearAttachments(g_command_buffer_mgr->GetCurrentCommandBuffer(), 1, &clear_attachment, 1, - &clear_rect); - DrawFrame(FramebufferManager::GetInstance()->GetColorCopyForReadbackRenderPass(), target_rect, - scaled_efb_rect, xfb_addr, xfb_sources, xfb_count, fb_width, fb_stride, fb_height); - vkCmdEndRenderPass(g_command_buffer_mgr->GetCurrentCommandBuffer()); - - // Prepare the readback texture for copying. - StagingTexture2D* readback_texture = PrepareFrameDumpImage(width, height, ticks); - if (!readback_texture) - return false; - - // Queue a copy to the current frame dump buffer. It will be written to the frame dump later. - m_frame_dump_render_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); - readback_texture->CopyFromImage(g_command_buffer_mgr->GetCurrentCommandBuffer(), - m_frame_dump_render_texture->GetImage(), - VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, width, height, 0, 0); - return true; -} - -void Renderer::StartFrameDumping() -{ - _assert_(!m_frame_dumping_active); - - // Register fence callback so that we know when frames are ready to be written to the dump. - // This is done by clearing the fence pointer, so WriteFrameDumpFrame doesn't have to wait. - auto queued_callback = [](VkCommandBuffer, VkFence) {}; - auto signaled_callback = std::bind(&Renderer::OnFrameDumpImageReady, this, std::placeholders::_1); - - // We use the array pointer as a key here, that way if Renderer needed fence callbacks in - // the future it could be used without conflicting. - // We're not interested in when fences are submitted, so the first callback is a no-op. - g_command_buffer_mgr->AddFencePointCallback( - m_frame_dump_images.data(), std::move(queued_callback), std::move(signaled_callback)); - m_frame_dumping_active = true; -} - -void Renderer::EndFrameDumping() -{ - _assert_(m_frame_dumping_active); - - // Write any pending frames to the frame dump. - FlushFrameDump(); - - // Remove the fence callback that we registered earlier, one less function that needs to be - // called when preparing a command buffer. - g_command_buffer_mgr->RemoveFencePointCallback(m_frame_dump_images.data()); - m_frame_dumping_active = false; -} - -void Renderer::OnFrameDumpImageReady(VkFence fence) -{ - for (FrameDumpImage& frame : m_frame_dump_images) - { - // fence being a null handle means that we don't have to wait to re-use this image. - if (frame.fence == fence) - frame.fence = VK_NULL_HANDLE; - } -} - -void Renderer::WriteFrameDumpImage(size_t index) -{ - /*FrameDumpImage& frame = m_frame_dump_images[index]; - _assert_(frame.pending); - - // Check fence has been signaled. - // The callback here should set fence to null. - if (frame.fence != VK_NULL_HANDLE) - { - g_command_buffer_mgr->WaitForFence(frame.fence); - _assert_(frame.fence == VK_NULL_HANDLE); - } - - // Copy the now-populated image data to the output file. - DumpFrameData(reinterpret_cast(frame.readback_texture->GetMapPointer()), - static_cast(frame.readback_texture->GetWidth()), - static_cast(frame.readback_texture->GetHeight()), - static_cast(frame.readback_texture->GetRowStride()), frame.dump_state); - - frame.pending = false;*/ -} - -StagingTexture2D* Renderer::PrepareFrameDumpImage(u32 width, u32 height, u64 ticks) -{ - // Ensure the last frame that was sent to the frame dump has completed encoding before we send - // the next image to it. - //FinishFrameData(); - - // If the last image hasn't been written to the frame dump yet, write it now. - // This is necessary so that the worker thread is no more than one frame behind, and the pointer - // (which is actually the buffer) is safe for us to re-use next time. - if (m_frame_dump_images[m_current_frame_dump_image].pending) - WriteFrameDumpImage(m_current_frame_dump_image); - - // Move to the next image buffer - m_current_frame_dump_image = (m_current_frame_dump_image + 1) % FRAME_DUMP_BUFFERED_FRAMES; - FrameDumpImage& image = m_frame_dump_images[m_current_frame_dump_image]; - - // Ensure the dimensions of the readback texture are sufficient. - if (!image.readback_texture || width != image.readback_texture->GetWidth() || - height != image.readback_texture->GetHeight()) - { - // Allocate a new readback texture. - // The reset() call is here so that the memory is released before allocating the new texture. - image.readback_texture.reset(); - image.readback_texture = StagingTexture2D::Create(STAGING_BUFFER_TYPE_READBACK, width, height, - EFB_COLOR_TEXTURE_FORMAT); - - if (!image.readback_texture || !image.readback_texture->Map()) - { - // Not actually fatal, just means we can't dump this frame. - PanicAlert("Failed to allocate frame dump readback texture."); - image.readback_texture.reset(); - return nullptr; - } - } - - // The copy happens immediately after this function returns, so flag this frame as pending. - image.fence = g_command_buffer_mgr->GetCurrentCommandBufferFence(); - image.dump_state = AVIDump::FetchState(ticks); - image.pending = true; - return image.readback_texture.get(); -} - -void Renderer::FlushFrameDump() -{ - // We must write frames in order, so this is why we use a counter rather than a range. - for (size_t i = 0; i < FRAME_DUMP_BUFFERED_FRAMES; i++) - { - if (m_frame_dump_images[m_current_frame_dump_image].pending) - WriteFrameDumpImage(m_current_frame_dump_image); - - m_current_frame_dump_image = (m_current_frame_dump_image + 1) % FRAME_DUMP_BUFFERED_FRAMES; - } - - // Since everything has been written now, may as well start at index zero. - // count-1 here because the index is incremented before usage. - m_current_frame_dump_image = FRAME_DUMP_BUFFERED_FRAMES - 1; -} - void Renderer::BlitScreen(VkRenderPass render_pass, const TargetRectangle& dst_rect, const TargetRectangle& src_rect, const Texture2D* src_tex) { @@ -908,100 +646,6 @@ void Renderer::BlitScreen(VkRenderPass render_pass, const TargetRectangle& dst_r } } -bool Renderer::ResizeFrameDumpBuffer(u32 new_width, u32 new_height) -{ - if (m_frame_dump_render_texture && m_frame_dump_render_texture->GetWidth() == new_width && - m_frame_dump_render_texture->GetHeight() == new_height) - { - return true; - } - - // Ensure all previous frames have been dumped, since we are destroying a framebuffer - // that may still be in use. - FlushFrameDump(); - - if (m_frame_dump_framebuffer != VK_NULL_HANDLE) - { - vkDestroyFramebuffer(g_vulkan_context->GetDevice(), m_frame_dump_framebuffer, nullptr); - m_frame_dump_framebuffer = VK_NULL_HANDLE; - } - - m_frame_dump_render_texture = - Texture2D::Create(new_width, new_height, 1, 1, EFB_COLOR_TEXTURE_FORMAT, - VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_TILING_OPTIMAL, - VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT); - - if (!m_frame_dump_render_texture) - { - WARN_LOG(VIDEO, "Failed to resize frame dump render texture"); - m_frame_dump_render_texture.reset(); - return false; - } - - VkImageView attachment = m_frame_dump_render_texture->GetView(); - VkFramebufferCreateInfo info = {}; - info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; - info.renderPass = FramebufferManager::GetInstance()->GetColorCopyForReadbackRenderPass(); - info.attachmentCount = 1; - info.pAttachments = &attachment; - info.width = new_width; - info.height = new_height; - info.layers = 1; - - VkResult res = - vkCreateFramebuffer(g_vulkan_context->GetDevice(), &info, nullptr, &m_frame_dump_framebuffer); - if (res != VK_SUCCESS) - { - WARN_LOG(VIDEO, "Failed to create frame dump framebuffer"); - m_frame_dump_render_texture.reset(); - return false; - } - - // Render pass expects texture is in transfer src to start with. - m_frame_dump_render_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); - - return true; -} - -void Renderer::DestroyFrameDumpResources() -{ - if (m_frame_dump_framebuffer != VK_NULL_HANDLE) - { - vkDestroyFramebuffer(g_vulkan_context->GetDevice(), m_frame_dump_framebuffer, nullptr); - m_frame_dump_framebuffer = VK_NULL_HANDLE; - } - - m_frame_dump_render_texture.reset(); - - for (FrameDumpImage& image : m_frame_dump_images) - { - image.readback_texture.reset(); - image.fence = VK_NULL_HANDLE; - image.dump_state = {}; - image.pending = false; - } - m_current_frame_dump_image = FRAME_DUMP_BUFFERED_FRAMES - 1; -} - -void Renderer::CheckForTargetResize(u32 fb_width, u32 fb_stride, u32 fb_height) -{ - /*if (FramebufferManagerBase::LastXfbWidth() == fb_stride && - FramebufferManagerBase::LastXfbHeight() == fb_height) - { - return; - } - - u32 new_width = (fb_stride < 1 || fb_stride > MAX_XFB_WIDTH) ? MAX_XFB_WIDTH : fb_stride; - u32 new_height = (fb_height < 1 || fb_height > MAX_XFB_HEIGHT) ? MAX_XFB_HEIGHT : fb_height; - FramebufferManagerBase::SetLastXfbWidth(new_width); - FramebufferManagerBase::SetLastXfbHeight(new_height); - - // Changing the XFB source area may alter the target size. - if (CalculateTargetSize()) - ResizeEFBTextures();*/ -} - void Renderer::CheckForSurfaceChange() { if (!m_surface_needs_change.IsSet()) diff --git a/Source/Core/VideoBackends/Vulkan/Renderer.h b/Source/Core/VideoBackends/Vulkan/Renderer.h index b9d746582c..a94d44138b 100644 --- a/Source/Core/VideoBackends/Vulkan/Renderer.h +++ b/Source/Core/VideoBackends/Vulkan/Renderer.h @@ -72,7 +72,6 @@ private: void BeginFrame(); - void CheckForTargetResize(u32 fb_width, u32 fb_stride, u32 fb_height); void CheckForSurfaceChange(); void CheckForConfigChanges(); @@ -86,61 +85,13 @@ private: bool CompileShaders(); void DestroyShaders(); - // Transitions EFB/XFB buffers to SHADER_READ_ONLY, ready for presenting/dumping. - // If MSAA is enabled, and XFB is disabled, also resolves the EFB buffer. - void TransitionBuffersForSwap(const TargetRectangle& scaled_rect, - const XFBSourceBase* const* xfb_sources, u32 xfb_count); - - // Draw either the EFB, or specified XFB sources to the currently-bound framebuffer. - void DrawFrame(VkRenderPass render_pass, const TargetRectangle& target_rect, - const TargetRectangle& scaled_efb_rect, u32 xfb_addr, - const XFBSourceBase* const* xfb_sources, u32 xfb_count, u32 fb_width, - u32 fb_stride, u32 fb_height); - void DrawEFB(VkRenderPass render_pass, const TargetRectangle& target_rect, - const TargetRectangle& scaled_efb_rect); - void DrawVirtualXFB(VkRenderPass render_pass, const TargetRectangle& target_rect, u32 xfb_addr, - const XFBSourceBase* const* xfb_sources, u32 xfb_count, u32 fb_width, - u32 fb_stride, u32 fb_height); - void DrawRealXFB(VkRenderPass render_pass, const TargetRectangle& target_rect, - const XFBSourceBase* const* xfb_sources, u32 xfb_count, u32 fb_width, - u32 fb_stride, u32 fb_height); - // Draw the frame, as well as the OSD to the swap chain. void DrawScreen(VKTexture* xfb_texture); - // Draw the frame only to the screenshot buffer. - bool DrawFrameDump(const TargetRectangle& scaled_efb_rect, u32 xfb_addr, - const XFBSourceBase* const* xfb_sources, u32 xfb_count, u32 fb_width, - u32 fb_stride, u32 fb_height, u64 ticks); - - // Sets up renderer state to permit framedumping. - // Ideally we would have EndFrameDumping be a virtual method of Renderer, but due to various - // design issues it would have to end up being called in the destructor, which won't work. - void StartFrameDumping(); - void EndFrameDumping(); - - // Fence callback so that we know when frames are ready to be written to the dump. - // This is done by clearing the fence pointer, so WriteFrameDumpFrame doesn't have to wait. - void OnFrameDumpImageReady(VkFence fence); - - // Writes the specified buffered frame to the frame dump. - // NOTE: Assumes that frame.ticks and frame.pending are valid. - void WriteFrameDumpImage(size_t index); - - // If there is a pending frame in this buffer, writes it to the frame dump. - // Ensures that the specified readback buffer meets the size requirements of the current frame. - StagingTexture2D* PrepareFrameDumpImage(u32 width, u32 height, u64 ticks); - - // Ensures all buffered frames are written to frame dump. - void FlushFrameDump(); - // Copies/scales an image to the currently-bound framebuffer. void BlitScreen(VkRenderPass render_pass, const TargetRectangle& dst_rect, const TargetRectangle& src_rect, const Texture2D* src_tex); - bool ResizeFrameDumpBuffer(u32 new_width, u32 new_height); - void DestroyFrameDumpResources(); - VkSemaphore m_image_available_semaphore = VK_NULL_HANDLE; VkSemaphore m_rendering_finished_semaphore = VK_NULL_HANDLE; @@ -153,22 +104,5 @@ private: // Shaders used for clear/blit. VkShaderModule m_clear_fragment_shader = VK_NULL_HANDLE; - - // Texture used for screenshot/frame dumping - std::unique_ptr m_frame_dump_render_texture; - VkFramebuffer m_frame_dump_framebuffer = VK_NULL_HANDLE; - - // Readback resources for frame dumping - static const size_t FRAME_DUMP_BUFFERED_FRAMES = 2; - struct FrameDumpImage - { - std::unique_ptr readback_texture; - VkFence fence = VK_NULL_HANDLE; - AVIDump::Frame dump_state = {}; - bool pending = false; - }; - std::array m_frame_dump_images; - size_t m_current_frame_dump_image = FRAME_DUMP_BUFFERED_FRAMES - 1; - bool m_frame_dumping_active = false; }; } diff --git a/Source/Core/VideoCommon/FramebufferManagerBase.cpp b/Source/Core/VideoCommon/FramebufferManagerBase.cpp index d749cb7bcf..5e95cff805 100644 --- a/Source/Core/VideoCommon/FramebufferManagerBase.cpp +++ b/Source/Core/VideoCommon/FramebufferManagerBase.cpp @@ -14,145 +14,7 @@ std::unique_ptr g_framebuffer_manager; -std::unique_ptr - FramebufferManagerBase::m_realXFBSource; // Only used in Real XFB mode -FramebufferManagerBase::VirtualXFBListType - FramebufferManagerBase::m_virtualXFBList; // Only used in Virtual XFB mode -std::array - FramebufferManagerBase::m_overlappingXFBArray; - unsigned int FramebufferManagerBase::m_EFBLayers = 1; -FramebufferManagerBase::FramebufferManagerBase() -{ - // Can't hurt - m_overlappingXFBArray.fill(nullptr); -} +FramebufferManagerBase::~FramebufferManagerBase() = default; -FramebufferManagerBase::~FramebufferManagerBase() -{ - // Necessary, as these are static members - // (they really shouldn't be and should be refactored at some point). - m_virtualXFBList.clear(); - m_realXFBSource.reset(); -} - -void FramebufferManagerBase::CopyToXFB(u32 xfbAddr, u32 fbStride, u32 fbHeight, - const EFBRectangle& sourceRc, float Gamma) -{ -} - -void FramebufferManagerBase::CopyToVirtualXFB(u32 xfbAddr, u32 fbStride, u32 fbHeight, - const EFBRectangle& sourceRc, float Gamma) -{ - if (!g_framebuffer_manager) - return; - - VirtualXFBListType::iterator vxfb = FindVirtualXFB(xfbAddr, sourceRc.GetWidth(), fbHeight); - - if (m_virtualXFBList.end() == vxfb) - { - if (m_virtualXFBList.size() < MAX_VIRTUAL_XFB) - { - // create a new Virtual XFB and place it at the front of the list - m_virtualXFBList.emplace_front(); - vxfb = m_virtualXFBList.begin(); - } - else - { - // Replace the last virtual XFB - --vxfb; - } - } - // else // replace existing virtual XFB - - // move this Virtual XFB to the front of the list. - if (m_virtualXFBList.begin() != vxfb) - m_virtualXFBList.splice(m_virtualXFBList.begin(), m_virtualXFBList, vxfb); - - u32 target_width, target_height; - std::tie(target_width, target_height) = g_framebuffer_manager->GetTargetSize(); - - // recreate if needed - if (vxfb->xfbSource && - (vxfb->xfbSource->texWidth != target_width || vxfb->xfbSource->texHeight != target_height)) - vxfb->xfbSource.reset(); - - if (!vxfb->xfbSource) - { - vxfb->xfbSource = - g_framebuffer_manager->CreateXFBSource(target_width, target_height, m_EFBLayers); - if (!vxfb->xfbSource) - return; - - vxfb->xfbSource->texWidth = target_width; - vxfb->xfbSource->texHeight = target_height; - } - - vxfb->xfbSource->srcAddr = vxfb->xfbAddr = xfbAddr; - vxfb->xfbSource->srcWidth = vxfb->xfbWidth = sourceRc.GetWidth(); - vxfb->xfbSource->srcHeight = vxfb->xfbHeight = fbHeight; - - vxfb->xfbSource->sourceRc = g_renderer->ConvertEFBRectangle(sourceRc); - - // keep stale XFB data from being used - ReplaceVirtualXFB(); - - // Copy EFB data to XFB and restore render target again - vxfb->xfbSource->CopyEFB(Gamma); -} - -FramebufferManagerBase::VirtualXFBListType::iterator -FramebufferManagerBase::FindVirtualXFB(u32 xfbAddr, u32 width, u32 height) -{ - const u32 srcLower = xfbAddr; - const u32 srcUpper = xfbAddr + 2 * width * height; - - return std::find_if(m_virtualXFBList.begin(), m_virtualXFBList.end(), - [srcLower, srcUpper](const VirtualXFB& xfb) { - const u32 dstLower = xfb.xfbAddr; - const u32 dstUpper = xfb.xfbAddr + 2 * xfb.xfbWidth * xfb.xfbHeight; - - return dstLower >= srcLower && dstUpper <= srcUpper; - }); -} - -void FramebufferManagerBase::ReplaceVirtualXFB() -{ - VirtualXFBListType::iterator it = m_virtualXFBList.begin(); - - const s32 srcLower = it->xfbAddr; - const s32 srcUpper = it->xfbAddr + 2 * it->xfbWidth * it->xfbHeight; - const s32 lineSize = 2 * it->xfbWidth; - - ++it; - - for (; it != m_virtualXFBList.end(); ++it) - { - s32 dstLower = it->xfbAddr; - s32 dstUpper = it->xfbAddr + 2 * it->xfbWidth * it->xfbHeight; - - if (dstLower >= srcLower && dstUpper <= srcUpper) - { - // Invalidate the data - it->xfbAddr = 0; - it->xfbHeight = 0; - it->xfbWidth = 0; - } - else if (AddressRangesOverlap(srcLower, srcUpper, dstLower, dstUpper)) - { - s32 upperOverlap = (srcUpper - dstLower) / lineSize; - s32 lowerOverlap = (dstUpper - srcLower) / lineSize; - - if (upperOverlap > 0 && lowerOverlap < 0) - { - it->xfbAddr += lineSize * upperOverlap; - it->xfbHeight -= upperOverlap; - } - else if (lowerOverlap > 0) - { - it->xfbHeight -= lowerOverlap; - } - } - } -} diff --git a/Source/Core/VideoCommon/FramebufferManagerBase.h b/Source/Core/VideoCommon/FramebufferManagerBase.h index b0ba40b1a0..2d725fa346 100644 --- a/Source/Core/VideoCommon/FramebufferManagerBase.h +++ b/Source/Core/VideoCommon/FramebufferManagerBase.h @@ -17,76 +17,16 @@ inline bool AddressRangesOverlap(u32 aLower, u32 aUpper, u32 bLower, u32 bUpper) return !((aLower >= bUpper) || (bLower >= aUpper)); } -struct XFBSourceBase -{ - virtual ~XFBSourceBase() {} - - virtual void CopyEFB(float Gamma) = 0; - - u32 srcAddr; - u32 srcWidth; - u32 srcHeight; - - unsigned int texWidth; - unsigned int texHeight; - - // TODO: only used by OGL - TargetRectangle sourceRc; -}; - class FramebufferManagerBase { public: - enum - { - // There may be multiple XFBs in GameCube RAM. This is the maximum number to - // virtualize. - MAX_VIRTUAL_XFB = 8 - }; - - FramebufferManagerBase(); virtual ~FramebufferManagerBase(); - static void CopyToXFB(u32 xfbAddr, u32 fbStride, u32 fbHeight, const EFBRectangle& sourceRc, - float Gamma); - static unsigned int GetEFBLayers() { return m_EFBLayers; } - virtual std::pair GetTargetSize() const = 0; protected: - struct VirtualXFB - { - VirtualXFB() {} - // Address and size in GameCube RAM - u32 xfbAddr = 0; - u32 xfbWidth = 0; - u32 xfbHeight = 0; - - std::unique_ptr xfbSource; - }; - - typedef std::list VirtualXFBListType; static unsigned int m_EFBLayers; - -private: - virtual std::unique_ptr - CreateXFBSource(unsigned int target_width, unsigned int target_height, unsigned int layers) = 0; - - static VirtualXFBListType::iterator FindVirtualXFB(u32 xfbAddr, u32 width, u32 height); - - static void ReplaceVirtualXFB(); - - // TODO: merge these virtual funcs, they are nearly all the same - virtual void CopyToRealXFB(u32 xfbAddr, u32 fbStride, u32 fbHeight, const EFBRectangle& sourceRc, - float Gamma = 1.0f) = 0; - static void CopyToVirtualXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc, - float Gamma = 1.0f); - - static std::unique_ptr m_realXFBSource; // Only used in Real XFB mode - static VirtualXFBListType m_virtualXFBList; // Only used in Virtual XFB mode - - static std::array m_overlappingXFBArray; }; extern std::unique_ptr g_framebuffer_manager; diff --git a/Source/Core/VideoCommon/RenderBase.cpp b/Source/Core/VideoCommon/RenderBase.cpp index 0a3648c9ea..4bc8911b08 100644 --- a/Source/Core/VideoCommon/RenderBase.cpp +++ b/Source/Core/VideoCommon/RenderBase.cpp @@ -112,8 +112,6 @@ void Renderer::RenderToXFB(u32 xfbAddr, const EFBRectangle& sourceRc, u32 fbStri if (!fbStride || !fbHeight) return; - - m_xfb_written = true; } unsigned int Renderer::GetEFBScale() const @@ -412,34 +410,6 @@ std::tuple Renderer::ScaleToDisplayAspectRatio(const int width, return std::make_tuple(scaled_width, scaled_height); } -TargetRectangle Renderer::CalculateFrameDumpDrawRectangle() const -{ - // No point including any borders in the frame dump image, since they'd have to be cropped anyway. - TargetRectangle rc; - rc.left = 0; - rc.top = 0; - - // If full-resolution frame dumping is disabled, just use the window draw rectangle. - if (!g_ActiveConfig.bInternalResolutionFrameDumps) - { - // But still remove the borders, since the caller expects this. - rc.right = m_target_rectangle.GetWidth(); - rc.bottom = m_target_rectangle.GetHeight(); - return rc; - } - - // Grab the dimensions of the EFB textures, we scale either of these depending on the ratio. - u32 efb_width, efb_height; - std::tie(efb_width, efb_height) = g_framebuffer_manager->GetTargetSize(); - - float draw_width, draw_height; - std::tie(draw_width, draw_height) = ScaleToDisplayAspectRatio(efb_width, efb_height); - - rc.right = static_cast(std::ceil(draw_width)); - rc.bottom = static_cast(std::ceil(draw_height)); - return rc; -} - void Renderer::UpdateDrawRectangle() { // The rendering window size @@ -693,7 +663,6 @@ void Renderer::Swap(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, const stats.ResetFrame(); Core::Callback_VideoCopiedToXFB(update_frame_count); - m_xfb_written = false; } bool Renderer::IsFrameDumping() diff --git a/Source/Core/VideoCommon/RenderBase.h b/Source/Core/VideoCommon/RenderBase.h index 1d776a97d1..f2063e8228 100644 --- a/Source/Core/VideoCommon/RenderBase.h +++ b/Source/Core/VideoCommon/RenderBase.h @@ -96,7 +96,6 @@ public: float CalculateDrawAspectRatio() const; std::tuple ScaleToDisplayAspectRatio(int width, int height) const; - TargetRectangle CalculateFrameDumpDrawRectangle() const; void UpdateDrawRectangle(); // Use this to convert a single target rectangle to two stereo rectangles @@ -167,7 +166,6 @@ protected: int m_backbuffer_width = 0; int m_backbuffer_height = 0; TargetRectangle m_target_rectangle = {}; - bool m_xfb_written = false; FPSCounter m_fps_counter;