Merge pull request #4436 from stenzek/vulkan-full-ir-framedump
VideoBackends: Internal resolution frame dumping
This commit is contained in:
commit
0212741574
|
@ -236,6 +236,11 @@ static wxString cache_hires_textures_desc =
|
|||
"more RAM but fixes possible stuttering.\n\nIf unsure, leave this unchecked.");
|
||||
static wxString dump_efb_desc = wxTRANSLATE(
|
||||
"Dump the contents of EFB copies to User/Dump/Textures/.\n\nIf unsure, leave this unchecked.");
|
||||
static wxString internal_resolution_frame_dumping_desc = wxTRANSLATE(
|
||||
"Create frame dumps and screenshots at the internal resolution of the renderer, rather than "
|
||||
"the size of the window it is displayed within. If the aspect ratio is widescreen, the output "
|
||||
"image will be scaled horizontally to preserve the vertical resolution.\n\nIf unsure, leave "
|
||||
"this unchecked.");
|
||||
#if defined(HAVE_LIBAV) || defined(_WIN32)
|
||||
static wxString use_ffv1_desc =
|
||||
wxTRANSLATE("Encode frame dumps using the FFV1 codec.\n\nIf unsure, leave this unchecked.");
|
||||
|
@ -858,6 +863,14 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string& title)
|
|||
CreateCheckBox(page_advanced, _("Prefetch Custom Textures"),
|
||||
wxGetTranslation(cache_hires_textures_desc), vconfig.bCacheHiresTextures);
|
||||
szr_utility->Add(cache_hires_textures);
|
||||
|
||||
if (vconfig.backend_info.bSupportsInternalResolutionFrameDumps)
|
||||
{
|
||||
szr_utility->Add(CreateCheckBox(page_advanced, _("Full Resolution Frame Dumps"),
|
||||
wxGetTranslation(internal_resolution_frame_dumping_desc),
|
||||
vconfig.bInternalResolutionFrameDumps));
|
||||
}
|
||||
|
||||
szr_utility->Add(CreateCheckBox(page_advanced, _("Dump EFB Target"),
|
||||
wxGetTranslation(dump_efb_desc), vconfig.bDumpEFBTarget));
|
||||
szr_utility->Add(CreateCheckBox(page_advanced, _("Free Look"),
|
||||
|
|
|
@ -243,13 +243,13 @@ Renderer::Renderer(void*& window_handle)
|
|||
FramebufferManagerBase::SetLastXfbWidth(MAX_XFB_WIDTH);
|
||||
FramebufferManagerBase::SetLastXfbHeight(MAX_XFB_HEIGHT);
|
||||
|
||||
UpdateDrawRectangle(s_backbuffer_width, s_backbuffer_height);
|
||||
UpdateDrawRectangle();
|
||||
|
||||
s_last_multisamples = g_ActiveConfig.iMultisamples;
|
||||
s_last_efb_scale = g_ActiveConfig.iEFBScale;
|
||||
s_last_stereo_mode = g_ActiveConfig.iStereoMode > 0;
|
||||
s_last_xfb_mode = g_ActiveConfig.bUseRealXFB;
|
||||
CalculateTargetSize(s_backbuffer_width, s_backbuffer_height);
|
||||
CalculateTargetSize();
|
||||
PixelShaderManager::SetEfbScaleChanged();
|
||||
|
||||
SetupDeviceObjects();
|
||||
|
@ -732,7 +732,7 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight,
|
|||
ResetAPIState();
|
||||
|
||||
// Prepare to copy the XFBs to our backbuffer
|
||||
UpdateDrawRectangle(s_backbuffer_width, s_backbuffer_height);
|
||||
UpdateDrawRectangle();
|
||||
TargetRectangle targetRc = GetTargetRectangle();
|
||||
|
||||
D3D::context->OMSetRenderTargets(1, &D3D::GetBackBuffer()->GetRTV(), nullptr);
|
||||
|
@ -867,7 +867,7 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight,
|
|||
D3D::Present();
|
||||
|
||||
// Resize the back buffers NOW to avoid flickering
|
||||
if (CalculateTargetSize(s_backbuffer_width, s_backbuffer_height) || xfbchanged || windowResized ||
|
||||
if (CalculateTargetSize() || xfbchanged || windowResized ||
|
||||
s_last_efb_scale != g_ActiveConfig.iEFBScale ||
|
||||
s_last_multisamples != g_ActiveConfig.iMultisamples ||
|
||||
s_last_stereo_mode != (g_ActiveConfig.iStereoMode > 0))
|
||||
|
@ -886,7 +886,7 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight,
|
|||
s_backbuffer_height = D3D::GetBackBufferHeight();
|
||||
}
|
||||
|
||||
UpdateDrawRectangle(s_backbuffer_width, s_backbuffer_height);
|
||||
UpdateDrawRectangle();
|
||||
|
||||
s_last_efb_scale = g_ActiveConfig.iEFBScale;
|
||||
s_last_stereo_mode = g_ActiveConfig.iStereoMode > 0;
|
||||
|
|
|
@ -72,6 +72,7 @@ void VideoBackend::InitBackendInfo()
|
|||
g_Config.backend_info.bSupportsDepthClamp = true;
|
||||
g_Config.backend_info.bSupportsReversedDepthRange = false;
|
||||
g_Config.backend_info.bSupportsMultithreading = false;
|
||||
g_Config.backend_info.bSupportsInternalResolutionFrameDumps = false;
|
||||
|
||||
IDXGIFactory* factory;
|
||||
IDXGIAdapter* ad;
|
||||
|
|
|
@ -222,13 +222,13 @@ Renderer::Renderer(void*& window_handle)
|
|||
FramebufferManagerBase::SetLastXfbWidth(MAX_XFB_WIDTH);
|
||||
FramebufferManagerBase::SetLastXfbHeight(MAX_XFB_HEIGHT);
|
||||
|
||||
UpdateDrawRectangle(s_backbuffer_width, s_backbuffer_height);
|
||||
UpdateDrawRectangle();
|
||||
|
||||
s_last_multisamples = g_ActiveConfig.iMultisamples;
|
||||
s_last_efb_scale = g_ActiveConfig.iEFBScale;
|
||||
s_last_stereo_mode = g_ActiveConfig.iStereoMode > 0;
|
||||
s_last_xfb_mode = g_ActiveConfig.bUseRealXFB;
|
||||
CalculateTargetSize(s_backbuffer_width, s_backbuffer_height);
|
||||
CalculateTargetSize();
|
||||
PixelShaderManager::SetEfbScaleChanged();
|
||||
|
||||
SetupDeviceObjects();
|
||||
|
@ -654,7 +654,7 @@ void Renderer::SwapImpl(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height
|
|||
BBox::Invalidate();
|
||||
|
||||
// Prepare to copy the XFBs to our backbuffer
|
||||
UpdateDrawRectangle(s_backbuffer_width, s_backbuffer_height);
|
||||
UpdateDrawRectangle();
|
||||
TargetRectangle target_rc = GetTargetRectangle();
|
||||
|
||||
D3D::GetBackBuffer()->TransitionToResourceState(D3D::current_command_list,
|
||||
|
@ -819,8 +819,8 @@ void Renderer::SwapImpl(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height
|
|||
D3D::Present();
|
||||
|
||||
// Resize the back buffers NOW to avoid flickering
|
||||
if (CalculateTargetSize(s_backbuffer_width, s_backbuffer_height) || xfb_changed ||
|
||||
window_resized || s_last_efb_scale != g_ActiveConfig.iEFBScale ||
|
||||
if (CalculateTargetSize() || xfb_changed || window_resized ||
|
||||
s_last_efb_scale != g_ActiveConfig.iEFBScale ||
|
||||
s_last_multisamples != g_ActiveConfig.iMultisamples ||
|
||||
s_last_stereo_mode != (g_ActiveConfig.iStereoMode > 0))
|
||||
{
|
||||
|
@ -851,7 +851,7 @@ void Renderer::SwapImpl(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height
|
|||
s_backbuffer_height = D3D::GetBackBufferHeight();
|
||||
}
|
||||
|
||||
UpdateDrawRectangle(s_backbuffer_width, s_backbuffer_height);
|
||||
UpdateDrawRectangle();
|
||||
|
||||
s_last_efb_scale = g_ActiveConfig.iEFBScale;
|
||||
s_last_stereo_mode = g_ActiveConfig.iStereoMode > 0;
|
||||
|
|
|
@ -75,6 +75,7 @@ void VideoBackend::InitBackendInfo()
|
|||
g_Config.backend_info.bSupportsDepthClamp = true;
|
||||
g_Config.backend_info.bSupportsReversedDepthRange = false;
|
||||
g_Config.backend_info.bSupportsMultithreading = false;
|
||||
g_Config.backend_info.bSupportsInternalResolutionFrameDumps = false;
|
||||
|
||||
IDXGIFactory* factory;
|
||||
IDXGIAdapter* ad;
|
||||
|
|
|
@ -41,6 +41,7 @@ void VideoBackend::InitBackendInfo()
|
|||
g_Config.backend_info.bSupportsDepthClamp = true;
|
||||
g_Config.backend_info.bSupportsReversedDepthRange = true;
|
||||
g_Config.backend_info.bSupportsMultithreading = false;
|
||||
g_Config.backend_info.bSupportsInternalResolutionFrameDumps = false;
|
||||
|
||||
// aamodes: We only support 1 sample, so no MSAA
|
||||
g_Config.backend_info.Adapters.clear();
|
||||
|
|
|
@ -44,8 +44,6 @@ void OpenGLPostProcessing::BlitFromTexture(TargetRectangle src, TargetRectangle
|
|||
{
|
||||
ApplyShader();
|
||||
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||
|
||||
glViewport(dst.left, dst.bottom, dst.GetWidth(), dst.GetHeight());
|
||||
|
||||
OpenGL_BindAttributelessVAO();
|
||||
|
|
|
@ -700,10 +700,10 @@ Renderer::Renderer()
|
|||
FramebufferManagerBase::SetLastXfbWidth(MAX_XFB_WIDTH);
|
||||
FramebufferManagerBase::SetLastXfbHeight(MAX_XFB_HEIGHT);
|
||||
|
||||
UpdateDrawRectangle(s_backbuffer_width, s_backbuffer_height);
|
||||
UpdateDrawRectangle();
|
||||
|
||||
s_last_efb_scale = g_ActiveConfig.iEFBScale;
|
||||
CalculateTargetSize(s_backbuffer_width, s_backbuffer_height);
|
||||
CalculateTargetSize();
|
||||
|
||||
PixelShaderManager::SetEfbScaleChanged();
|
||||
|
||||
|
@ -768,8 +768,7 @@ Renderer::~Renderer()
|
|||
{
|
||||
FlushFrameDump();
|
||||
FinishFrameData();
|
||||
if (m_frame_dumping_pbo[0])
|
||||
glDeleteBuffers(2, m_frame_dumping_pbo.data());
|
||||
DestroyFrameDumpResources();
|
||||
}
|
||||
|
||||
void Renderer::Shutdown()
|
||||
|
@ -1373,84 +1372,37 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight,
|
|||
|
||||
ResetAPIState();
|
||||
|
||||
UpdateDrawRectangle(s_backbuffer_width, s_backbuffer_height);
|
||||
UpdateDrawRectangle();
|
||||
TargetRectangle flipped_trc = GetTargetRectangle();
|
||||
|
||||
// Flip top and bottom for some reason; TODO: Fix the code to suck less?
|
||||
std::swap(flipped_trc.top, flipped_trc.bottom);
|
||||
|
||||
// Copy the framebuffer to screen.
|
||||
const XFBSource* xfbSource = nullptr;
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||
DrawFrame(flipped_trc, rc, xfbAddr, xfbSourceList, xfbCount, fbWidth, fbStride, fbHeight);
|
||||
|
||||
if (g_ActiveConfig.bUseXFB)
|
||||
// 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())
|
||||
{
|
||||
// draw each xfb source
|
||||
for (u32 i = 0; i < xfbCount; ++i)
|
||||
// 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)
|
||||
{
|
||||
xfbSource = (const XFBSource*)xfbSourceList[i];
|
||||
|
||||
TargetRectangle drawRc;
|
||||
TargetRectangle sourceRc;
|
||||
sourceRc.left = xfbSource->sourceRc.left;
|
||||
sourceRc.right = xfbSource->sourceRc.right;
|
||||
sourceRc.top = xfbSource->sourceRc.top;
|
||||
sourceRc.bottom = xfbSource->sourceRc.bottom;
|
||||
|
||||
if (g_ActiveConfig.bUseRealXFB)
|
||||
{
|
||||
drawRc = flipped_trc;
|
||||
sourceRc.right -= fbStride - fbWidth;
|
||||
|
||||
// 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).
|
||||
sourceRc.top = sourceRc.bottom;
|
||||
sourceRc.bottom = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// use virtual xfb with offset
|
||||
int xfbHeight = xfbSource->srcHeight;
|
||||
int xfbWidth = xfbSource->srcWidth;
|
||||
int hOffset = ((s32)xfbSource->srcAddr - (s32)xfbAddr) / ((s32)fbStride * 2);
|
||||
|
||||
drawRc.top = flipped_trc.top - hOffset * flipped_trc.GetHeight() / (s32)fbHeight;
|
||||
drawRc.bottom =
|
||||
flipped_trc.top - (hOffset + xfbHeight) * flipped_trc.GetHeight() / (s32)fbHeight;
|
||||
drawRc.left =
|
||||
flipped_trc.left +
|
||||
(flipped_trc.GetWidth() - xfbWidth * flipped_trc.GetWidth() / (s32)fbStride) / 2;
|
||||
drawRc.right =
|
||||
flipped_trc.left +
|
||||
(flipped_trc.GetWidth() + xfbWidth * flipped_trc.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)flipped_trc.GetHeight();
|
||||
// float hScale = (float)fbWidth / (float)flipped_trc.GetWidth();
|
||||
// drawRc.top *= vScale;
|
||||
// drawRc.bottom *= vScale;
|
||||
// drawRc.left *= hScale;
|
||||
// drawRc.right *= hScale;
|
||||
|
||||
sourceRc.right -= Renderer::EFBToScaledX(fbStride - fbWidth);
|
||||
}
|
||||
|
||||
BlitScreen(sourceRc, drawRc, xfbSource->texture, xfbSource->texWidth, xfbSource->texHeight);
|
||||
// DumpFrameUsingFBO resets GL_FRAMEBUFFER, so change back to the window for drawing OSD.
|
||||
DumpFrameUsingFBO(rc, xfbAddr, xfbSourceList, xfbCount, fbWidth, fbStride, fbHeight, ticks);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
|
||||
DumpFrame(flipped_trc, ticks);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
TargetRectangle targetRc = ConvertEFBRectangle(rc);
|
||||
|
||||
// for msaa mode, we must resolve the efb content to non-msaa
|
||||
GLuint tex = FramebufferManager::ResolveAndGetRenderTarget(rc);
|
||||
BlitScreen(targetRc, flipped_trc, tex, s_target_width, s_target_height);
|
||||
}
|
||||
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
|
||||
|
||||
DumpFrame(flipped_trc, ticks);
|
||||
|
||||
// Finish up the current frame, print some stats
|
||||
|
||||
|
@ -1484,7 +1436,7 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight,
|
|||
s_last_efb_scale = g_ActiveConfig.iEFBScale;
|
||||
}
|
||||
bool TargetSizeChanged = false;
|
||||
if (CalculateTargetSize(s_backbuffer_width, s_backbuffer_height))
|
||||
if (CalculateTargetSize())
|
||||
{
|
||||
TargetSizeChanged = true;
|
||||
}
|
||||
|
@ -1494,7 +1446,7 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight,
|
|||
{
|
||||
s_last_xfb_mode = g_ActiveConfig.bUseRealXFB;
|
||||
|
||||
UpdateDrawRectangle(s_backbuffer_width, s_backbuffer_height);
|
||||
UpdateDrawRectangle();
|
||||
|
||||
if (TargetSizeChanged || s_last_multisamples != g_ActiveConfig.iMultisamples ||
|
||||
s_last_stereo_mode != (g_ActiveConfig.iStereoMode > 0))
|
||||
|
@ -1580,6 +1532,104 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight,
|
|||
ClearEFBCache();
|
||||
}
|
||||
|
||||
void Renderer::DrawFrame(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(target_rc, xfb_sources, xfb_count, fb_width, fb_stride, fb_height);
|
||||
else
|
||||
DrawVirtualXFB(target_rc, xfb_addr, xfb_sources, xfb_count, fb_width, fb_stride, fb_height);
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawEFB(target_rc, source_rc);
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::DrawEFB(const TargetRectangle& target_rc, const EFBRectangle& 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);
|
||||
BlitScreen(scaled_source_rc, target_rc, tex, s_target_width, s_target_height);
|
||||
}
|
||||
|
||||
void Renderer::DrawVirtualXFB(const TargetRectangle& target_rc, 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* 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(const TargetRectangle& target_rc,
|
||||
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* 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);
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::FlushFrameDump()
|
||||
{
|
||||
if (!m_last_frame_exported)
|
||||
|
@ -1598,9 +1648,6 @@ void Renderer::FlushFrameDump()
|
|||
|
||||
void Renderer::DumpFrame(const TargetRectangle& flipped_trc, u64 ticks)
|
||||
{
|
||||
if (!IsFrameDumping())
|
||||
return;
|
||||
|
||||
if (!m_frame_dumping_pbo[0])
|
||||
{
|
||||
glGenBuffers(2, m_frame_dumping_pbo.data());
|
||||
|
@ -1637,6 +1684,82 @@ 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)
|
||||
{
|
||||
// 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<u32>(render_rc.GetWidth());
|
||||
u32 render_height = static_cast<u32>(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.
|
||||
FramebufferManager::SetFramebuffer(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);
|
||||
DrawFrame(render_rc, source_rc, xfb_addr, xfb_sources, xfb_count, fb_width, fb_stride, fb_height);
|
||||
|
||||
// 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);
|
||||
FramebufferManager::SetFramebuffer(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;
|
||||
TextureCache::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()
|
||||
{
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
#include <string>
|
||||
#include "VideoCommon/RenderBase.h"
|
||||
|
||||
struct XFBSourceBase;
|
||||
|
||||
namespace OGL
|
||||
{
|
||||
void ClearEFBCache();
|
||||
|
@ -110,11 +112,33 @@ 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(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(const TargetRectangle& target_rc, const EFBRectangle& source_rc);
|
||||
void DrawVirtualXFB(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(const TargetRectangle& target_rc, const XFBSourceBase* const* xfb_sources,
|
||||
u32 xfb_count, u32 fb_width, u32 fb_stride, u32 fb_height);
|
||||
|
||||
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);
|
||||
|
||||
// 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<u32, 2> m_frame_dumping_pbo = {};
|
||||
|
|
|
@ -104,6 +104,7 @@ void VideoBackend::InitBackendInfo()
|
|||
g_Config.backend_info.bSupportsSSAA = true;
|
||||
g_Config.backend_info.bSupportsReversedDepthRange = true;
|
||||
g_Config.backend_info.bSupportsMultithreading = false;
|
||||
g_Config.backend_info.bSupportsInternalResolutionFrameDumps = true;
|
||||
|
||||
// Overwritten in Render.cpp later
|
||||
g_Config.backend_info.bSupportsDualSourceBlend = true;
|
||||
|
|
|
@ -132,6 +132,7 @@ void VideoSoftware::InitBackendInfo()
|
|||
g_Config.backend_info.bSupportsOversizedViewports = true;
|
||||
g_Config.backend_info.bSupportsPrimitiveRestart = false;
|
||||
g_Config.backend_info.bSupportsMultithreading = false;
|
||||
g_Config.backend_info.bSupportsInternalResolutionFrameDumps = false;
|
||||
|
||||
// aamodes
|
||||
g_Config.backend_info.AAModes = {1};
|
||||
|
|
|
@ -54,8 +54,8 @@ Renderer::Renderer(std::unique_ptr<SwapChain> swap_chain) : m_swap_chain(std::mo
|
|||
s_backbuffer_width = m_swap_chain ? m_swap_chain->GetWidth() : MAX_XFB_WIDTH;
|
||||
s_backbuffer_height = m_swap_chain ? m_swap_chain->GetHeight() : MAX_XFB_HEIGHT;
|
||||
s_last_efb_scale = g_ActiveConfig.iEFBScale;
|
||||
UpdateDrawRectangle(s_backbuffer_width, s_backbuffer_height);
|
||||
CalculateTargetSize(s_backbuffer_width, s_backbuffer_height);
|
||||
UpdateDrawRectangle();
|
||||
CalculateTargetSize();
|
||||
PixelShaderManager::SetEfbScaleChanged();
|
||||
}
|
||||
|
||||
|
@ -711,13 +711,7 @@ bool Renderer::DrawFrameDump(const EFBRectangle& source_rect, u32 xfb_addr,
|
|||
const XFBSourceBase* const* xfb_sources, u32 xfb_count, u32 fb_width,
|
||||
u32 fb_stride, u32 fb_height, u64 ticks)
|
||||
{
|
||||
// Draw the screenshot to an image containing only the active screen area, removing any
|
||||
// borders as a result of the game rendering in a different aspect ratio.
|
||||
TargetRectangle target_rect = GetTargetRectangle();
|
||||
target_rect.right = target_rect.GetWidth();
|
||||
target_rect.bottom = target_rect.GetHeight();
|
||||
target_rect.left = 0;
|
||||
target_rect.top = 0;
|
||||
TargetRectangle target_rect = CalculateFrameDumpDrawRectangle();
|
||||
u32 width = std::max(1u, static_cast<u32>(target_rect.GetWidth()));
|
||||
u32 height = std::max(1u, static_cast<u32>(target_rect.GetHeight()));
|
||||
if (!ResizeFrameDumpBuffer(width, height))
|
||||
|
@ -998,8 +992,8 @@ void Renderer::CheckForTargetResize(u32 fb_width, u32 fb_stride, u32 fb_height)
|
|||
FramebufferManagerBase::SetLastXfbHeight(new_height);
|
||||
|
||||
// Changing the XFB source area will likely change the final drawing rectangle.
|
||||
UpdateDrawRectangle(s_backbuffer_width, s_backbuffer_height);
|
||||
if (CalculateTargetSize(s_backbuffer_width, s_backbuffer_height))
|
||||
UpdateDrawRectangle();
|
||||
if (CalculateTargetSize())
|
||||
{
|
||||
PixelShaderManager::SetEfbScaleChanged();
|
||||
ResizeEFBTextures();
|
||||
|
@ -1112,11 +1106,11 @@ void Renderer::CheckForConfigChanges()
|
|||
|
||||
// If the aspect ratio is changed, this changes the area that the game is drawn to.
|
||||
if (aspect_changed)
|
||||
UpdateDrawRectangle(s_backbuffer_width, s_backbuffer_height);
|
||||
UpdateDrawRectangle();
|
||||
|
||||
if (efb_scale_changed || aspect_changed)
|
||||
{
|
||||
if (CalculateTargetSize(s_backbuffer_width, s_backbuffer_height))
|
||||
if (CalculateTargetSize())
|
||||
ResizeEFBTextures();
|
||||
}
|
||||
|
||||
|
@ -1157,8 +1151,8 @@ void Renderer::OnSwapChainResized()
|
|||
{
|
||||
s_backbuffer_width = m_swap_chain->GetWidth();
|
||||
s_backbuffer_height = m_swap_chain->GetHeight();
|
||||
UpdateDrawRectangle(s_backbuffer_width, s_backbuffer_height);
|
||||
if (CalculateTargetSize(s_backbuffer_width, s_backbuffer_height))
|
||||
UpdateDrawRectangle();
|
||||
if (CalculateTargetSize())
|
||||
{
|
||||
PixelShaderManager::SetEfbScaleChanged();
|
||||
ResizeEFBTextures();
|
||||
|
|
|
@ -233,14 +233,15 @@ void VulkanContext::PopulateBackendInfo(VideoConfig* config)
|
|||
config->backend_info.bSupportsPaletteConversion = true; // Assumed support.
|
||||
config->backend_info.bSupportsClipControl = true; // Assumed support.
|
||||
config->backend_info.bSupportsMultithreading = true; // Assumed support.
|
||||
config->backend_info.bSupportsPostProcessing = false; // No support yet.
|
||||
config->backend_info.bSupportsDualSourceBlend = false; // Dependent on features.
|
||||
config->backend_info.bSupportsGeometryShaders = false; // Dependent on features.
|
||||
config->backend_info.bSupportsGSInstancing = false; // Dependent on features.
|
||||
config->backend_info.bSupportsBBox = false; // Dependent on features.
|
||||
config->backend_info.bSupportsSSAA = false; // Dependent on features.
|
||||
config->backend_info.bSupportsDepthClamp = false; // Dependent on features.
|
||||
config->backend_info.bSupportsReversedDepthRange = false; // No support yet due to driver bugs.
|
||||
config->backend_info.bSupportsInternalResolutionFrameDumps = true; // Assumed support.
|
||||
config->backend_info.bSupportsPostProcessing = false; // No support yet.
|
||||
config->backend_info.bSupportsDualSourceBlend = false; // Dependent on features.
|
||||
config->backend_info.bSupportsGeometryShaders = false; // Dependent on features.
|
||||
config->backend_info.bSupportsGSInstancing = false; // Dependent on features.
|
||||
config->backend_info.bSupportsBBox = false; // Dependent on features.
|
||||
config->backend_info.bSupportsSSAA = false; // Dependent on features.
|
||||
config->backend_info.bSupportsDepthClamp = false; // Dependent on features.
|
||||
config->backend_info.bSupportsReversedDepthRange = false; // No support yet due to driver bugs.
|
||||
}
|
||||
|
||||
void VulkanContext::PopulateBackendInfoAdapters(VideoConfig* config, const GPUList& gpu_list)
|
||||
|
|
|
@ -60,6 +60,8 @@ public:
|
|||
static int ScaleToVirtualXfbHeight(int y);
|
||||
|
||||
static unsigned int GetEFBLayers() { return m_EFBLayers; }
|
||||
virtual void GetTargetSize(unsigned int* width, unsigned int* height) = 0;
|
||||
|
||||
protected:
|
||||
struct VirtualXFB
|
||||
{
|
||||
|
@ -79,8 +81,6 @@ protected:
|
|||
private:
|
||||
virtual std::unique_ptr<XFBSourceBase>
|
||||
CreateXFBSource(unsigned int target_width, unsigned int target_height, unsigned int layers) = 0;
|
||||
// TODO: figure out why OGL is different for this guy
|
||||
virtual void GetTargetSize(unsigned int* width, unsigned int* height) = 0;
|
||||
|
||||
static VirtualXFBListType::iterator FindVirtualXFB(u32 xfbAddr, u32 width, u32 height);
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <mutex>
|
||||
#include <string>
|
||||
|
||||
#include "Common/Assert.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/Event.h"
|
||||
#include "Common/FileUtil.h"
|
||||
|
@ -188,7 +189,7 @@ void Renderer::CalculateTargetScale(int x, int y, int* scaledX, int* scaledY)
|
|||
}
|
||||
|
||||
// return true if target size changed
|
||||
bool Renderer::CalculateTargetSize(unsigned int framebuffer_width, unsigned int framebuffer_height)
|
||||
bool Renderer::CalculateTargetSize()
|
||||
{
|
||||
int newEFBWidth, newEFBHeight;
|
||||
newEFBWidth = newEFBHeight = 0;
|
||||
|
@ -449,10 +450,80 @@ void Renderer::DrawDebugText()
|
|||
g_renderer->RenderText(final_yellow, 20, 20, 0xFFFFFF00);
|
||||
}
|
||||
|
||||
void Renderer::UpdateDrawRectangle(int backbuffer_width, int backbuffer_height)
|
||||
float Renderer::CalculateDrawAspectRatio(int target_width, int target_height)
|
||||
{
|
||||
float FloatGLWidth = (float)backbuffer_width;
|
||||
float FloatGLHeight = (float)backbuffer_height;
|
||||
// The dimensions are the sizes that are used to create the EFB/backbuffer textures, so
|
||||
// they should always be greater than zero.
|
||||
_assert_(target_width > 0 && target_height > 0);
|
||||
if (g_ActiveConfig.iAspectRatio == ASPECT_STRETCH)
|
||||
{
|
||||
// If stretch is enabled, we prefer the aspect ratio of the window.
|
||||
return (static_cast<float>(target_width) / static_cast<float>(target_height)) /
|
||||
(static_cast<float>(s_backbuffer_width) / static_cast<float>(s_backbuffer_height));
|
||||
}
|
||||
|
||||
// The rendering window aspect ratio as a proportion of the 4:3 or 16:9 ratio
|
||||
if (g_ActiveConfig.iAspectRatio == ASPECT_ANALOG_WIDE ||
|
||||
(g_ActiveConfig.iAspectRatio != ASPECT_ANALOG && Core::g_aspect_wide))
|
||||
{
|
||||
return (static_cast<float>(target_width) / static_cast<float>(target_height)) /
|
||||
AspectToWidescreen(VideoInterface::GetAspectRatio());
|
||||
}
|
||||
else
|
||||
{
|
||||
return (static_cast<float>(target_width) / static_cast<float>(target_height)) /
|
||||
VideoInterface::GetAspectRatio();
|
||||
}
|
||||
}
|
||||
|
||||
TargetRectangle Renderer::CalculateFrameDumpDrawRectangle()
|
||||
{
|
||||
// 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.
|
||||
// Also do this if RealXFB is enabled, since the image has been downscaled for the XFB copy
|
||||
// anyway, and there's no point writing an upscaled frame with no filtering.
|
||||
if (!g_ActiveConfig.bInternalResolutionFrameDumps || g_ActiveConfig.RealXFBEnabled())
|
||||
{
|
||||
// But still remove the borders, since the caller expects this.
|
||||
rc.right = target_rc.GetWidth();
|
||||
rc.bottom = target_rc.GetHeight();
|
||||
return rc;
|
||||
}
|
||||
|
||||
// Grab the dimensions of the EFB textures, we scale either of these depending on the ratio.
|
||||
unsigned int efb_width, efb_height;
|
||||
g_framebuffer_manager->GetTargetSize(&efb_width, &efb_height);
|
||||
|
||||
// Scale either the width or height depending the content aspect ratio.
|
||||
// This way we preserve as much resolution as possible when scaling.
|
||||
float ratio = CalculateDrawAspectRatio(efb_width, efb_height);
|
||||
float draw_width, draw_height;
|
||||
if (ratio >= 1.0f)
|
||||
{
|
||||
// Preserve horizontal resolution, scale vertically.
|
||||
draw_width = static_cast<float>(efb_width);
|
||||
draw_height = static_cast<float>(efb_height) * ratio;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Preserve vertical resolution, scale horizontally.
|
||||
draw_width = static_cast<float>(efb_width) / ratio;
|
||||
draw_height = static_cast<float>(efb_height);
|
||||
}
|
||||
|
||||
rc.right = static_cast<int>(std::ceil(draw_width));
|
||||
rc.bottom = static_cast<int>(std::ceil(draw_height));
|
||||
return rc;
|
||||
}
|
||||
|
||||
void Renderer::UpdateDrawRectangle()
|
||||
{
|
||||
float FloatGLWidth = static_cast<float>(s_backbuffer_width);
|
||||
float FloatGLHeight = static_cast<float>(s_backbuffer_height);
|
||||
float FloatXOffset = 0;
|
||||
float FloatYOffset = 0;
|
||||
|
||||
|
@ -511,17 +582,7 @@ void Renderer::UpdateDrawRectangle(int backbuffer_width, int backbuffer_height)
|
|||
// Check for force-settings and override.
|
||||
|
||||
// The rendering window aspect ratio as a proportion of the 4:3 or 16:9 ratio
|
||||
float Ratio;
|
||||
if (g_ActiveConfig.iAspectRatio == ASPECT_ANALOG_WIDE ||
|
||||
(g_ActiveConfig.iAspectRatio != ASPECT_ANALOG && Core::g_aspect_wide))
|
||||
{
|
||||
Ratio = (WinWidth / WinHeight) / AspectToWidescreen(VideoInterface::GetAspectRatio());
|
||||
}
|
||||
else
|
||||
{
|
||||
Ratio = (WinWidth / WinHeight) / VideoInterface::GetAspectRatio();
|
||||
}
|
||||
|
||||
float Ratio = CalculateDrawAspectRatio(s_backbuffer_width, s_backbuffer_height);
|
||||
if (g_ActiveConfig.iAspectRatio != ASPECT_STRETCH)
|
||||
{
|
||||
if (Ratio > 1.0f)
|
||||
|
|
|
@ -93,7 +93,9 @@ public:
|
|||
virtual TargetRectangle ConvertEFBRectangle(const EFBRectangle& rc) = 0;
|
||||
|
||||
static const TargetRectangle& GetTargetRectangle() { return target_rc; }
|
||||
static void UpdateDrawRectangle(int backbuffer_width, int backbuffer_height);
|
||||
static float CalculateDrawAspectRatio(int target_width, int target_height);
|
||||
static TargetRectangle CalculateFrameDumpDrawRectangle();
|
||||
static void UpdateDrawRectangle();
|
||||
|
||||
// Use this to convert a single target rectangle to two stereo rectangles
|
||||
static void ConvertStereoRectangle(const TargetRectangle& rc, TargetRectangle& leftRc,
|
||||
|
@ -143,7 +145,7 @@ public:
|
|||
virtual void ChangeSurface(void* new_surface_handle) {}
|
||||
protected:
|
||||
static void CalculateTargetScale(int x, int y, int* scaledX, int* scaledY);
|
||||
bool CalculateTargetSize(unsigned int framebuffer_width, unsigned int framebuffer_height);
|
||||
bool CalculateTargetSize();
|
||||
|
||||
static void CheckFifoRecording();
|
||||
static void RecordVideoMemory();
|
||||
|
|
|
@ -39,6 +39,7 @@ VideoConfig::VideoConfig()
|
|||
backend_info.api_type = APIType::Nothing;
|
||||
backend_info.bSupportsExclusiveFullscreen = false;
|
||||
backend_info.bSupportsMultithreading = false;
|
||||
backend_info.bSupportsInternalResolutionFrameDumps = false;
|
||||
|
||||
bEnableValidationLayer = false;
|
||||
bBackendMultithreading = true;
|
||||
|
@ -74,6 +75,7 @@ void VideoConfig::Load(const std::string& ini_file)
|
|||
settings->Get("DumpFramesAsImages", &bDumpFramesAsImages, 0);
|
||||
settings->Get("FreeLook", &bFreeLook, 0);
|
||||
settings->Get("UseFFV1", &bUseFFV1, 0);
|
||||
settings->Get("InternalResolutionFrameDumps", &bInternalResolutionFrameDumps, 0);
|
||||
settings->Get("EnablePixelLighting", &bEnablePixelLighting, 0);
|
||||
settings->Get("FastDepthCalc", &bFastDepthCalc, true);
|
||||
settings->Get("MSAA", &iMultisamples, 1);
|
||||
|
@ -291,6 +293,7 @@ void VideoConfig::Save(const std::string& ini_file)
|
|||
settings->Set("DumpFramesAsImages", bDumpFramesAsImages);
|
||||
settings->Set("FreeLook", bFreeLook);
|
||||
settings->Set("UseFFV1", bUseFFV1);
|
||||
settings->Set("InternalResolutionFrameDumps", bInternalResolutionFrameDumps);
|
||||
settings->Set("EnablePixelLighting", bEnablePixelLighting);
|
||||
settings->Set("FastDepthCalc", bFastDepthCalc);
|
||||
settings->Set("MSAA", iMultisamples);
|
||||
|
|
|
@ -101,6 +101,7 @@ struct VideoConfig final
|
|||
bool bDumpEFBTarget;
|
||||
bool bDumpFramesAsImages;
|
||||
bool bUseFFV1;
|
||||
bool bInternalResolutionFrameDumps;
|
||||
bool bFreeLook;
|
||||
bool bBorderlessFullscreen;
|
||||
|
||||
|
@ -184,6 +185,7 @@ struct VideoConfig final
|
|||
bool bSupportsDepthClamp; // Needed by VertexShaderGen, so must stay in VideoCommon
|
||||
bool bSupportsReversedDepthRange;
|
||||
bool bSupportsMultithreading;
|
||||
bool bSupportsInternalResolutionFrameDumps;
|
||||
} backend_info;
|
||||
|
||||
// Utility
|
||||
|
|
Loading…
Reference in New Issue