Add support for hybrid XFB

This commit is contained in:
iwubcode
2017-11-17 19:47:56 -06:00
parent 84ca9a4aec
commit 79387dddb2
45 changed files with 400 additions and 985 deletions
@@ -52,7 +52,6 @@
<ClCompile Include="PixelShaderCache.cpp" />
<ClCompile Include="PSTextureEncoder.cpp" />
<ClCompile Include="Render.cpp" />
<ClCompile Include="Television.cpp" />
<ClCompile Include="TextureCache.cpp" />
<ClCompile Include="VertexManager.cpp" />
<ClCompile Include="VertexShaderCache.cpp" />
@@ -73,7 +72,6 @@
<ClInclude Include="PixelShaderCache.h" />
<ClInclude Include="PSTextureEncoder.h" />
<ClInclude Include="Render.h" />
<ClInclude Include="Television.h" />
<ClInclude Include="TextureCache.h" />
<ClInclude Include="VertexManager.h" />
<ClInclude Include="VertexShaderCache.h" />
@@ -48,9 +48,6 @@
<ClCompile Include="Render.cpp">
<Filter>Render</Filter>
</ClCompile>
<ClCompile Include="Television.cpp">
<Filter>Render</Filter>
</ClCompile>
<ClCompile Include="TextureCache.cpp">
<Filter>Render</Filter>
</ClCompile>
@@ -108,9 +105,6 @@
<ClInclude Include="Render.h">
<Filter>Render</Filter>
</ClInclude>
<ClInclude Include="Television.h">
<Filter>Render</Filter>
</ClInclude>
<ClInclude Include="TextureCache.h">
<Filter>Render</Filter>
</ClInclude>
@@ -330,12 +330,6 @@ std::pair<u32, u32> FramebufferManager::GetTargetSize() const
return std::make_pair(m_target_width, m_target_height);
}
void XFBSource::DecodeToTexture(u32 xfbAddr, u32 fbWidth, u32 fbHeight)
{
// DX11's XFB decoder does not use this function.
// YUYV data is decoded in Render::Swap.
}
void XFBSource::CopyEFB(float Gamma)
{
g_renderer->ResetAPIState(); // reset any game specific settings
@@ -50,7 +50,6 @@ struct XFBSource : public XFBSourceBase
{
XFBSource(D3DTexture2D* _tex, int slices) : tex(_tex), m_slices(slices) {}
~XFBSource() { tex->Release(); }
void DecodeToTexture(u32 xfbAddr, u32 fbWidth, u32 fbHeight) override;
void CopyEFB(float Gamma) override;
D3DTexture2D* const tex;
@@ -41,8 +41,11 @@ void PSTextureEncoder::Init()
HRESULT hr;
// Create output texture RGBA format
// TODO: This Texture is overly large and parts of it are unused
// EFB2RAM copies use max (EFB_WIDTH * 4) by (EFB_HEIGHT / 4)
// XFB2RAM copies use max (EFB_WIDTH / 2) by (EFB_HEIGHT)
D3D11_TEXTURE2D_DESC t2dd = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_B8G8R8A8_UNORM, EFB_WIDTH * 4,
EFB_HEIGHT / 4, 1, 1, D3D11_BIND_RENDER_TARGET);
EFB_HEIGHT, 1, 1, D3D11_BIND_RENDER_TARGET);
hr = D3D::device->CreateTexture2D(&t2dd, nullptr, &m_out);
CHECK(SUCCEEDED(hr), "create efb encode output texture");
D3D::SetDebugObjectName(m_out, "efb encoder output texture");
+10 -97
View File
@@ -24,10 +24,10 @@
#include "VideoBackends/D3D/D3DBase.h"
#include "VideoBackends/D3D/D3DState.h"
#include "VideoBackends/D3D/D3DUtil.h"
#include "VideoBackends/D3D/DXTexture.h"
#include "VideoBackends/D3D/FramebufferManager.h"
#include "VideoBackends/D3D/GeometryShaderCache.h"
#include "VideoBackends/D3D/PixelShaderCache.h"
#include "VideoBackends/D3D/Television.h"
#include "VideoBackends/D3D/TextureCache.h"
#include "VideoBackends/D3D/VertexShaderCache.h"
@@ -40,6 +40,7 @@
#include "VideoCommon/SamplerCommon.h"
#include "VideoCommon/VideoBackendBase.h"
#include "VideoCommon/VideoConfig.h"
#include "VideoCommon/VideoCommon.h"
#include "VideoCommon/XFMemory.h"
namespace DX11
@@ -66,11 +67,8 @@ struct GXPipelineState
static u32 s_last_multisamples = 1;
static bool s_last_stereo_mode = false;
static bool s_last_xfb_mode = false;
static bool s_last_fullscreen_mode = false;
static Television s_television;
static std::array<ID3D11BlendState*, 4> s_clear_blend_states{};
static std::array<ID3D11DepthStencilState*, 3> s_clear_depth_states{};
static ID3D11BlendState* s_reset_blend_state = nullptr;
@@ -85,8 +83,6 @@ static StateCache s_gx_state_cache;
static void SetupDeviceObjects()
{
s_television.Init();
HRESULT hr;
D3D11_DEPTH_STENCIL_DESC ddesc;
@@ -182,8 +178,6 @@ static void TeardownDeviceObjects()
SAFE_RELEASE(s_screenshot_texture);
SAFE_RELEASE(s_3d_vision_texture);
s_television.Shutdown();
s_gx_state_cache.Clear();
}
@@ -241,7 +235,6 @@ Renderer::Renderer() : ::Renderer(D3D::GetBackBufferWidth(), D3D::GetBackBufferH
{
s_last_multisamples = g_ActiveConfig.iMultisamples;
s_last_stereo_mode = g_ActiveConfig.iStereoMode > 0;
s_last_xfb_mode = g_ActiveConfig.bUseRealXFB;
s_last_fullscreen_mode = D3D::GetFullscreenState();
g_framebuffer_manager = std::make_unique<FramebufferManager>(m_target_width, m_target_height);
@@ -640,22 +633,11 @@ void Renderer::SetBlendingState(const BlendingState& state)
}
// This function has the final picture. We adjust the aspect ratio here.
void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight,
const EFBRectangle& rc, u64 ticks, float Gamma)
void Renderer::SwapImpl(AbstractTexture* texture, const EFBRectangle& rc, u64 ticks, float Gamma)
{
if ((!m_xfb_written && !g_ActiveConfig.RealXFBEnabled()) || !fbWidth || !fbHeight)
if (!m_xfb_written)
{
Core::Callback_VideoCopiedToXFB(false);
return;
}
u32 xfbCount = 0;
const XFBSourceBase* const* xfbSourceList =
FramebufferManager::GetXFBSource(xfbAddr, fbStride, fbHeight, &xfbCount);
if ((!xfbSourceList || xfbCount == 0) && g_ActiveConfig.bUseXFB && !g_ActiveConfig.bUseRealXFB)
{
Core::Callback_VideoCopiedToXFB(false);
return;
}
ResetAPIState();
@@ -671,67 +653,11 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight,
// activate linear filtering for the buffer copies
D3D::SetLinearCopySampler();
auto* xfb_texture = static_cast<DXTexture*>(texture);
TargetRectangle source_rc = xfb_texture->config.Rect();
if (g_ActiveConfig.bUseXFB && g_ActiveConfig.bUseRealXFB)
{
// TODO: Television should be used to render Virtual XFB mode as well.
D3D11_VIEWPORT vp = CD3D11_VIEWPORT((float)targetRc.left, (float)targetRc.top,
(float)targetRc.GetWidth(), (float)targetRc.GetHeight());
D3D::context->RSSetViewports(1, &vp);
s_television.Submit(xfbAddr, fbStride, fbWidth, fbHeight);
s_television.Render();
}
else if (g_ActiveConfig.bUseXFB)
{
// draw each xfb source
for (u32 i = 0; i < xfbCount; ++i)
{
const auto* const xfbSource = static_cast<const XFBSource*>(xfbSourceList[i]);
// use virtual xfb with offset
int xfbHeight = xfbSource->srcHeight;
int xfbWidth = xfbSource->srcWidth;
int hOffset = ((s32)xfbSource->srcAddr - (s32)xfbAddr) / ((s32)fbStride * 2);
TargetRectangle drawRc;
drawRc.top = targetRc.top + hOffset * targetRc.GetHeight() / (s32)fbHeight;
drawRc.bottom = targetRc.top + (hOffset + xfbHeight) * targetRc.GetHeight() / (s32)fbHeight;
drawRc.left = targetRc.left +
(targetRc.GetWidth() - xfbWidth * targetRc.GetWidth() / (s32)fbStride) / 2;
drawRc.right = targetRc.left +
(targetRc.GetWidth() + xfbWidth * targetRc.GetWidth() / (s32)fbStride) / 2;
// The following code disables auto stretch. Kept for reference.
// scale draw area for a 1 to 1 pixel mapping with the draw target
// float vScale = (float)fbHeight / (float)s_backbuffer_height;
// float hScale = (float)fbWidth / (float)s_backbuffer_width;
// drawRc.top *= vScale;
// drawRc.bottom *= vScale;
// drawRc.left *= hScale;
// drawRc.right *= hScale;
TargetRectangle sourceRc;
sourceRc.left = xfbSource->sourceRc.left;
sourceRc.top = xfbSource->sourceRc.top;
sourceRc.right = xfbSource->sourceRc.right;
sourceRc.bottom = xfbSource->sourceRc.bottom;
sourceRc.right -= Renderer::EFBToScaledX(fbStride - fbWidth);
BlitScreen(sourceRc, drawRc, xfbSource->tex, xfbSource->texWidth, xfbSource->texHeight,
Gamma);
}
}
else
{
TargetRectangle sourceRc = Renderer::ConvertEFBRectangle(rc);
// TODO: Improve sampling algorithm for the pixel shader so that we can use the multisampled EFB
// texture as source
D3DTexture2D* read_texture = FramebufferManager::GetResolvedEFBColorTexture();
BlitScreen(sourceRc, targetRc, read_texture, GetTargetWidth(), GetTargetHeight(), Gamma);
}
BlitScreen(source_rc, targetRc, xfb_texture->GetRawTexIdentifier(), xfb_texture->config.width,
xfb_texture->config.height, Gamma);
// Dump frames
if (IsFrameDumping())
@@ -773,33 +699,20 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight,
g_texture_cache->OnConfigChanged(g_ActiveConfig);
VertexShaderCache::RetreiveAsyncShaders();
SetWindowSize(fbStride, fbHeight);
SetWindowSize(xfb_texture->config.width, xfb_texture->config.height);
const bool window_resized = CheckForResize();
const bool fullscreen = D3D::GetFullscreenState();
const bool fs_changed = s_last_fullscreen_mode != fullscreen;
bool xfbchanged = s_last_xfb_mode != g_ActiveConfig.bUseRealXFB;
if (FramebufferManagerBase::LastXfbWidth() != fbStride ||
FramebufferManagerBase::LastXfbHeight() != fbHeight)
{
xfbchanged = true;
unsigned int xfb_w = (fbStride < 1 || fbStride > MAX_XFB_WIDTH) ? MAX_XFB_WIDTH : fbStride;
unsigned int xfb_h = (fbHeight < 1 || fbHeight > MAX_XFB_HEIGHT) ? MAX_XFB_HEIGHT : fbHeight;
FramebufferManagerBase::SetLastXfbWidth(xfb_w);
FramebufferManagerBase::SetLastXfbHeight(xfb_h);
}
// Flip/present backbuffer to frontbuffer here
D3D::Present();
// Resize the back buffers NOW to avoid flickering
if (CalculateTargetSize() || xfbchanged || window_resized || fs_changed ||
if (CalculateTargetSize() || window_resized || fs_changed ||
s_last_multisamples != g_ActiveConfig.iMultisamples ||
s_last_stereo_mode != (g_ActiveConfig.iStereoMode > 0))
{
s_last_xfb_mode = g_ActiveConfig.bUseRealXFB;
s_last_multisamples = g_ActiveConfig.iMultisamples;
s_last_fullscreen_mode = fullscreen;
PixelShaderCache::InvalidateMSAAShaders();
+1 -2
View File
@@ -46,8 +46,7 @@ public:
TargetRectangle ConvertEFBRectangle(const EFBRectangle& rc) override;
void SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, const EFBRectangle& rc,
u64 ticks, float Gamma) override;
void SwapImpl(AbstractTexture* texture, const EFBRectangle& rc, u64 ticks, float Gamma) override;
void ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable,
u32 color, u32 z) override;
@@ -1,166 +0,0 @@
// Copyright 2011 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "VideoBackends/D3D/Television.h"
#include <vector>
#include "Core/HW/Memmap.h"
#include "VideoBackends/D3D/D3DBase.h"
#include "VideoBackends/D3D/D3DShader.h"
#include "VideoBackends/D3D/D3DState.h"
#include "VideoBackends/D3D/D3DUtil.h"
#include "VideoBackends/D3D/VertexShaderCache.h"
#include "VideoCommon/VideoCommon.h"
#include "VideoCommon/VideoConfig.h"
namespace DX11
{
static const char YUYV_DECODER_PS[] =
"// dolphin-emu YUYV decoder pixel shader\n"
"Texture2D Tex0 : register(t0);\n"
"sampler Samp0 : register(s0);\n"
"static const float3x3 YCBCR_TO_RGB = float3x3(\n"
"1.164, 0.000, 1.596,\n"
"1.164, -0.392, -0.813,\n"
"1.164, 2.017, 0.000\n"
");\n"
"void main(out float4 ocol0 : SV_Target, in float4 pos : SV_Position, in float2 uv0 : "
"TEXCOORD0)\n"
"{\n"
"float3 sample = Tex0.Sample(Samp0, uv0).rgb;\n"
// GameCube/Wii XFB data is in YUYV format with ITU-R Rec. BT.601 color
// primaries, compressed to the range Y in 16..235, U and V in 16..240.
// We want to convert it to RGB format with sRGB color primaries, with
// range 0..255.
// Recover RGB components
"float3 yuv_601_sub = sample.grb - float3(16.0/255.0, 128.0/255.0, 128.0/255.0);\n"
"float3 rgb_601 = mul(YCBCR_TO_RGB, yuv_601_sub);\n"
// If we were really obsessed with accuracy, we would correct for the
// differing color primaries between BT.601 and sRGB. However, this may not
// be worth the trouble because:
// - BT.601 defines two sets of primaries: one for NTSC and one for PAL.
// - sRGB's color primaries are actually an intermediate between BT.601's
// NTSC and PAL primaries.
// - If users even noticed any difference at all, they would be confused by
// the slightly-different colors in the NTSC and PAL versions of the same
// game.
// - Even the game designers probably don't pay close attention to this
// stuff.
// Still, instructions on how to do it can be found at
// <http://www.poynton.com/notes/colour_and_gamma/ColorFAQ.html#RTFToC20>
"ocol0 = float4(rgb_601, 1);\n"
"}\n";
Television::Television() : m_yuyvTexture(nullptr), m_yuyvTextureSRV(nullptr), m_pShader(nullptr)
{
}
void Television::Init()
{
HRESULT hr;
// Create YUYV texture for real XFB mode
// Initialize the texture with YCbCr black
//
// Some games use narrower XFB widths (Nintendo titles are fond of 608),
// so the sampler's BorderColor won't cover the right side
// (see sampler state below)
const unsigned int MAX_XFB_SIZE = 2 * (MAX_XFB_WIDTH)*MAX_XFB_HEIGHT;
std::vector<u8> fill(MAX_XFB_SIZE);
for (size_t i = 0; i < MAX_XFB_SIZE / sizeof(u32); ++i)
reinterpret_cast<u32*>(fill.data())[i] = 0x80108010;
D3D11_SUBRESOURCE_DATA srd = {fill.data(), 2 * (MAX_XFB_WIDTH), 0};
// This texture format is designed for YUYV data.
D3D11_TEXTURE2D_DESC t2dd =
CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_G8R8_G8B8_UNORM, MAX_XFB_WIDTH, MAX_XFB_HEIGHT, 1, 1);
hr = D3D::device->CreateTexture2D(&t2dd, &srd, &m_yuyvTexture);
CHECK(SUCCEEDED(hr), "create tv yuyv texture");
D3D::SetDebugObjectName(m_yuyvTexture, "tv yuyv texture");
// Create shader resource view for YUYV texture
D3D11_SHADER_RESOURCE_VIEW_DESC srvd = CD3D11_SHADER_RESOURCE_VIEW_DESC(
m_yuyvTexture, D3D11_SRV_DIMENSION_TEXTURE2D, DXGI_FORMAT_G8R8_G8B8_UNORM);
hr = D3D::device->CreateShaderResourceView(m_yuyvTexture, &srvd, &m_yuyvTextureSRV);
CHECK(SUCCEEDED(hr), "create tv yuyv texture srv");
D3D::SetDebugObjectName(m_yuyvTextureSRV, "tv yuyv texture srv");
// Create YUYV-decoding pixel shader
m_pShader = D3D::CompileAndCreatePixelShader(YUYV_DECODER_PS);
CHECK(m_pShader != nullptr, "compile and create yuyv decoder pixel shader");
D3D::SetDebugObjectName(m_pShader, "yuyv decoder pixel shader");
// Create sampler state and set border color
//
// The default sampler border color of { 0.f, 0.f, 0.f, 0.f }
// creates a green border around the image - see issue 6483
// (remember, the XFB is being interpreted as YUYV, and 0,0,0,0
// is actually two green pixels in YUYV - black should be 16,128,16,128,
// but we reverse the order to match DXGI_FORMAT_G8R8_G8B8_UNORM's ordering)
float border[4] = {128.0f / 255.0f, 16.0f / 255.0f, 128.0f / 255.0f, 16.0f / 255.0f};
D3D11_SAMPLER_DESC samDesc = CD3D11_SAMPLER_DESC(
D3D11_FILTER_MIN_MAG_MIP_LINEAR, D3D11_TEXTURE_ADDRESS_BORDER, D3D11_TEXTURE_ADDRESS_BORDER,
D3D11_TEXTURE_ADDRESS_BORDER, 0.f, 1, D3D11_COMPARISON_ALWAYS, border, 0.f, 0.f);
hr = D3D::device->CreateSamplerState(&samDesc, &m_samplerState);
CHECK(SUCCEEDED(hr), "create yuyv decoder sampler state");
D3D::SetDebugObjectName(m_samplerState, "yuyv decoder sampler state");
}
void Television::Shutdown()
{
SAFE_RELEASE(m_pShader);
SAFE_RELEASE(m_yuyvTextureSRV);
SAFE_RELEASE(m_yuyvTexture);
SAFE_RELEASE(m_samplerState);
}
void Television::Submit(u32 xfbAddr, u32 stride, u32 width, u32 height)
{
m_curAddr = xfbAddr;
m_curWidth = width;
m_curHeight = height;
// Load data from GameCube RAM to YUYV texture
u8* yuyvSrc = Memory::GetPointer(xfbAddr);
D3D11_BOX box = CD3D11_BOX(0, 0, 0, stride, height, 1);
D3D::context->UpdateSubresource(m_yuyvTexture, 0, &box, yuyvSrc, 2 * stride, 2 * stride * height);
}
void Television::Render()
{
if (g_ActiveConfig.bUseRealXFB && g_ActiveConfig.bUseXFB)
{
// Use real XFB mode
// TODO: If this is the lower field, render at a vertical offset of 1
// line down. We could even consider implementing a deinterlacing
// algorithm.
D3D11_RECT sourceRc = CD3D11_RECT(0, 0, int(m_curWidth), int(m_curHeight));
D3D::stateman->SetSampler(0, m_samplerState);
D3D::drawShadedTexQuad(m_yuyvTextureSRV, &sourceRc, MAX_XFB_WIDTH, MAX_XFB_HEIGHT, m_pShader,
VertexShaderCache::GetSimpleVertexShader(),
VertexShaderCache::GetSimpleInputLayout());
}
else if (g_ActiveConfig.bUseXFB)
{
// Use virtual XFB mode
// TODO: Eventually, Television should render the Virtual XFB mode
// display as well.
}
}
}
@@ -1,45 +0,0 @@
// Copyright 2011 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include "Common/CommonTypes.h"
struct ID3D11Texture2D;
struct ID3D11ShaderResourceView;
struct ID3D11PixelShader;
struct ID3D11SamplerState;
namespace DX11
{
class Television
{
public:
Television();
void Init();
void Shutdown();
// Submit video data to be drawn. This will change the current state of the
// TV. xfbAddr points to YUYV data stored in GameCube/Wii RAM, but the XFB
// may be virtualized when rendering so the RAM may not actually be read.
void Submit(u32 xfbAddr, u32 stride, u32 width, u32 height);
// Render the current state of the TV.
void Render();
private:
// Properties of last Submit call
u32 m_curAddr;
u32 m_curWidth;
u32 m_curHeight;
// Used for real XFB mode
ID3D11Texture2D* m_yuyvTexture;
ID3D11ShaderResourceView* m_yuyvTextureSRV;
ID3D11PixelShader* m_pShader;
ID3D11SamplerState* m_samplerState;
};
}
+1
View File
@@ -78,6 +78,7 @@ void VideoBackend::InitBackendInfo()
g_Config.backend_info.bSupportsInternalResolutionFrameDumps = false;
g_Config.backend_info.bSupportsGPUTextureDecoding = false;
g_Config.backend_info.bSupportsST3CTextures = false;
g_Config.backend_info.bSupportsCopyToVram = true;
g_Config.backend_info.bSupportsBitfield = false;
g_Config.backend_info.bSupportsDynamicSamplerIndexing = false;
g_Config.backend_info.bSupportsBPTCTextures = false;
@@ -12,7 +12,6 @@
class XFBSource : public XFBSourceBase
{
public:
void DecodeToTexture(u32 xfb_addr, u32 fb_width, u32 fb_height) override {}
void CopyEFB(float gamma) override {}
};
+1 -1
View File
@@ -36,7 +36,7 @@ TargetRectangle Renderer::ConvertEFBRectangle(const EFBRectangle& rc)
return result;
}
void Renderer::SwapImpl(u32, u32, u32, u32, const EFBRectangle&, u64, float)
void Renderer::SwapImpl(AbstractTexture*, const EFBRectangle&, u64, float)
{
UpdateActiveConfig();
}
+1 -2
View File
@@ -21,8 +21,7 @@ public:
void BBoxWrite(int index, u16 value) override {}
TargetRectangle ConvertEFBRectangle(const EFBRectangle& rc) override;
void SwapImpl(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height, const EFBRectangle& rc,
u64 ticks, float gamma) override;
void SwapImpl(AbstractTexture* texture, const EFBRectangle& rc, u64 ticks, float Gamma) override;
void ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable,
u32 color, u32 z) override
@@ -530,7 +530,7 @@ void FramebufferManager::ResolveEFBStencilTexture()
void FramebufferManager::CopyToRealXFB(u32 xfbAddr, u32 fbStride, u32 fbHeight,
const EFBRectangle& sourceRc, float Gamma)
{
u8* xfb_in_ram = Memory::GetPointer(xfbAddr);
/* u8* xfb_in_ram = Memory::GetPointer(xfbAddr);
if (!xfb_in_ram)
{
WARN_LOG(VIDEO, "Tried to copy to invalid XFB address");
@@ -539,7 +539,7 @@ void FramebufferManager::CopyToRealXFB(u32 xfbAddr, u32 fbStride, u32 fbHeight,
TargetRectangle targetRc = g_renderer->ConvertEFBRectangle(sourceRc);
TextureConverter::EncodeToRamYUYV(ResolveAndGetRenderTarget(sourceRc), targetRc, xfb_in_ram,
sourceRc.GetWidth(), fbStride, fbHeight);
sourceRc.GetWidth(), fbStride, fbHeight);*/
}
GLuint FramebufferManager::GetResolvedFramebuffer()
@@ -615,11 +615,6 @@ XFBSource::~XFBSource()
glDeleteTextures(1, &texture);
}
void XFBSource::DecodeToTexture(u32 xfbAddr, u32 fbWidth, u32 fbHeight)
{
TextureConverter::DecodeToTexture(xfbAddr, fbWidth, fbHeight, texture);
}
void XFBSource::CopyEFB(float Gamma)
{
g_renderer->ResetAPIState();
@@ -54,7 +54,6 @@ struct XFBSource : public XFBSourceBase
~XFBSource();
void CopyEFB(float Gamma) override;
void DecodeToTexture(u32 xfbAddr, u32 fbWidth, u32 fbHeight) override;
const GLuint texture;
const int m_layers;
@@ -25,7 +25,7 @@ static const char s_vertex_shader[] = "out vec2 uv0;\n"
"void main(void) {\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 = rawpos * src_rect.zw + src_rect.xy;\n"
" uv0 = vec2(mix(src_rect.xy, src_rect.zw, rawpos));\n"
"}\n";
OpenGLPostProcessing::OpenGLPostProcessing() : m_initialized(false)
@@ -52,8 +52,8 @@ void OpenGLPostProcessing::BlitFromTexture(TargetRectangle src, TargetRectangle
glUniform4f(m_uniform_resolution, (float)src_width, (float)src_height, 1.0f / (float)src_width,
1.0f / (float)src_height);
glUniform4f(m_uniform_src_rect, src.left / (float)src_width, src.bottom / (float)src_height,
src.GetWidth() / (float)src_width, src.GetHeight() / (float)src_height);
glUniform4f(m_uniform_src_rect, src.left / (float)src_width, src.top / (float)src_height,
src.right / (float)src_width, src.bottom / (float)src_height);
glUniform1ui(m_uniform_time, (GLuint)m_timer.GetTimeElapsed());
glUniform1i(m_uniform_layer, layer);
+16 -140
View File
@@ -66,7 +66,6 @@ static std::unique_ptr<RasterFont> s_raster_font;
static int s_MSAASamples = 1;
static u32 s_last_multisamples = 1;
static bool s_last_stereo_mode = false;
static bool s_last_xfb_mode = false;
static bool s_vsync;
@@ -726,7 +725,6 @@ Renderer::Renderer()
s_MSAASamples = s_last_multisamples;
s_last_stereo_mode = g_ActiveConfig.iStereoMode > 0;
s_last_xfb_mode = g_ActiveConfig.bUseRealXFB;
// Handle VSync on/off
s_vsync = g_ActiveConfig.IsVSync();
@@ -1331,8 +1329,7 @@ void Renderer::SetBlendingState(const BlendingState& state)
}
// This function has the final picture. We adjust the aspect ratio here.
void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight,
const EFBRectangle& rc, u64 ticks, float Gamma)
void Renderer::SwapImpl(AbstractTexture* texture, const EFBRectangle& rc, u64 ticks, float Gamma)
{
if (g_ogl_config.bSupportsDebug)
{
@@ -1342,20 +1339,13 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight,
glDisable(GL_DEBUG_OUTPUT);
}
if ((!m_xfb_written && !g_ActiveConfig.RealXFBEnabled()) || !fbWidth || !fbHeight)
{
Core::Callback_VideoCopiedToXFB(false);
return;
}
auto* xfb_texture = static_cast<OGLTexture*>(texture);
u32 xfbCount = 0;
const XFBSourceBase* const* xfbSourceList =
FramebufferManager::GetXFBSource(xfbAddr, fbStride, fbHeight, &xfbCount);
if (g_ActiveConfig.VirtualXFBEnabled() && (!xfbSourceList || xfbCount == 0))
{
Core::Callback_VideoCopiedToXFB(false);
return;
}
TargetRectangle sourceRc = ConvertEFBRectangle(rc);
sourceRc.left = 0;
sourceRc.right = xfb_texture->config.width;
sourceRc.top = xfb_texture->config.height;
sourceRc.bottom = 0;
ResetAPIState();
@@ -1366,7 +1356,8 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight,
std::swap(flipped_trc.top, flipped_trc.bottom);
// Copy the framebuffer to screen.
DrawFrame(0, flipped_trc, rc, xfbAddr, xfbSourceList, xfbCount, fbWidth, fbStride, fbHeight);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
BlitScreen(sourceRc, flipped_trc, xfb_texture->GetRawTexIdentifier(), xfb_texture->config.width, xfb_texture->config.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.
@@ -1380,7 +1371,7 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight,
if (use_offscreen_buffer)
{
// DumpFrameUsingFBO resets GL_FRAMEBUFFER, so change back to the window for drawing OSD.
DumpFrameUsingFBO(rc, xfbAddr, xfbSourceList, xfbCount, fbWidth, fbStride, fbHeight, ticks);
DumpFrameUsingFBO(sourceRc, ticks);
}
else
{
@@ -1391,24 +1382,10 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight,
// Finish up the current frame, print some stats
SetWindowSize(fbStride, fbHeight);
SetWindowSize(xfb_texture->config.width, xfb_texture->config.height);
GLInterface->Update(); // just updates the render window position and the backbuffer size
bool xfbchanged = s_last_xfb_mode != g_ActiveConfig.bUseRealXFB;
if (FramebufferManagerBase::LastXfbWidth() != fbStride ||
FramebufferManagerBase::LastXfbHeight() != fbHeight)
{
xfbchanged = true;
unsigned int const last_w =
(fbStride < 1 || fbStride > MAX_XFB_WIDTH) ? MAX_XFB_WIDTH : fbStride;
unsigned int const last_h =
(fbHeight < 1 || fbHeight > MAX_XFB_HEIGHT) ? MAX_XFB_HEIGHT : fbHeight;
FramebufferManagerBase::SetLastXfbWidth(last_w);
FramebufferManagerBase::SetLastXfbHeight(last_h);
}
bool window_resized = false;
int window_width = static_cast<int>(std::max(GLInterface->GetBackBufferWidth(), 1u));
int window_height = static_cast<int>(std::max(GLInterface->GetBackBufferHeight(), 1u));
@@ -1428,9 +1405,8 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight,
stencil_buffer_enabled != BoundingBox::NeedsStencilBuffer() ||
s_last_stereo_mode != (g_ActiveConfig.iStereoMode > 0);
if (xfbchanged || window_resized || fb_needs_update)
if (window_resized || fb_needs_update)
{
s_last_xfb_mode = g_ActiveConfig.bUseRealXFB;
UpdateDrawRectangle();
}
if (fb_needs_update)
@@ -1523,110 +1499,13 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight,
ClearEFBCache();
}
void Renderer::DrawFrame(GLuint framebuffer, const TargetRectangle& target_rc,
const EFBRectangle& source_rc, u32 xfb_addr,
const XFBSourceBase* const* xfb_sources, u32 xfb_count, u32 fb_width,
u32 fb_stride, u32 fb_height)
{
if (g_ActiveConfig.bUseXFB)
{
if (g_ActiveConfig.bUseRealXFB)
DrawRealXFB(framebuffer, target_rc, xfb_sources, xfb_count, fb_width, fb_stride, fb_height);
else
DrawVirtualXFB(framebuffer, target_rc, xfb_addr, xfb_sources, xfb_count, fb_width, fb_stride,
fb_height);
}
else
{
DrawEFB(framebuffer, target_rc, source_rc);
}
}
void Renderer::DrawEFB(GLuint framebuffer, const TargetRectangle& target_rc,
const EFBRectangle& source_rc)
const TargetRectangle& source_rc)
{
TargetRectangle scaled_source_rc = ConvertEFBRectangle(source_rc);
// for msaa mode, we must resolve the efb content to non-msaa
GLuint tex = FramebufferManager::ResolveAndGetRenderTarget(source_rc);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
BlitScreen(scaled_source_rc, target_rc, tex, m_target_width, m_target_height);
}
void Renderer::DrawVirtualXFB(GLuint framebuffer, const TargetRectangle& target_rc, u32 xfb_addr,
const XFBSourceBase* const* xfb_sources, u32 xfb_count, u32 fb_width,
u32 fb_stride, u32 fb_height)
{
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
for (u32 i = 0; i < xfb_count; ++i)
{
const XFBSource* xfbSource = static_cast<const XFBSource*>(xfb_sources[i]);
TargetRectangle draw_rc;
TargetRectangle source_rc;
source_rc.left = xfbSource->sourceRc.left;
source_rc.right = xfbSource->sourceRc.right;
source_rc.top = xfbSource->sourceRc.top;
source_rc.bottom = xfbSource->sourceRc.bottom;
// use virtual xfb with offset
int xfbHeight = xfbSource->srcHeight;
int xfbWidth = xfbSource->srcWidth;
int hOffset = (static_cast<s32>(xfbSource->srcAddr) - static_cast<s32>(xfb_addr)) /
(static_cast<s32>(fb_stride) * 2);
draw_rc.top = target_rc.top - hOffset * target_rc.GetHeight() / static_cast<s32>(fb_height);
draw_rc.bottom =
target_rc.top - (hOffset + xfbHeight) * target_rc.GetHeight() / static_cast<s32>(fb_height);
draw_rc.left =
target_rc.left +
(target_rc.GetWidth() - xfbWidth * target_rc.GetWidth() / static_cast<s32>(fb_stride)) / 2;
draw_rc.right =
target_rc.left +
(target_rc.GetWidth() + xfbWidth * target_rc.GetWidth() / static_cast<s32>(fb_stride)) / 2;
// The following code disables auto stretch. Kept for reference.
// scale draw area for a 1 to 1 pixel mapping with the draw target
// float h_scale = static_cast<float>(fb_width) / static_cast<float>(target_rc.GetWidth());
// float v_scale = static_cast<float>(fb_height) / static_cast<float>(target_rc.GetHeight());
// draw_rc.top *= v_scale;
// draw_rc.bottom *= v_scale;
// draw_rc.left *= h_scale;
// draw_rc.right *= h_scale;
source_rc.right -= Renderer::EFBToScaledX(fb_stride - fb_width);
BlitScreen(source_rc, draw_rc, xfbSource->texture, xfbSource->texWidth, xfbSource->texHeight);
}
}
void Renderer::DrawRealXFB(GLuint framebuffer, const TargetRectangle& target_rc,
const XFBSourceBase* const* xfb_sources, u32 xfb_count, u32 fb_width,
u32 fb_stride, u32 fb_height)
{
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
for (u32 i = 0; i < xfb_count; ++i)
{
const XFBSource* xfbSource = static_cast<const XFBSource*>(xfb_sources[i]);
TargetRectangle source_rc;
source_rc.left = xfbSource->sourceRc.left;
source_rc.right = xfbSource->sourceRc.right;
source_rc.top = xfbSource->sourceRc.top;
source_rc.bottom = xfbSource->sourceRc.bottom;
source_rc.right -= fb_stride - fb_width;
// RealXFB doesn't call ConvertEFBRectangle for sourceRc, therefore it is still assuming a top-
// left origin. The top offset is always zero (see FramebufferManagerBase::GetRealXFBSource).
source_rc.top = source_rc.bottom;
source_rc.bottom = 0;
TargetRectangle draw_rc = target_rc;
BlitScreen(source_rc, draw_rc, xfbSource->texture, xfbSource->texWidth, xfbSource->texHeight);
}
BlitScreen(source_rc, target_rc, tex, m_target_width, m_target_height);
}
void Renderer::FlushFrameDump()
@@ -1683,9 +1562,7 @@ void Renderer::DumpFrame(const TargetRectangle& flipped_trc, u64 ticks)
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
}
void Renderer::DumpFrameUsingFBO(const EFBRectangle& source_rc, u32 xfb_addr,
const XFBSourceBase* const* xfb_sources, u32 xfb_count,
u32 fb_width, u32 fb_stride, u32 fb_height, u64 ticks)
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();
@@ -1705,8 +1582,7 @@ void Renderer::DumpFrameUsingFBO(const EFBRectangle& source_rc, u32 xfb_addr,
// 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);
DrawFrame(m_frame_dump_render_framebuffer, render_rc, source_rc, xfb_addr, xfb_sources, xfb_count,
fb_width, fb_stride, fb_height);
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);
+3 -17
View File
@@ -98,8 +98,7 @@ public:
TargetRectangle ConvertEFBRectangle(const EFBRectangle& rc) override;
void SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, const EFBRectangle& rc,
u64 ticks, float Gamma) override;
void SwapImpl(AbstractTexture* texture, const EFBRectangle& rc, u64 ticks, float Gamma) override;
void ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable,
u32 color, u32 z) override;
@@ -112,27 +111,14 @@ private:
void UpdateEFBCache(EFBAccessType type, u32 cacheRectIdx, const EFBRectangle& efbPixelRc,
const TargetRectangle& targetPixelRc, const void* data);
// Draw either the EFB, or specified XFB sources to the currently-bound framebuffer.
void DrawFrame(GLuint framebuffer, const TargetRectangle& target_rc,
const EFBRectangle& source_rc, u32 xfb_addr,
const XFBSourceBase* const* xfb_sources, u32 xfb_count, u32 fb_width,
u32 fb_stride, u32 fb_height);
void DrawEFB(GLuint framebuffer, const TargetRectangle& target_rc, const EFBRectangle& source_rc);
void DrawVirtualXFB(GLuint framebuffer, const TargetRectangle& target_rc, u32 xfb_addr,
const XFBSourceBase* const* xfb_sources, u32 xfb_count, u32 fb_width,
u32 fb_stride, u32 fb_height);
void DrawRealXFB(GLuint framebuffer, const TargetRectangle& target_rc,
const XFBSourceBase* const* xfb_sources, u32 xfb_count, u32 fb_width,
u32 fb_stride, u32 fb_height);
void DrawEFB(GLuint framebuffer, const TargetRectangle& target_rc, const TargetRectangle& source_rc);
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 EFBRectangle& source_rc, u32 xfb_addr,
const XFBSourceBase* const* xfb_sources, u32 xfb_count, u32 fb_width,
u32 fb_stride, u32 fb_height, 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);
+1
View File
@@ -91,6 +91,7 @@ void VideoBackend::InitBackendInfo()
g_Config.backend_info.bSupportsReversedDepthRange = true;
g_Config.backend_info.bSupportsMultithreading = false;
g_Config.backend_info.bSupportsInternalResolutionFrameDumps = true;
g_Config.backend_info.bSupportsCopyToVram = true;
// TODO: There is a bug here, if texel buffers are not supported the graphics options
// will show the option when it is not supported. The only way around this would be
@@ -520,15 +520,6 @@ void CopyToXFB(yuv422_packed* xfb_in_ram, u32 fbWidth, u32 fbHeight, const EFBRe
// Scanline buffer, leave room for borders
yuv444 scanline[EFB_WIDTH + 2];
// our internal yuv444 type is not normalized, so black is {0, 0, 0} instead of {16, 128, 128}
yuv444 black;
black.Y = 0;
black.U = 0;
black.V = 0;
scanline[0] = black; // black border at start
scanline[right + 1] = black; // black border at end
for (u16 y = sourceRc.top; y < sourceRc.bottom; y++)
{
// Get a scanline of YUV pixels in 4:4:4 format
@@ -538,6 +529,10 @@ void CopyToXFB(yuv422_packed* xfb_in_ram, u32 fbWidth, u32 fbHeight, const EFBRe
scanline[i] = GetColorYUV(x, y);
}
// Flipper clamps the border colors
scanline[0] = scanline[1];
scanline[right + 1] = scanline[right];
// And Downsample them to 4:2:2
for (int i = 1, x = left; x < right; i += 2, x += 2)
{
@@ -562,26 +557,7 @@ void CopyToXFB(yuv422_packed* xfb_in_ram, u32 fbWidth, u32 fbHeight, const EFBRe
// main memory or doing a yuyv conversion
void BypassXFB(u8* texture, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc, float Gamma)
{
if (fbWidth * fbHeight > MAX_XFB_WIDTH * MAX_XFB_HEIGHT)
{
ERROR_LOG(VIDEO, "Framebuffer is too large: %ix%i", fbWidth, fbHeight);
return;
}
size_t textureAddress = 0;
const int left = sourceRc.left;
const int right = sourceRc.right;
for (u16 y = sourceRc.top; y < sourceRc.bottom; y++)
{
for (u16 x = left; x < right; x++)
{
const u32 color = Common::swap32(GetColor(x, y) | 0xFF);
std::memcpy(&texture[textureAddress], &color, sizeof(u32));
textureAddress += sizeof(u32);
}
}
// TODO: Upload directly to texture cache.
}
bool ZCompare(u16 x, u16 y, u32 z)

Some files were not shown because too many files have changed in this diff Show More