summaryrefslogtreecommitdiff
path: root/Source/Core/VideoCommon/RenderBase.cpp
diff options
context:
space:
mode:
authorPierre Bourdon <delroth@gmail.com>2017-11-19 04:58:59 +0100
committerGitHub <noreply@github.com>2017-11-19 04:58:59 +0100
commit609a17a0cd41a12c0fbf9a7c47c8889232594778 (patch)
tree0a5f6f4b0a7d480accc4dfbcc3e9c1c6e3652dc0 /Source/Core/VideoCommon/RenderBase.cpp
parentd800b0f79868a28356b4e40cb9b2e5af43977042 (diff)
parent1f1574b7ab032afa7b3a600a071699f2cbea124e (diff)
Merge pull request #5498 from iwubcode/hybrid_xfb
Hybrid xfb
Diffstat (limited to 'Source/Core/VideoCommon/RenderBase.cpp')
-rw-r--r--Source/Core/VideoCommon/RenderBase.cpp189
1 files changed, 107 insertions, 82 deletions
diff --git a/Source/Core/VideoCommon/RenderBase.cpp b/Source/Core/VideoCommon/RenderBase.cpp
index 63e3f5f5ed..0db81bb885 100644
--- a/Source/Core/VideoCommon/RenderBase.cpp
+++ b/Source/Core/VideoCommon/RenderBase.cpp
@@ -37,13 +37,13 @@
#include "Core/Config/SYSCONFSettings.h"
#include "Core/ConfigManager.h"
#include "Core/Core.h"
-#include "Core/CoreTiming.h"
#include "Core/FifoPlayer/FifoRecorder.h"
#include "Core/HW/VideoInterface.h"
#include "Core/Host.h"
#include "Core/Movie.h"
#include "VideoCommon/AVIDump.h"
+#include "VideoCommon/AbstractTexture.h"
#include "VideoCommon/BPMemory.h"
#include "VideoCommon/CPMemory.h"
#include "VideoCommon/CommandProcessor.h"
@@ -84,9 +84,6 @@ static float AspectToWidescreen(float aspect)
Renderer::Renderer(int backbuffer_width, int backbuffer_height)
: m_backbuffer_width(backbuffer_width), m_backbuffer_height(backbuffer_height)
{
- FramebufferManagerBase::SetLastXfbWidth(MAX_XFB_WIDTH);
- FramebufferManagerBase::SetLastXfbHeight(MAX_XFB_HEIGHT);
-
UpdateActiveConfig();
UpdateDrawRectangle();
CalculateTargetSize();
@@ -100,11 +97,15 @@ Renderer::Renderer(int backbuffer_width, int backbuffer_height)
m_last_host_config_bits = ShaderHostConfig::GetCurrent().bits;
}
-Renderer::~Renderer()
+Renderer::~Renderer() = default;
+
+void Renderer::ExitFramedumping()
{
ShutdownFrameDumping();
if (m_frame_dump_thread.joinable())
m_frame_dump_thread.join();
+
+ m_dump_texture.reset();
}
void Renderer::RenderToXFB(u32 xfbAddr, const EFBRectangle& sourceRc, u32 fbStride, u32 fbHeight,
@@ -114,21 +115,6 @@ void Renderer::RenderToXFB(u32 xfbAddr, const EFBRectangle& sourceRc, u32 fbStri
if (!fbStride || !fbHeight)
return;
-
- m_xfb_written = true;
-
- if (g_ActiveConfig.bUseXFB)
- {
- FramebufferManagerBase::CopyToXFB(xfbAddr, fbStride, fbHeight, sourceRc, Gamma);
- }
- else
- {
- // The timing is not predictable here. So try to use the XFB path to dump frames.
- u64 ticks = CoreTiming::GetTicks();
-
- // below div two to convert from bytes to pixels - it expects width, not stride
- Swap(xfbAddr, fbStride / 2, fbStride / 2, fbHeight, sourceRc, ticks, Gamma);
- }
}
unsigned int Renderer::GetEFBScale() const
@@ -167,8 +153,8 @@ bool Renderer::CalculateTargetSize()
if (g_ActiveConfig.iEFBScale == EFB_SCALE_AUTO_INTEGRAL)
{
// Set a scale based on the window size
- int width = FramebufferManagerBase::ScaleToVirtualXfbWidth(EFB_WIDTH, m_target_rectangle);
- int height = FramebufferManagerBase::ScaleToVirtualXfbHeight(EFB_HEIGHT, m_target_rectangle);
+ int width = EFB_WIDTH * m_target_rectangle.GetWidth() / m_last_xfb_width;
+ int height = EFB_HEIGHT * m_target_rectangle.GetWidth() / m_last_xfb_height;
m_efb_scale = std::max((width - 1) / EFB_WIDTH + 1, (height - 1) / EFB_HEIGHT + 1);
}
else
@@ -342,6 +328,7 @@ void Renderer::DrawDebugText()
}
const char* const efbcopy_text = g_ActiveConfig.bSkipEFBCopyToRam ? "to Texture" : "to RAM";
+ const char* const xfbcopy_text = g_ActiveConfig.bSkipXFBCopyToRam ? "to Texture" : "to RAM";
// The rows
const std::string lines[] = {
@@ -353,6 +340,8 @@ void Renderer::DrawDebugText()
"Speed Limit: Unlimited" :
StringFromFormat("Speed Limit: %li%%",
std::lround(SConfig::GetInstance().m_EmulationSpeed * 100.f)),
+ std::string("Copy XFB: ") + xfbcopy_text +
+ (g_ActiveConfig.bImmediateXFB ? " (Immediate)" : ""),
};
enum
@@ -425,36 +414,6 @@ std::tuple<float, float> 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.
- // 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 = 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<int>(std::ceil(draw_width));
- rc.bottom = static_cast<int>(std::ceil(draw_height));
- return rc;
-}
-
void Renderer::UpdateDrawRectangle()
{
// The rendering window size
@@ -564,13 +523,26 @@ void Renderer::UpdateDrawRectangle()
void Renderer::SetWindowSize(int width, int height)
{
- width = std::max(width, 1);
- height = std::max(height, 1);
-
// Scale the window size by the EFB scale.
if (g_ActiveConfig.iEFBScale != EFB_SCALE_AUTO_INTEGRAL)
std::tie(width, height) = CalculateTargetScale(width, height);
+ std::tie(width, height) = CalculateOutputDimensions(width, height);
+
+ // Track the last values of width/height to avoid sending a window resize event every frame.
+ if (width != m_last_window_request_width || height != m_last_window_request_height)
+ {
+ m_last_window_request_width = width;
+ m_last_window_request_height = height;
+ Host_RequestRenderWindowSize(width, height);
+ }
+}
+
+std::tuple<int, int> Renderer::CalculateOutputDimensions(int width, int height)
+{
+ width = std::max(width, 1);
+ height = std::max(height, 1);
+
float scaled_width, scaled_height;
std::tie(scaled_width, scaled_height) = ScaleToDisplayAspectRatio(width, height);
@@ -602,13 +574,7 @@ void Renderer::SetWindowSize(int width, int height)
width -= width % 4;
height -= height % 4;
- // Track the last values of width/height to avoid sending a window resize event every frame.
- if (width != m_last_window_request_width || height != m_last_window_request_height)
- {
- m_last_window_request_width = width;
- m_last_window_request_height = height;
- Host_RequestRenderWindowSize(width, height);
- }
+ return std::make_tuple(width, height);
}
void Renderer::CheckFifoRecording()
@@ -645,7 +611,7 @@ void Renderer::RecordVideoMemory()
}
void Renderer::Swap(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, const EFBRectangle& rc,
- u64 ticks, float Gamma)
+ u64 ticks)
{
// Heuristic to detect if a GameCube game is in 16:9 anamorphic widescreen mode.
if (!SConfig::GetInstance().bWii)
@@ -663,11 +629,49 @@ void Renderer::Swap(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, const
m_aspect_wide = flush_count_anamorphic > 0.75 * flush_total;
}
- // TODO: merge more generic parts into VideoCommon
- SwapImpl(xfbAddr, fbWidth, fbStride, fbHeight, rc, ticks, Gamma);
+ if (IsFrameDumping() && m_last_xfb_texture)
+ {
+ FinishFrameData();
+ }
+ else
+ {
+ ShutdownFrameDumping();
+ }
+
+ bool update_frame_count = false;
+ if (xfbAddr && fbWidth && fbStride && fbHeight)
+ {
+ constexpr int force_safe_texture_cache_hash = 0;
+ // Get the current XFB from texture cache
+ auto* xfb_entry = g_texture_cache->GetXFBTexture(
+ xfbAddr, fbStride, fbHeight, TextureFormat::XFB, force_safe_texture_cache_hash);
+
+ if (xfb_entry && xfb_entry->id != m_last_xfb_id)
+ {
+ m_last_xfb_texture = xfb_entry->texture.get();
+ m_last_xfb_id = xfb_entry->id;
+ m_last_xfb_ticks = ticks;
+
+ auto xfb_rect = xfb_entry->texture->GetConfig().GetRect();
+ xfb_rect.right -= EFBToScaledX(fbStride - fbWidth);
- if (m_xfb_written)
- m_fps_counter.Update();
+ m_last_xfb_region = xfb_rect;
+
+ // TODO: merge more generic parts into VideoCommon
+ g_renderer->SwapImpl(xfb_entry->texture.get(), xfb_rect, ticks, xfb_entry->gamma);
+
+ m_fps_counter.Update();
+ update_frame_count = true;
+ if (IsFrameDumping())
+ {
+ DoDumpFrame();
+ }
+ }
+
+ // Update our last xfb values
+ m_last_xfb_width = (fbStride < 1 || fbStride > MAX_XFB_WIDTH) ? MAX_XFB_WIDTH : fbStride;
+ m_last_xfb_height = (fbHeight < 1 || fbHeight > MAX_XFB_HEIGHT) ? MAX_XFB_HEIGHT : fbHeight;
+ }
frameCount++;
GFX_DEBUGGER_PAUSE_AT(NEXT_FRAME, true);
@@ -677,9 +681,7 @@ void Renderer::Swap(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, const
// New frame
stats.ResetFrame();
- Core::Callback_VideoCopiedToXFB(m_xfb_written ||
- (g_ActiveConfig.bUseXFB && g_ActiveConfig.bUseRealXFB));
- m_xfb_written = false;
+ Core::Callback_VideoCopiedToXFB(update_frame_count);
}
bool Renderer::IsFrameDumping()
@@ -690,10 +692,41 @@ bool Renderer::IsFrameDumping()
if (SConfig::GetInstance().m_DumpFrames)
return true;
- ShutdownFrameDumping();
return false;
}
+void Renderer::DoDumpFrame()
+{
+ UpdateFrameDumpTexture();
+
+ auto result = m_dump_texture->Map();
+ if (result.has_value())
+ {
+ auto raw_data = result.value();
+ DumpFrameData(raw_data.data, raw_data.width, raw_data.height, raw_data.stride,
+ AVIDump::FetchState(m_last_xfb_ticks));
+ }
+}
+
+void Renderer::UpdateFrameDumpTexture()
+{
+ int target_width, target_height;
+ std::tie(target_width, target_height) = CalculateOutputDimensions(
+ m_last_xfb_texture->GetConfig().width, m_last_xfb_texture->GetConfig().height);
+ if (m_dump_texture == nullptr ||
+ m_dump_texture->GetConfig().width != static_cast<u32>(target_width) ||
+ m_dump_texture->GetConfig().height != static_cast<u32>(target_height))
+ {
+ TextureConfig config;
+ config.width = target_width;
+ config.height = target_height;
+ config.rendertarget = true;
+ m_dump_texture = g_texture_cache->CreateTexture(config);
+ }
+ m_dump_texture->CopyRectangleFromTexture(m_last_xfb_texture, m_last_xfb_region,
+ EFBRectangle{0, 0, target_width, target_height});
+}
+
void Renderer::ShutdownFrameDumping()
{
if (!m_frame_dump_thread_running.IsSet())
@@ -704,12 +737,9 @@ void Renderer::ShutdownFrameDumping()
m_frame_dump_start.Set();
}
-void Renderer::DumpFrameData(const u8* data, int w, int h, int stride, const AVIDump::Frame& state,
- bool swap_upside_down)
+void Renderer::DumpFrameData(const u8* data, int w, int h, int stride, const AVIDump::Frame& state)
{
- FinishFrameData();
-
- m_frame_dump_config = FrameDumpConfig{data, w, h, stride, swap_upside_down, state};
+ m_frame_dump_config = FrameDumpConfig{m_last_xfb_texture, data, w, h, stride, state};
if (!m_frame_dump_thread_running.IsSet())
{
@@ -730,6 +760,7 @@ void Renderer::FinishFrameData()
m_frame_dump_done.Wait();
m_frame_dump_frame_running = false;
+ m_frame_dump_config.texture->Unmap();
}
void Renderer::RunFrameDumps()
@@ -756,12 +787,6 @@ void Renderer::RunFrameDumps()
auto config = m_frame_dump_config;
- if (config.upside_down)
- {
- config.data = config.data + (config.height - 1) * config.stride;
- config.stride = -config.stride;
- }
-
// Save screenshot
if (m_screenshot_request.TestAndClear())
{