Move xfb tracking and IR scaling out of RenderBase

This commit is contained in:
Scott Mansell 2023-01-31 17:26:46 +13:00
parent e009002411
commit 11de923dcb
20 changed files with 238 additions and 248 deletions

View File

@ -96,7 +96,7 @@ static size_t s_state_writes_in_queue;
static std::condition_variable s_state_write_queue_is_empty;
// Don't forget to increase this after doing changes on the savestate system
constexpr u32 STATE_VERSION = 157; // Last changed in PR 11183
constexpr u32 STATE_VERSION = 158; // Last changed in PR ???
// Maps savestate versions to Dolphin versions.
// Versions after 42 don't need to be added to this list,

View File

@ -114,8 +114,8 @@ void PerfQuery::FlushOne()
// NOTE: Reported pixel metrics should be referenced to native resolution
// TODO: Dropping the lower 2 bits from this count should be closer to actual
// hardware behavior when drawing triangles.
const u64 native_res_result = result * EFB_WIDTH / g_renderer->GetTargetWidth() * EFB_HEIGHT /
g_renderer->GetTargetHeight();
const u64 native_res_result = result * EFB_WIDTH / g_framebuffer_manager->GetEFBWidth() * EFB_HEIGHT /
g_framebuffer_manager->GetEFBHeight();
m_results[entry.query_group].fetch_add(static_cast<u32>(native_res_result),
std::memory_order_relaxed);
@ -143,8 +143,8 @@ void PerfQuery::WeakFlush()
if (hr == S_OK)
{
// NOTE: Reported pixel metrics should be referenced to native resolution
const u64 native_res_result = result * EFB_WIDTH / g_renderer->GetTargetWidth() * EFB_HEIGHT /
g_renderer->GetTargetHeight();
const u64 native_res_result = result * EFB_WIDTH / g_framebuffer_manager->GetEFBWidth() * EFB_HEIGHT /
g_framebuffer_manager->GetEFBHeight();
m_results[entry.query_group].store(static_cast<u32>(native_res_result),
std::memory_order_relaxed);

View File

@ -245,8 +245,8 @@ void PerfQuery::AccumulateQueriesFromBuffer(u32 query_count)
// NOTE: Reported pixel metrics should be referenced to native resolution
const u64 native_res_result = static_cast<u64>(result) * EFB_WIDTH /
g_renderer->GetTargetWidth() * EFB_HEIGHT /
g_renderer->GetTargetHeight();
g_framebuffer_manager->GetEFBWidth() * EFB_HEIGHT /
g_framebuffer_manager->GetEFBHeight();
m_results[entry.query_group].fetch_add(static_cast<u32>(native_res_result),
std::memory_order_relaxed);
}

View File

@ -78,7 +78,7 @@ void Metal::PerfQuery::ReturnResults(const u64* data, const PerfQueryGroup* grou
for (size_t i = 0; i < count; ++i)
{
u64 native_res_result = data[i] * (EFB_WIDTH * EFB_HEIGHT) /
(g_renderer->GetTargetWidth() * g_renderer->GetTargetHeight());
(g_framebuffer_manager->GetEFBWidth() * g_framebuffer_manager->GetEFBHeight());
native_res_result /= g_ActiveConfig.iMultisamples;

View File

@ -9,7 +9,7 @@
#include "Common/GL/GLExtensions/GLExtensions.h"
#include "VideoBackends/OGL/OGLGfx.h"
#include "VideoCommon/RenderBase.h"
#include "VideoCommon/FramebufferManager.h"
#include "VideoCommon/VideoCommon.h"
#include "VideoCommon/VideoConfig.h"
@ -165,7 +165,7 @@ void PerfQueryGL::FlushOne()
// TODO: Dropping the lower 2 bits from this count should be closer to actual
// hardware behavior when drawing triangles.
result = static_cast<u64>(result) * EFB_WIDTH * EFB_HEIGHT /
(g_renderer->GetTargetWidth() * g_renderer->GetTargetHeight());
(g_framebuffer_manager->GetEFBWidth() * g_framebuffer_manager->GetEFBHeight());
// Adjust for multisampling
if (g_ActiveConfig.iMultisamples > 1)
@ -265,7 +265,7 @@ void PerfQueryGLESNV::FlushOne()
// TODO: Dropping the lower 2 bits from this count should be closer to actual
// hardware behavior when drawing triangles.
const u64 native_res_result = static_cast<u64>(result) * EFB_WIDTH * EFB_HEIGHT /
(g_renderer->GetTargetWidth() * g_renderer->GetTargetHeight());
(g_framebuffer_manager->GetEFBWidth() * g_framebuffer_manager->GetEFBHeight());
m_results[entry.query_group].fetch_add(static_cast<u32>(native_res_result),
std::memory_order_relaxed);

View File

@ -15,7 +15,7 @@
#include "VideoBackends/Vulkan/StateTracker.h"
#include "VideoBackends/Vulkan/VKGfx.h"
#include "VideoBackends/Vulkan/VulkanContext.h"
#include "VideoCommon/RenderBase.h"
#include "VideoCommon/FramebufferManager.h"
#include "VideoCommon/VideoCommon.h"
namespace Vulkan
@ -219,8 +219,8 @@ void PerfQuery::ReadbackQueries(u32 query_count)
// NOTE: Reported pixel metrics should be referenced to native resolution
const u64 native_res_result = static_cast<u64>(m_query_result_buffer[i]) * EFB_WIDTH /
g_renderer->GetTargetWidth() * EFB_HEIGHT /
g_renderer->GetTargetHeight();
g_framebuffer_manager->GetEFBWidth() * EFB_HEIGHT /
g_framebuffer_manager->GetEFBHeight();
m_results[entry.query_group].fetch_add(static_cast<u32>(native_res_result),
std::memory_order_relaxed);
}

View File

@ -158,8 +158,6 @@ void AsyncRequests::HandleEvent(const AsyncRequests::Event& e)
case Event::SWAP_EVENT:
g_presenter->ViSwap(e.swap_event.xfbAddr, e.swap_event.fbWidth, e.swap_event.fbStride,
e.swap_event.fbHeight, e.time);
g_renderer->TrackSwaps(e.swap_event.xfbAddr, e.swap_event.fbWidth, e.swap_event.fbStride,
e.swap_event.fbHeight, e.time);
break;
case Event::BBOX_READ:

View File

@ -198,7 +198,7 @@ void SetScissorAndViewport()
{
auto native_rc = ComputeScissorRects().Best();
auto target_rc = g_renderer->ConvertEFBRectangle(native_rc.rect);
auto target_rc = g_framebuffer_manager->ConvertEFBRectangle(native_rc.rect);
auto converted_rc = g_gfx->ConvertFramebufferRectangle(target_rc, g_gfx->GetCurrentFramebuffer());
g_gfx->SetScissorRect(converted_rc);
@ -216,10 +216,10 @@ void SetScissorAndViewport()
raw_height = std::round(raw_height);
}
float x = g_renderer->EFBToScaledXf(raw_x);
float y = g_renderer->EFBToScaledYf(raw_y);
float width = g_renderer->EFBToScaledXf(raw_width);
float height = g_renderer->EFBToScaledYf(raw_height);
float x = g_framebuffer_manager->EFBToScaledXf(raw_x);
float y = g_framebuffer_manager->EFBToScaledYf(raw_y);
float width = g_framebuffer_manager->EFBToScaledXf(raw_width);
float height = g_framebuffer_manager->EFBToScaledYf(raw_height);
float min_depth = (xfmem.viewport.farZ - xfmem.viewport.zRange) / 16777216.0f;
float max_depth = xfmem.viewport.farZ / 16777216.0f;
if (width < 0.f)

View File

@ -352,7 +352,6 @@ static void BPWritten(PixelShaderManager& pixel_shader_manager,
// below div two to convert from bytes to pixels - it expects width, not stride
u64 ticks = Core::System::GetInstance().GetCoreTiming().GetTicks();
g_presenter->ImmediateSwap(destAddr, destStride / 2, destStride, height, ticks);
g_renderer->TrackSwaps(destAddr, destStride / 2, destStride, height, ticks);
}
else
{

View File

@ -10,6 +10,7 @@
#include "Common/Logging/Log.h"
#include "Common/MsgHandler.h"
#include "Core/Config/GraphicsSettings.h"
#include "Core/System.h"
#include "VideoCommon/AbstractFramebuffer.h"
#include "VideoCommon/AbstractGfx.h"
#include "VideoCommon/AbstractPipeline.h"
@ -19,7 +20,8 @@
#include "VideoCommon/BPFunctions.h"
#include "VideoCommon/DriverDetails.h"
#include "VideoCommon/FramebufferShaderGen.h"
#include "VideoCommon/RenderBase.h"
#include "VideoCommon/PixelShaderManager.h"
#include "VideoCommon/Present.h"
#include "VideoCommon/VertexManagerBase.h"
#include "VideoCommon/VideoCommon.h"
#include "VideoCommon/VideoConfig.h"
@ -145,16 +147,16 @@ static u32 CalculateEFBLayers()
return (g_ActiveConfig.stereo_mode != StereoMode::Off) ? 2 : 1;
}
TextureConfig FramebufferManager::GetEFBColorTextureConfig()
TextureConfig FramebufferManager::GetEFBColorTextureConfig(u32 width, u32 height)
{
return TextureConfig(g_renderer->GetTargetWidth(), g_renderer->GetTargetHeight(), 1,
return TextureConfig(width, height, 1,
CalculateEFBLayers(), g_ActiveConfig.iMultisamples, GetEFBColorFormat(),
AbstractTextureFlag_RenderTarget);
}
TextureConfig FramebufferManager::GetEFBDepthTextureConfig()
TextureConfig FramebufferManager::GetEFBDepthTextureConfig(u32 width, u32 height)
{
return TextureConfig(g_renderer->GetTargetWidth(), g_renderer->GetTargetHeight(), 1,
return TextureConfig(width, height, 1,
CalculateEFBLayers(), g_ActiveConfig.iMultisamples, GetEFBDepthFormat(),
AbstractTextureFlag_RenderTarget);
}
@ -169,10 +171,65 @@ FramebufferState FramebufferManager::GetEFBFramebufferState() const
return ret;
}
MathUtil::Rectangle<int>
FramebufferManager::ConvertEFBRectangle(const MathUtil::Rectangle<int>& rc) const
{
MathUtil::Rectangle<int> result;
result.left = EFBToScaledX(rc.left);
result.top = EFBToScaledY(rc.top);
result.right = EFBToScaledX(rc.right);
result.bottom = EFBToScaledY(rc.bottom);
return result;
}
unsigned int FramebufferManager::GetEFBScale() const
{
return m_efb_scale;
}
int FramebufferManager::EFBToScaledX(int x) const
{
return x * static_cast<int>(m_efb_scale);
}
int FramebufferManager::EFBToScaledY(int y) const
{
return y * static_cast<int>(m_efb_scale);
}
float FramebufferManager::EFBToScaledXf(float x) const
{
return x * ((float)GetEFBWidth() / (float)EFB_WIDTH);
}
float FramebufferManager::EFBToScaledYf(float y) const
{
return y * ((float)GetEFBHeight() / (float)EFB_HEIGHT);
}
std::tuple<u32, u32> FramebufferManager::CalculateTargetSize()
{
if (g_ActiveConfig.iEFBScale == EFB_SCALE_AUTO_INTEGRAL)
m_efb_scale = g_presenter->AutoIntegralScale();
else
m_efb_scale = g_ActiveConfig.iEFBScale;
const u32 max_size = g_ActiveConfig.backend_info.MaxTextureSize;
if (max_size < EFB_WIDTH * m_efb_scale)
m_efb_scale = max_size / EFB_WIDTH;
u32 new_efb_width = std::max(EFB_WIDTH * static_cast<int>(m_efb_scale), 1u);
u32 new_efb_height = std::max(EFB_HEIGHT * static_cast<int>(m_efb_scale), 1u);
return std::make_tuple(new_efb_width, new_efb_height);
}
bool FramebufferManager::CreateEFBFramebuffer()
{
const TextureConfig efb_color_texture_config = GetEFBColorTextureConfig();
const TextureConfig efb_depth_texture_config = GetEFBDepthTextureConfig();
auto [width, height] = CalculateTargetSize();
const TextureConfig efb_color_texture_config = GetEFBColorTextureConfig(width, height);
const TextureConfig efb_depth_texture_config = GetEFBDepthTextureConfig(width, height);
// We need a second texture to swap with for changing pixel formats
m_efb_color_texture = g_gfx->CreateTexture(efb_color_texture_config, "EFB color texture");
@ -634,7 +691,7 @@ void FramebufferManager::DestroyReadbackPipelines()
bool FramebufferManager::CreateReadbackFramebuffer()
{
if (g_renderer->GetEFBScale() != 1)
if (GetEFBScale() != 1)
{
const TextureConfig color_config(IsUsingTiledEFBCache() ? m_efb_cache_tile_size : EFB_WIDTH,
IsUsingTiledEFBCache() ? m_efb_cache_tile_size : EFB_HEIGHT, 1,
@ -655,7 +712,7 @@ bool FramebufferManager::CreateReadbackFramebuffer()
(IsUsingTiledEFBCache() && !g_ActiveConfig.backend_info.bSupportsPartialDepthCopies) ||
!AbstractTexture::IsCompatibleDepthAndColorFormats(m_efb_depth_texture->GetFormat(),
GetEFBDepthCopyFormat()) ||
g_renderer->GetEFBScale() != 1)
GetEFBScale() != 1)
{
const TextureConfig depth_config(IsUsingTiledEFBCache() ? m_efb_cache_tile_size : EFB_WIDTH,
IsUsingTiledEFBCache() ? m_efb_cache_tile_size : EFB_HEIGHT, 1,
@ -732,10 +789,10 @@ void FramebufferManager::PopulateEFBCache(bool depth, u32 tile_index, bool async
// Issue a copy from framebuffer -> copy texture if we have >1xIR or MSAA on.
EFBCacheData& data = depth ? m_efb_depth_cache : m_efb_color_cache;
const MathUtil::Rectangle<int> rect = GetEFBCacheTileRect(tile_index);
const MathUtil::Rectangle<int> native_rect = g_renderer->ConvertEFBRectangle(rect);
const MathUtil::Rectangle<int> native_rect = ConvertEFBRectangle(rect);
AbstractTexture* src_texture =
depth ? ResolveEFBDepthTexture(native_rect) : ResolveEFBColorTexture(native_rect);
if (g_renderer->GetEFBScale() != 1 || force_intermediate_copy)
if (GetEFBScale() != 1 || force_intermediate_copy)
{
// Downsample from internal resolution to 1x.
// TODO: This won't produce correct results at IRs above 2x. More samples are required.
@ -795,9 +852,9 @@ void FramebufferManager::ClearEFB(const MathUtil::Rectangle<int>& rc, bool color
FlagPeekCacheAsOutOfDate();
// Native -> EFB coordinates
MathUtil::Rectangle<int> target_rc = g_renderer->ConvertEFBRectangle(rc);
MathUtil::Rectangle<int> target_rc = ConvertEFBRectangle(rc);
target_rc = g_gfx->ConvertFramebufferRectangle(target_rc, m_efb_framebuffer.get());
target_rc.ClampUL(0, 0, g_renderer->GetTargetWidth(), g_renderer->GetTargetHeight());
target_rc.ClampUL(0, 0, m_efb_framebuffer->GetWidth(), m_efb_framebuffer->GetWidth());
// Determine whether the EFB has an alpha channel. If it doesn't, we can clear the alpha
// channel to 0xFF.
@ -925,7 +982,7 @@ void FramebufferManager::CreatePokeVertices(std::vector<EFBPokeVertex>* destinat
// GPU will expand the point to a quad.
const float cs_x = (static_cast<float>(x) + 0.5f) * cs_pixel_width - 1.0f;
const float cs_y = 1.0f - (static_cast<float>(y) + 0.5f) * cs_pixel_height;
const float point_size = static_cast<float>(g_renderer->GetEFBScale());
const float point_size = static_cast<float>(GetEFBScale());
destination_list->push_back({{cs_x, cs_y, z, point_size}, color});
return;
}

View File

@ -6,6 +6,7 @@
#include <array>
#include <memory>
#include <optional>
#include <tuple>
#include "Common/CommonTypes.h"
#include "Common/EnumFormatter.h"
@ -54,8 +55,8 @@ public:
static AbstractTextureFormat GetEFBColorFormat();
static AbstractTextureFormat GetEFBDepthFormat();
static AbstractTextureFormat GetEFBDepthCopyFormat();
static TextureConfig GetEFBColorTextureConfig();
static TextureConfig GetEFBDepthTextureConfig();
static TextureConfig GetEFBColorTextureConfig(u32 width, u32 height);
static TextureConfig GetEFBDepthTextureConfig(u32 width, u32 height);
// Accessors.
AbstractTexture* GetEFBColorTexture() const { return m_efb_color_texture.get(); }
@ -69,6 +70,20 @@ public:
bool IsEFBStereo() const { return m_efb_color_texture->GetLayers() > 1; }
FramebufferState GetEFBFramebufferState() const;
// EFB coordinate conversion functions
// Use this to convert a whole native EFB rect to backbuffer coordinates
MathUtil::Rectangle<int> ConvertEFBRectangle(const MathUtil::Rectangle<int>& rc) const;
unsigned int GetEFBScale() const;
// Use this to upscale native EFB coordinates to IDEAL internal resolution
int EFBToScaledX(int x) const;
int EFBToScaledY(int y) const;
// Floating point versions of the above - only use them if really necessary
float EFBToScaledXf(float x) const;
float EFBToScaledYf(float y) const;
// First-time setup.
bool Initialize();
@ -172,9 +187,13 @@ protected:
void DrawPokeVertices(const EFBPokeVertex* vertices, u32 vertex_count,
const AbstractPipeline* pipeline);
std::tuple<u32, u32> CalculateTargetSize();
void DoLoadState(PointerWrap& p);
void DoSaveState(PointerWrap& p);
float m_efb_scale = 0.0f;
std::unique_ptr<AbstractTexture> m_efb_color_texture;
std::unique_ptr<AbstractTexture> m_efb_convert_color_texture;
std::unique_ptr<AbstractTexture> m_efb_depth_texture;

View File

@ -7,7 +7,7 @@
#include "Common/ChunkFile.h"
#include "Common/CommonTypes.h"
#include "VideoCommon/RenderBase.h"
#include "VideoCommon/FramebufferManager.h"
#include "VideoCommon/VideoCommon.h"
#include "VideoCommon/VideoConfig.h"
#include "VideoCommon/XFMemory.h"
@ -74,7 +74,7 @@ void PixelShaderManager::Dirty()
// Any constants that can changed based on settings should be re-calculated
m_fog_range_adjusted_changed = true;
SetEfbScaleChanged(g_renderer->EFBToScaledXf(1), g_renderer->EFBToScaledYf(1));
SetEfbScaleChanged(g_framebuffer_manager->EFBToScaledXf(1), g_framebuffer_manager->EFBToScaledYf(1));
SetFogParamChanged();
dirty = true;
@ -103,7 +103,7 @@ void PixelShaderManager::SetConstants()
// TODO: Shouldn't this be EFBToScaledXf?
constants.fogf[2] = ScreenSpaceCenter;
constants.fogf[3] =
static_cast<float>(g_renderer->EFBToScaledX(static_cast<int>(2.0f * xfmem.viewport.wd)));
static_cast<float>(g_framebuffer_manager->EFBToScaledX(static_cast<int>(2.0f * xfmem.viewport.wd)));
for (size_t i = 0, vec_index = 0; i < std::size(bpmem.fogRange.K); i++)
{

View File

@ -3,6 +3,7 @@
#include "VideoCommon/Present.h"
#include "Common/ChunkFile.h"
#include "Core/HW/VideoInterface.h"
#include "Core/Host.h"
@ -17,6 +18,7 @@
#include "VideoCommon/VertexManagerBase.h"
#include "VideoCommon/VideoConfig.h"
#include "VideoCommon/VideoEvents.h"
#include "Present.h"
std::unique_ptr<VideoCommon::Presenter> g_presenter;
@ -61,35 +63,39 @@ bool Presenter::Initialize()
return true;
}
bool Presenter::FetchXFB(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height)
bool Presenter::FetchXFB(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height, u64 ticks)
{
ReleaseXFBContentLock();
m_xfb_entry = g_texture_cache->GetXFBTexture(xfb_addr, fb_width, fb_height, fb_stride, &m_xfb_rect);
bool is_duplicate = m_xfb_entry->id == m_last_xfb_id;
m_xfb_entry->AcquireContentLock();
if (m_last_xfb_id == m_xfb_entry->id)
return false;
m_last_xfb_addr = xfb_addr;
m_last_xfb_ticks = ticks;
m_last_xfb_width = fb_width;
m_last_xfb_stride = fb_stride;
m_last_xfb_height = fb_height;
m_last_xfb_id = m_xfb_entry->id;
return true;
return is_duplicate;
}
void Presenter::ViSwap(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height, u64 ticks)
{
bool unique = FetchXFB(xfb_addr, fb_width, fb_stride, fb_height);
bool unique = FetchXFB(xfb_addr, fb_width, fb_stride, fb_height, ticks);
PresentInfo present_info;
present_info.emulated_timestamp = ticks;
if (unique)
{
present_info.frame_count = g_renderer->FrameCountIncrement();
present_info.frame_count = m_frame_count++;
present_info.reason = PresentInfo::PresentReason::VideoInterface;
}
else
{
present_info.frame_count = g_renderer->FrameCount() - 1; // Previous frame
present_info.frame_count = m_frame_count - 1; // Previous frame
present_info.reason = PresentInfo::PresentReason::VideoInterfaceDuplicate;
}
present_info.present_count = m_present_count;
@ -111,11 +117,11 @@ void Presenter::ViSwap(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height,
void Presenter::ImmediateSwap(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height, u64 ticks)
{
FetchXFB(xfb_addr, fb_width, fb_stride, fb_height);
FetchXFB(xfb_addr, fb_width, fb_stride, fb_height, ticks);
PresentInfo present_info;
present_info.emulated_timestamp = ticks;
present_info.frame_count = g_renderer->FrameCountIncrement();
present_info.frame_count = m_frame_count++;
present_info.reason = PresentInfo::PresentReason::Immediate;
present_info.present_count = m_present_count++;
@ -145,7 +151,7 @@ void Presenter::ProcessFrameDumping(u64 ticks) const
}
g_frame_dumper->DumpCurrentFrame(m_xfb_entry->texture.get(), m_xfb_rect, target_rect, ticks,
g_renderer->FrameCount());
m_frame_count);
}
}
@ -307,6 +313,13 @@ void* Presenter::GetNewSurfaceHandle()
return handle;
}
u32 Presenter::AutoIntegralScale() const
{
// Calculate a scale based on the window size
u32 width = EFB_WIDTH * m_target_rectangle.GetWidth() / m_last_xfb_width;
u32 height = EFB_HEIGHT * m_target_rectangle.GetHeight() / m_last_xfb_height;
return std::max((width - 1) / EFB_WIDTH + 1, (height - 1) / EFB_HEIGHT + 1);
}
void Presenter::SetWindowSize(int width, int height)
{
const auto [out_width, out_height] = g_presenter->CalculateOutputDimensions(width, height);
@ -577,4 +590,26 @@ void Presenter::SetMousePress(u32 button_mask)
m_onscreen_ui->SetMousePress(button_mask);
}
void Presenter::DoState(PointerWrap& p)
{
p.Do(m_frame_count);
p.Do(m_last_xfb_ticks);
p.Do(m_last_xfb_addr);
p.Do(m_last_xfb_width);
p.Do(m_last_xfb_stride);
p.Do(m_last_xfb_height);
if (p.IsReadMode())
{
// This technically counts as the end of the frame
AfterFrameEvent::Trigger();
// re-display the most recent XFB
ImmediateSwap(m_last_xfb_addr, m_last_xfb_width, m_last_xfb_stride,
m_last_xfb_height, m_last_xfb_ticks);
}
}
} // namespace VideoCommon

View File

@ -8,6 +8,7 @@
#include "VideoCommon/TextureCacheBase.h"
#include "VideoCommon/TextureConfig.h"
#include "VideoCommon/VideoCommon.h"
#include <array>
#include <memory>
@ -47,6 +48,7 @@ public:
int GetBackbufferWidth() const { return m_backbuffer_width; }
int GetBackbufferHeight() const { return m_backbuffer_height; }
float GetBackbufferScale() const { return m_backbuffer_scale; }
u32 AutoIntegralScale() const;
AbstractTextureFormat GetBackbufferFormat() const { return m_backbuffer_format; }
void SetWindowSize(int width, int height);
void SetBackbuffer(int backbuffer_width, int backbuffer_height);
@ -86,12 +88,16 @@ public:
void SetMousePos(float x, float y);
void SetMousePress(u32 button_mask);
int FrameCount() const { return m_frame_count; }
void DoState(PointerWrap& p);
const MathUtil::Rectangle<int>& GetTargetRectangle() const { return m_target_rectangle; }
private:
// Fetches the XFB texture from the texture cache.
// Returns true the contents have changed since last time
bool FetchXFB(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height);
bool FetchXFB(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height, u64 ticks);
void ProcessFrameDumping(u64 ticks) const;
@ -130,7 +136,15 @@ private:
std::unique_ptr<VideoCommon::PostProcessing> m_post_processor;
std::unique_ptr<VideoCommon::OnScreenUI> m_onscreen_ui;
u64 m_frame_count = 0;
u64 m_present_count = 0;
// XFB tracking
u64 m_last_xfb_ticks = 0;
u32 m_last_xfb_addr = 0;
u32 m_last_xfb_width = MAX_XFB_WIDTH;
u32 m_last_xfb_stride = 0;
u32 m_last_xfb_height = MAX_XFB_HEIGHT;
};
} // namespace VideoCommon

View File

@ -37,7 +37,6 @@
#include "VideoCommon/FrameDumper.h"
#include "VideoCommon/FramebufferManager.h"
#include "VideoCommon/PixelEngine.h"
#include "VideoCommon/PixelShaderManager.h"
#include "VideoCommon/Present.h"
#include "VideoCommon/VertexManagerBase.h"
#include "VideoCommon/VideoBackendBase.h"
@ -48,10 +47,8 @@
std::unique_ptr<Renderer> g_renderer;
Renderer::Renderer()
: m_prev_efb_format{PixelFormat::INVALID_FMT},
m_last_xfb_width{MAX_XFB_WIDTH}, m_last_xfb_height{MAX_XFB_HEIGHT}
: m_prev_efb_format{PixelFormat::INVALID_FMT}
{
CalculateTargetSize();
UpdateWidescreen();
m_config_changed_handle = ConfigChangedEvent::Register([this](u32 bits) { OnConfigChanged(bits); }, "Renderer");
@ -168,83 +165,6 @@ void Renderer::PokeEFB(EFBAccessType type, const EfbPokeData* points, size_t num
}
}
unsigned int Renderer::GetEFBScale() const
{
return m_efb_scale;
}
int Renderer::EFBToScaledX(int x) const
{
return x * static_cast<int>(m_efb_scale);
}
int Renderer::EFBToScaledY(int y) const
{
return y * static_cast<int>(m_efb_scale);
}
float Renderer::EFBToScaledXf(float x) const
{
return x * ((float)GetTargetWidth() / (float)EFB_WIDTH);
}
float Renderer::EFBToScaledYf(float y) const
{
return y * ((float)GetTargetHeight() / (float)EFB_HEIGHT);
}
std::tuple<int, int> Renderer::CalculateTargetScale(int x, int y) const
{
return std::make_tuple(x * static_cast<int>(m_efb_scale), y * static_cast<int>(m_efb_scale));
}
// return true if target size changed
bool Renderer::CalculateTargetSize()
{
if (g_ActiveConfig.iEFBScale == EFB_SCALE_AUTO_INTEGRAL)
{
auto target_rectangle = g_presenter->GetTargetRectangle();
// Set a scale based on the window size
int width = EFB_WIDTH * target_rectangle.GetWidth() / m_last_xfb_width;
int height = EFB_HEIGHT * target_rectangle.GetHeight() / m_last_xfb_height;
m_efb_scale = std::max((width - 1) / EFB_WIDTH + 1, (height - 1) / EFB_HEIGHT + 1);
}
else
{
m_efb_scale = g_ActiveConfig.iEFBScale;
}
const u32 max_size = g_ActiveConfig.backend_info.MaxTextureSize;
if (max_size < EFB_WIDTH * m_efb_scale)
m_efb_scale = max_size / EFB_WIDTH;
auto [new_efb_width, new_efb_height] = CalculateTargetScale(EFB_WIDTH, EFB_HEIGHT);
new_efb_width = std::max(new_efb_width, 1);
new_efb_height = std::max(new_efb_height, 1);
if (new_efb_width != m_target_width || new_efb_height != m_target_height)
{
m_target_width = new_efb_width;
m_target_height = new_efb_height;
auto& system = Core::System::GetInstance();
auto& pixel_shader_manager = system.GetPixelShaderManager();
pixel_shader_manager.SetEfbScaleChanged(EFBToScaledXf(1), EFBToScaledYf(1));
return true;
}
return false;
}
MathUtil::Rectangle<int> Renderer::ConvertEFBRectangle(const MathUtil::Rectangle<int>& rc) const
{
MathUtil::Rectangle<int> result;
result.left = EFBToScaledX(rc.left);
result.top = EFBToScaledY(rc.top);
result.right = EFBToScaledX(rc.right);
result.bottom = EFBToScaledY(rc.bottom);
return result;
}
void Renderer::UpdateWidescreen()
{
if (SConfig::GetInstance().bWii)
@ -324,20 +244,7 @@ void Renderer::OnConfigChanged(u32 bits)
UpdateWidescreen();
}
void Renderer::TrackSwaps(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height, u64 ticks)
{
if (xfb_addr && fb_width && fb_stride && fb_height)
{
// Update our last xfb values
m_last_xfb_addr = xfb_addr;
m_last_xfb_ticks = ticks;
m_last_xfb_width = fb_width;
m_last_xfb_stride = fb_stride;
m_last_xfb_height = fb_height;
}
}
bool Renderer::UseVertexDepthRange() const
bool Renderer::UseVertexDepthRange()
{
// We can't compute the depth range in the vertex shader if we don't support depth clamp.
if (!g_ActiveConfig.backend_info.bSupportsDepthClamp)
@ -359,29 +266,9 @@ bool Renderer::UseVertexDepthRange() const
void Renderer::DoState(PointerWrap& p)
{
p.Do(m_is_game_widescreen);
p.Do(m_frame_count);
p.Do(m_prev_efb_format);
p.Do(m_last_xfb_ticks);
p.Do(m_last_xfb_addr);
p.Do(m_last_xfb_width);
p.Do(m_last_xfb_stride);
p.Do(m_last_xfb_height);
g_bounding_box->DoState(p);
if (p.IsReadMode())
{
m_was_orthographically_anamorphic = false;
// This technically counts as the end of the frame
AfterFrameEvent::Trigger();
// re-display the most recent XFB
g_presenter->ImmediateSwap(m_last_xfb_addr, m_last_xfb_width, m_last_xfb_stride,
m_last_xfb_height, m_last_xfb_ticks);
}
#if defined(HAVE_FFMPEG)
g_frame_dumper->DoState(p);
#endif
}

View File

@ -25,80 +25,38 @@ struct EfbPokeData
// Renderer really isn't a very good name for this class - it's more like "Misc".
// It used to be a massive mess, but almost everything has been refactored out.
//
// Most of the remaining functionality is related to EFB and Internal Resolution scaling
//
// It also handles the Widescreen heuristic, frame counting and tracking xfb across save states.
// All that's left is Widescreen tracking, pixel format and a thin abstraction layer
// for VideoSoftware to intercept EFB accesses.
class Renderer
{
public:
Renderer();
virtual ~Renderer();
// Ideal internal resolution - multiple of the native EFB resolution
int GetTargetWidth() const { return m_target_width; }
int GetTargetHeight() const { return m_target_height; }
// EFB coordinate conversion functions
// Use this to convert a whole native EFB rect to backbuffer coordinates
MathUtil::Rectangle<int> ConvertEFBRectangle(const MathUtil::Rectangle<int>& rc) const;
unsigned int GetEFBScale() const;
// Use this to upscale native EFB coordinates to IDEAL internal resolution
int EFBToScaledX(int x) const;
int EFBToScaledY(int y) const;
// Floating point versions of the above - only use them if really necessary
float EFBToScaledXf(float x) const;
float EFBToScaledYf(float y) const;
virtual void ReinterpretPixelData(EFBReinterpretType convtype);
virtual u32 AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data);
virtual void PokeEFB(EFBAccessType type, const EfbPokeData* points, size_t num_points);
// Track swaps for save-states
void TrackSwaps(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height, u64 ticks);
bool IsGameWidescreen() const { return m_is_game_widescreen; }
PixelFormat GetPrevPixelFormat() const { return m_prev_efb_format; }
void StorePixelFormat(PixelFormat new_format) { m_prev_efb_format = new_format; }
bool UseVertexDepthRange() const;
static bool UseVertexDepthRange();
void DoState(PointerWrap& p);
bool CalculateTargetSize();
int FrameCount() const { return m_frame_count; }
int FrameCountIncrement() { return m_frame_count++; }
void OnConfigChanged(u32 bits);
protected:
void UpdateWidescreen();
void UpdateWidescreenHeuristic();
std::tuple<int, int> CalculateTargetScale(int x, int y) const;
bool m_is_game_widescreen = false;
bool m_was_orthographically_anamorphic = false;
// The framebuffer size
int m_target_width = 1;
int m_target_height = 1;
private:
PixelFormat m_prev_efb_format;
unsigned int m_efb_scale = 1;
u64 m_last_xfb_ticks = 0;
u32 m_last_xfb_addr = 0;
u32 m_last_xfb_width = 0;
u32 m_last_xfb_stride = 0;
u32 m_last_xfb_height = 0;
int m_frame_count = 0;
EventHook m_update_widescreen_handle;
EventHook m_config_changed_handle;

View File

@ -44,7 +44,7 @@
#include "VideoCommon/HiresTextures.h"
#include "VideoCommon/OpcodeDecoding.h"
#include "VideoCommon/PixelShaderManager.h"
#include "VideoCommon/RenderBase.h"
#include "VideoCommon/Present.h"
#include "VideoCommon/ShaderCache.h"
#include "VideoCommon/Statistics.h"
#include "VideoCommon/TMEM.h"
@ -783,7 +783,7 @@ void TextureCacheBase::OnFrameEnd()
g_texture_cache->FlushEFBCopies();
}
g_texture_cache->Cleanup(g_renderer->FrameCount());
g_texture_cache->Cleanup(g_presenter->FrameCount());
}
void TCacheEntry::DoState(PointerWrap& p)
@ -921,17 +921,17 @@ RcTcacheEntry TextureCacheBase::DoPartialTextureUpdates(RcTcacheEntry& entry_to_
entry->native_width != entry->GetWidth() || entry->native_height != entry->GetHeight())
{
ScaleTextureCacheEntryTo(entry_to_update,
g_renderer->EFBToScaledX(entry_to_update->native_width),
g_renderer->EFBToScaledY(entry_to_update->native_height));
ScaleTextureCacheEntryTo(entry, g_renderer->EFBToScaledX(entry->native_width),
g_renderer->EFBToScaledY(entry->native_height));
g_framebuffer_manager->EFBToScaledX(entry_to_update->native_width),
g_framebuffer_manager->EFBToScaledY(entry_to_update->native_height));
ScaleTextureCacheEntryTo(entry, g_framebuffer_manager->EFBToScaledX(entry->native_width),
g_framebuffer_manager->EFBToScaledY(entry->native_height));
src_x = g_renderer->EFBToScaledX(src_x);
src_y = g_renderer->EFBToScaledY(src_y);
dst_x = g_renderer->EFBToScaledX(dst_x);
dst_y = g_renderer->EFBToScaledY(dst_y);
copy_width = g_renderer->EFBToScaledX(copy_width);
copy_height = g_renderer->EFBToScaledY(copy_height);
src_x = g_framebuffer_manager->EFBToScaledX(src_x);
src_y = g_framebuffer_manager->EFBToScaledY(src_y);
dst_x = g_framebuffer_manager->EFBToScaledX(dst_x);
dst_y = g_framebuffer_manager->EFBToScaledY(dst_y);
copy_width = g_framebuffer_manager->EFBToScaledX(copy_width);
copy_height = g_framebuffer_manager->EFBToScaledY(copy_height);
}
// If the source rectangle is outside of what we actually have in VRAM, skip the copy.
@ -1091,7 +1091,7 @@ static void SetSamplerState(u32 index, float custom_tex_scale, bool custom_tex,
// that have arbitrary contents, eg. are used for fog effects where the
// distance they kick in at is important to preserve at any resolution.
// Correct this with the upscaling factor of custom textures.
s32 lod_offset = std::log2(g_renderer->GetEFBScale() / custom_tex_scale) * 256.f;
s32 lod_offset = std::log2(g_framebuffer_manager->GetEFBScale() / custom_tex_scale) * 256.f;
state.tm0.lod_bias = std::clamp<s32>(state.tm0.lod_bias + lod_offset, -32768, 32767);
// Anisotropic also pushes mips farther away so it cannot be used either
@ -1957,8 +1957,8 @@ void TextureCacheBase::StitchXFBCopy(RcTcacheEntry& stitched_entry)
// copies to be stitched together.
if (create_upscaled_copy)
{
ScaleTextureCacheEntryTo(stitched_entry, g_renderer->EFBToScaledX(stitched_entry->native_width),
g_renderer->EFBToScaledY(stitched_entry->native_height));
ScaleTextureCacheEntryTo(stitched_entry, g_framebuffer_manager->EFBToScaledX(stitched_entry->native_width),
g_framebuffer_manager->EFBToScaledY(stitched_entry->native_height));
}
for (TCacheEntry* entry : candidates)
@ -1993,17 +1993,17 @@ void TextureCacheBase::StitchXFBCopy(RcTcacheEntry& stitched_entry)
// Scale to internal resolution.
if (entry->native_width != entry->GetWidth())
{
src_x = g_renderer->EFBToScaledX(src_x);
src_y = g_renderer->EFBToScaledY(src_y);
src_width = g_renderer->EFBToScaledX(src_width);
src_height = g_renderer->EFBToScaledY(src_height);
src_x = g_framebuffer_manager->EFBToScaledX(src_x);
src_y = g_framebuffer_manager->EFBToScaledY(src_y);
src_width = g_framebuffer_manager->EFBToScaledX(src_width);
src_height = g_framebuffer_manager->EFBToScaledY(src_height);
}
if (create_upscaled_copy)
{
dst_x = g_renderer->EFBToScaledX(dst_x);
dst_y = g_renderer->EFBToScaledY(dst_y);
dst_width = g_renderer->EFBToScaledX(dst_width);
dst_height = g_renderer->EFBToScaledY(dst_height);
dst_x = g_framebuffer_manager->EFBToScaledX(dst_x);
dst_y = g_framebuffer_manager->EFBToScaledY(dst_y);
dst_width = g_framebuffer_manager->EFBToScaledX(dst_width);
dst_height = g_framebuffer_manager->EFBToScaledY(dst_height);
}
// If the source rectangle is outside of what we actually have in VRAM, skip the copy.
@ -2183,8 +2183,8 @@ void TextureCacheBase::CopyRenderTargetToTexture(
// For the latter, we keep the EFB resolution for the virtual XFB blit.
u32 tex_w = width;
u32 tex_h = height;
u32 scaled_tex_w = g_renderer->EFBToScaledX(width);
u32 scaled_tex_h = g_renderer->EFBToScaledY(height);
u32 scaled_tex_w = g_framebuffer_manager->EFBToScaledX(width);
u32 scaled_tex_h = g_framebuffer_manager->EFBToScaledY(height);
if (scaleByHalf)
{
@ -2269,7 +2269,7 @@ void TextureCacheBase::CopyRenderTargetToTexture(
// TODO: This only produces perfect downsampling for 2x IR, other resolutions will need more
// complex down filtering to average all pixels and produce the correct result.
const bool linear_filter =
!is_depth_copy && (scaleByHalf || g_renderer->GetEFBScale() != 1 || y_scale > 1.0f);
!is_depth_copy && (scaleByHalf || g_framebuffer_manager->GetEFBScale() != 1 || y_scale > 1.0f);
RcTcacheEntry entry;
if (copy_to_vram)
@ -2803,7 +2803,7 @@ void TextureCacheBase::CopyEFBToCacheEntry(RcTcacheEntry& entry, bool is_depth_c
return;
}
const auto scaled_src_rect = g_renderer->ConvertEFBRectangle(src_rect);
const auto scaled_src_rect = g_framebuffer_manager->ConvertEFBRectangle(src_rect);
const auto framebuffer_rect = g_gfx->ConvertFramebufferRectangle(
scaled_src_rect, g_framebuffer_manager->GetEFBFramebuffer());
AbstractTexture* src_texture =
@ -2877,7 +2877,7 @@ void TextureCacheBase::CopyEFB(AbstractStagingTexture* dst, const EFBCopyParams&
return;
}
const auto scaled_src_rect = g_renderer->ConvertEFBRectangle(src_rect);
const auto scaled_src_rect = g_framebuffer_manager->ConvertEFBRectangle(src_rect);
const auto framebuffer_rect = g_gfx->ConvertFramebufferRectangle(
scaled_src_rect, g_framebuffer_manager->GetEFBFramebuffer());
AbstractTexture* src_texture =

View File

@ -20,6 +20,7 @@
#include "VideoCommon/BPFunctions.h"
#include "VideoCommon/BPMemory.h"
#include "VideoCommon/CPMemory.h"
#include "VideoCommon/FramebufferManager.h"
#include "VideoCommon/FreeLookCamera.h"
#include "VideoCommon/GraphicsModSystem/Runtime/GraphicsModActionData.h"
#include "VideoCommon/GraphicsModSystem/Runtime/GraphicsModManager.h"
@ -339,10 +340,10 @@ void VertexShaderManager::SetConstants(const std::vector<std::string>& textures)
const bool bUseVertexRounding = g_ActiveConfig.UseVertexRounding();
const float viewport_width = bUseVertexRounding ?
(2.f * xfmem.viewport.wd) :
g_renderer->EFBToScaledXf(2.f * xfmem.viewport.wd);
g_framebuffer_manager->EFBToScaledXf(2.f * xfmem.viewport.wd);
const float viewport_height = bUseVertexRounding ?
(2.f * xfmem.viewport.ht) :
g_renderer->EFBToScaledXf(2.f * xfmem.viewport.ht);
g_framebuffer_manager->EFBToScaledXf(2.f * xfmem.viewport.ht);
const float pixel_size_x = 2.f / viewport_width;
const float pixel_size_y = 2.f / viewport_height;
constants.pixelcentercorrection[0] = pixel_center_correction * pixel_size_x;

View File

@ -14,6 +14,7 @@
#include "Core/ConfigManager.h"
#include "Core/Core.h"
#include "Core/Movie.h"
#include "Core/System.h"
#include "VideoCommon/AbstractGfx.h"
#include "VideoCommon/BPFunctions.h"
@ -24,7 +25,7 @@
#include "VideoCommon/GraphicsModSystem/Runtime/GraphicsModManager.h"
#include "VideoCommon/OnScreenDisplay.h"
#include "VideoCommon/Present.h"
#include "VideoCommon/RenderBase.h"
#include "VideoCommon/PixelShaderManager.h"
#include "VideoCommon/ShaderGenCommon.h"
#include "VideoCommon/TextureCacheBase.h"
#include "VideoCommon/VertexManagerBase.h"
@ -253,6 +254,7 @@ void CheckForConfigChanges()
const auto old_texture_filtering_mode = g_ActiveConfig.texture_filtering_mode;
const bool old_vsync = g_ActiveConfig.bVSyncActive;
const bool old_bbox = g_ActiveConfig.bBBoxEnable;
const int old_efb_scale = g_ActiveConfig.iEFBScale;
const u32 old_game_mod_changes =
g_ActiveConfig.graphics_mod_config ? g_ActiveConfig.graphics_mod_config->GetChangeCount() : 0;
const bool old_graphics_mods_enabled = g_ActiveConfig.bGraphicMods;
@ -302,7 +304,7 @@ void CheckForConfigChanges()
changed_bits |= CONFIG_CHANGE_BIT_VSYNC;
if (old_bbox != g_ActiveConfig.bBBoxEnable)
changed_bits |= CONFIG_CHANGE_BIT_BBOX;
if (g_renderer->CalculateTargetSize())
if (old_efb_scale != g_ActiveConfig.iEFBScale)
changed_bits |= CONFIG_CHANGE_BIT_TARGET_SIZE;
if (old_suggested_aspect_mode != g_ActiveConfig.suggested_aspect_mode)
changed_bits |= CONFIG_CHANGE_BIT_ASPECT_RATIO;
@ -315,10 +317,7 @@ void CheckForConfigChanges()
if (changed_bits == 0)
return;
// Notify all listeners
ConfigChangedEvent::Trigger(changed_bits);
// TODO: Move everything else to the ConfigChanged event
float old_scale = g_framebuffer_manager->GetEFBScale();
// Framebuffer changed?
if (changed_bits & (CONFIG_CHANGE_BIT_MULTISAMPLES | CONFIG_CHANGE_BIT_STEREO_MODE |
@ -327,6 +326,13 @@ void CheckForConfigChanges()
g_framebuffer_manager->RecreateEFBFramebuffer();
}
if (old_scale != g_framebuffer_manager->GetEFBScale())
{
auto& system = Core::System::GetInstance();
auto& pixel_shader_manager = system.GetPixelShaderManager();
pixel_shader_manager.Dirty();
}
// Reload shaders if host config has changed.
if (changed_bits & (CONFIG_CHANGE_BIT_HOST_CONFIG | CONFIG_CHANGE_BIT_MULTISAMPLES))
{
@ -342,6 +348,11 @@ void CheckForConfigChanges()
{
BPFunctions::SetScissorAndViewport();
}
// Notify all listeners
ConfigChangedEvent::Trigger(changed_bits);
// TODO: Move everything else to the ConfigChanged event
}
static EventHook s_check_config_event = AfterFrameEvent::Register([] {

View File

@ -7,15 +7,18 @@
#include "Common/ChunkFile.h"
#include "Core/System.h"
#include "VideoCommon/BoundingBox.h"
#include "VideoCommon/BPMemory.h"
#include "VideoCommon/BPStructs.h"
#include "VideoCommon/CPMemory.h"
#include "VideoCommon/CommandProcessor.h"
#include "VideoCommon/Fifo.h"
#include "VideoCommon/FramebufferManager.h"
#include "VideoCommon/FrameDumper.h"
#include "VideoCommon/GeometryShaderManager.h"
#include "VideoCommon/PixelEngine.h"
#include "VideoCommon/PixelShaderManager.h"
#include "VideoCommon/Present.h"
#include "VideoCommon/RenderBase.h"
#include "VideoCommon/TMEM.h"
#include "VideoCommon/TextureCacheBase.h"
@ -95,6 +98,14 @@ void VideoCommon_DoState(PointerWrap& p)
g_renderer->DoState(p);
p.DoMarker("Renderer");
g_presenter->DoState(p);
g_frame_dumper->DoState(p);
p.DoMarker("Presenter");
g_bounding_box->DoState(p);
p.DoMarker("Bounding Box");
// Refresh state.
if (p.IsReadMode())
{