Split out everying remaining from Swap
This commit is contained in:
parent
2a18b34a73
commit
0da69055d9
|
@ -91,6 +91,7 @@
|
|||
#include "VideoCommon/Present.h"
|
||||
#include "VideoCommon/RenderBase.h"
|
||||
#include "VideoCommon/VideoBackendBase.h"
|
||||
#include "VideoCommon/VideoEvents.h"
|
||||
|
||||
#ifdef ANDROID
|
||||
#include "jni/AndroidCommon/IDCache.h"
|
||||
|
@ -132,6 +133,13 @@ static thread_local bool tls_is_gpu_thread = false;
|
|||
|
||||
static void EmuThread(std::unique_ptr<BootParameters> boot, WindowSystemInfo wsi);
|
||||
|
||||
static EventHook s_frame_presented = AfterPresentEvent::Register([](auto& present_info) {
|
||||
const double last_speed_denominator = g_perf_metrics.GetLastSpeedDenominator();
|
||||
// The denominator should always be > 0 but if it's not, just return 1
|
||||
const double last_speed = last_speed_denominator > 0.0 ? (1.0 / last_speed_denominator) : 1.0;
|
||||
Core::Callback_FramePresented(last_speed);
|
||||
}, "Core Frame Presented");
|
||||
|
||||
bool GetIsThrottlerTempDisabled()
|
||||
{
|
||||
return s_is_throttler_temp_disabled;
|
||||
|
|
|
@ -14,8 +14,13 @@
|
|||
#include "Core/HW/Memmap.h"
|
||||
#include "Core/System.h"
|
||||
|
||||
#include "VideoCommon/BPMemory.h"
|
||||
#include "VideoCommon/CommandProcessor.h"
|
||||
#include "VideoCommon/OpcodeDecoding.h"
|
||||
#include "VideoCommon/TextureDecoder.h"
|
||||
#include "VideoCommon/XFStructs.h"
|
||||
#include "VideoCommon/XFMemory.h"
|
||||
#include "VideoCommon/VideoEvents.h"
|
||||
|
||||
class FifoRecorder::FifoRecordAnalyzer : public OpcodeDecoder::Callback
|
||||
{
|
||||
|
@ -249,6 +254,40 @@ void FifoRecorder::StartRecording(s32 numFrames, CallbackFunc finishedCb)
|
|||
|
||||
m_RequestedRecordingEnd = false;
|
||||
m_FinishedCb = finishedCb;
|
||||
|
||||
m_end_of_frame_event = AfterFrameEvent::Register([this] {
|
||||
const bool was_recording = OpcodeDecoder::g_record_fifo_data;
|
||||
OpcodeDecoder::g_record_fifo_data = IsRecording();
|
||||
|
||||
if (!OpcodeDecoder::g_record_fifo_data)
|
||||
return;
|
||||
|
||||
if (!was_recording)
|
||||
{
|
||||
RecordInitialVideoMemory();
|
||||
}
|
||||
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& command_processor = system.GetCommandProcessor();
|
||||
const auto& fifo = command_processor.GetFifo();
|
||||
EndFrame(fifo.CPBase.load(std::memory_order_relaxed),
|
||||
fifo.CPEnd.load(std::memory_order_relaxed));
|
||||
}, "FifoRecorder::EndFrame");
|
||||
}
|
||||
|
||||
void FifoRecorder::RecordInitialVideoMemory()
|
||||
{
|
||||
const u32* bpmem_ptr = reinterpret_cast<const u32*>(&bpmem);
|
||||
u32 cpmem[256] = {};
|
||||
// The FIFO recording format splits XF memory into xfmem and xfregs; follow
|
||||
// that split here.
|
||||
const u32* xfmem_ptr = reinterpret_cast<const u32*>(&xfmem);
|
||||
const u32* xfregs_ptr = reinterpret_cast<const u32*>(&xfmem) + FifoDataFile::XF_MEM_SIZE;
|
||||
u32 xfregs_size = sizeof(XFMemory) / 4 - FifoDataFile::XF_MEM_SIZE;
|
||||
|
||||
g_main_cp_state.FillCPMemoryArray(cpmem);
|
||||
|
||||
SetVideoMemory(bpmem_ptr, cpmem, xfmem_ptr, xfregs_ptr, xfregs_size, texMem);
|
||||
}
|
||||
|
||||
void FifoRecorder::StopRecording()
|
||||
|
@ -391,11 +430,14 @@ void FifoRecorder::EndFrame(u32 fifoStart, u32 fifoEnd)
|
|||
m_SkipFutureData = true;
|
||||
// Signal video backend that it should not call this function when the next frame ends
|
||||
m_IsRecording = false;
|
||||
|
||||
// Remove our frame end callback
|
||||
m_end_of_frame_event.reset();
|
||||
}
|
||||
}
|
||||
|
||||
void FifoRecorder::SetVideoMemory(const u32* bpMem, const u32* cpMem, const u32* xfMem,
|
||||
const u32* xfRegs, u32 xfRegsSize, const u8* texMem)
|
||||
const u32* xfRegs, u32 xfRegsSize, const u8* texMem_ptr)
|
||||
{
|
||||
std::lock_guard lk(m_mutex);
|
||||
|
||||
|
@ -408,7 +450,7 @@ void FifoRecorder::SetVideoMemory(const u32* bpMem, const u32* cpMem, const u32*
|
|||
u32 xfRegsCopySize = std::min((u32)FifoDataFile::XF_REGS_SIZE, xfRegsSize);
|
||||
memcpy(m_File->GetXFRegs(), xfRegs, xfRegsCopySize * 4);
|
||||
|
||||
memcpy(m_File->GetTexMem(), texMem, FifoDataFile::TEX_MEM_SIZE);
|
||||
memcpy(m_File->GetTexMem(), texMem_ptr, FifoDataFile::TEX_MEM_SIZE);
|
||||
}
|
||||
|
||||
m_record_analyzer = std::make_unique<FifoRecordAnalyzer>(this, cpMem);
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <vector>
|
||||
|
||||
#include "Common/Assert.h"
|
||||
#include "Common/EventHook.h"
|
||||
#include "Core/FifoPlayer/FifoDataFile.h"
|
||||
|
||||
class FifoRecorder
|
||||
|
@ -50,6 +51,8 @@ public:
|
|||
private:
|
||||
class FifoRecordAnalyzer;
|
||||
|
||||
void RecordInitialVideoMemory();
|
||||
|
||||
// Accessed from both GUI and video threads
|
||||
|
||||
std::recursive_mutex m_mutex;
|
||||
|
@ -72,4 +75,6 @@ private:
|
|||
std::vector<u8> m_FifoData;
|
||||
std::vector<u8> m_Ram;
|
||||
std::vector<u8> m_ExRam;
|
||||
|
||||
EventHook m_end_of_frame_event;
|
||||
};
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
|
||||
#include "InputCommon/DynamicInputTextures/DITConfiguration.h"
|
||||
#include "VideoCommon/HiresTextures.h"
|
||||
#include "VideoCommon/RenderBase.h"
|
||||
#include "VideoCommon/TextureCacheBase.h"
|
||||
|
||||
namespace InputCommon
|
||||
{
|
||||
|
@ -48,7 +48,7 @@ void DynamicInputTextureManager::GenerateTextures(const IniFile& file,
|
|||
any_dirty |= configuration.GenerateTextures(file, controller_names);
|
||||
}
|
||||
|
||||
if (any_dirty && g_renderer && Core::GetState() != Core::State::Starting)
|
||||
g_renderer->ForceReloadTextures();
|
||||
if (any_dirty && g_texture_cache && Core::GetState() != Core::State::Starting)
|
||||
g_texture_cache->ForceReloadTextures();
|
||||
}
|
||||
} // namespace InputCommon
|
||||
|
|
|
@ -28,6 +28,7 @@ static bool DumpFrameToPNG(const FrameData& frame, const std::string& file_name)
|
|||
|
||||
FrameDumper::FrameDumper()
|
||||
{
|
||||
m_frame_end_handle = AfterFrameEvent::Register([this] { FlushFrameDump(); }, "FrameDumper");
|
||||
}
|
||||
|
||||
FrameDumper::~FrameDumper()
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "Common/Thread.h"
|
||||
|
||||
#include "VideoCommon/FrameDumpFFMpeg.h"
|
||||
#include "VideoCommon/VideoEvents.h"
|
||||
|
||||
class AbstractStagingTexture;
|
||||
class AbstractTexture;
|
||||
|
@ -116,6 +117,8 @@ private:
|
|||
Common::Event m_screenshot_completed;
|
||||
std::mutex m_screenshot_lock;
|
||||
std::string m_screenshot_name;
|
||||
|
||||
EventHook m_frame_end_handle;
|
||||
};
|
||||
|
||||
extern std::unique_ptr<FrameDumper> g_frame_dumper;
|
||||
|
|
|
@ -79,6 +79,8 @@ bool FramebufferManager::Initialize()
|
|||
return false;
|
||||
}
|
||||
|
||||
m_end_of_frame_event = AfterFrameEvent::Register([this] { EndOfFrame(); }, "FramebufferManager");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "VideoCommon/AbstractTexture.h"
|
||||
#include "VideoCommon/RenderState.h"
|
||||
#include "VideoCommon/TextureConfig.h"
|
||||
#include "VideoCommon/VideoEvents.h"
|
||||
|
||||
class NativeVertexFormat;
|
||||
class PointerWrap;
|
||||
|
@ -213,6 +214,8 @@ protected:
|
|||
std::unique_ptr<AbstractPipeline> m_depth_poke_pipeline;
|
||||
std::vector<EFBPokeVertex> m_color_poke_vertices;
|
||||
std::vector<EFBPokeVertex> m_depth_poke_vertices;
|
||||
|
||||
EventHook m_end_of_frame_event;
|
||||
};
|
||||
|
||||
extern std::unique_ptr<FramebufferManager> g_framebuffer_manager;
|
||||
|
|
|
@ -85,6 +85,8 @@ bool GraphicsModManager::Initialize()
|
|||
g_ActiveConfig.graphics_mod_config->Load();
|
||||
g_ActiveConfig.graphics_mod_config->SetChangeCount(old_game_mod_changes);
|
||||
g_graphics_mod_manager->Load(*g_ActiveConfig.graphics_mod_config);
|
||||
|
||||
m_end_of_frame_event = AfterFrameEvent::Register([this] { EndOfFrame(); }, "ModManager");
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "VideoCommon/GraphicsModSystem/Runtime/GraphicsModAction.h"
|
||||
#include "VideoCommon/TextureInfo.h"
|
||||
#include "VideoCommon/XFMemory.h"
|
||||
#include "VideoCommon/VideoEvents.h"
|
||||
|
||||
class GraphicsModGroupConfig;
|
||||
class GraphicsModManager
|
||||
|
@ -34,9 +35,8 @@ public:
|
|||
|
||||
void Load(const GraphicsModGroupConfig& config);
|
||||
|
||||
void EndOfFrame();
|
||||
|
||||
private:
|
||||
void EndOfFrame();
|
||||
void Reset();
|
||||
|
||||
class DecoratedAction;
|
||||
|
@ -53,6 +53,8 @@ private:
|
|||
std::unordered_map<FBInfo, std::vector<GraphicsModAction*>, FBInfoHasher> m_xfb_target_to_actions;
|
||||
|
||||
std::unordered_set<std::string> m_groups;
|
||||
|
||||
EventHook m_end_of_frame_event;
|
||||
};
|
||||
|
||||
extern std::unique_ptr<GraphicsModManager> g_graphics_mod_manager;
|
||||
|
|
|
@ -100,6 +100,8 @@ void Presenter::ViSwap(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height,
|
|||
{
|
||||
Present();
|
||||
ProcessFrameDumping(ticks);
|
||||
|
||||
AfterPresentEvent::Trigger(present_info);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -117,8 +119,12 @@ void Presenter::ImmediateSwap(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_
|
|||
present_info.reason = PresentInfo::PresentReason::Immediate;
|
||||
present_info.present_count = m_present_count++;
|
||||
|
||||
BeforePresentEvent::Trigger(present_info);
|
||||
|
||||
Present();
|
||||
ProcessFrameDumping(ticks);
|
||||
|
||||
AfterPresentEvent::Trigger(present_info);
|
||||
}
|
||||
|
||||
void Presenter::ProcessFrameDumping(u64 ticks) const
|
||||
|
|
|
@ -64,6 +64,10 @@ Renderer::Renderer()
|
|||
{
|
||||
UpdateActiveConfig();
|
||||
CalculateTargetSize();
|
||||
UpdateWidescreen();
|
||||
// VertexManager doesn't maintain statistics in Wii mode.
|
||||
if (!SConfig::GetInstance().bWii)
|
||||
m_update_widescreen_handle = AfterFrameEvent::Register([this] { UpdateWidescreenHeuristic(); }, "WideScreen Heuristic");
|
||||
}
|
||||
|
||||
Renderer::~Renderer() = default;
|
||||
|
@ -202,15 +206,6 @@ void Renderer::PokeEFB(EFBAccessType type, const EfbPokeData* points, size_t num
|
|||
}
|
||||
}
|
||||
|
||||
void Renderer::RenderToXFB(u32 xfbAddr, const MathUtil::Rectangle<int>& sourceRc, u32 fbStride,
|
||||
u32 fbHeight, float Gamma)
|
||||
{
|
||||
CheckFifoRecording();
|
||||
|
||||
if (!fbStride || !fbHeight)
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned int Renderer::GetEFBScale() const
|
||||
{
|
||||
return m_efb_scale;
|
||||
|
@ -288,60 +283,39 @@ MathUtil::Rectangle<int> Renderer::ConvertEFBRectangle(const MathUtil::Rectangle
|
|||
return result;
|
||||
}
|
||||
|
||||
void Renderer::CheckFifoRecording()
|
||||
void Renderer::UpdateWidescreen()
|
||||
{
|
||||
const bool was_recording = OpcodeDecoder::g_record_fifo_data;
|
||||
OpcodeDecoder::g_record_fifo_data = FifoRecorder::GetInstance().IsRecording();
|
||||
if (SConfig::GetInstance().bWii)
|
||||
m_is_game_widescreen = Config::Get(Config::SYSCONF_WIDESCREEN);
|
||||
|
||||
if (!OpcodeDecoder::g_record_fifo_data)
|
||||
return;
|
||||
// suggested_aspect_mode overrides SYSCONF_WIDESCREEN
|
||||
if (g_ActiveConfig.suggested_aspect_mode == AspectMode::Analog)
|
||||
m_is_game_widescreen = false;
|
||||
else if (g_ActiveConfig.suggested_aspect_mode == AspectMode::AnalogWide)
|
||||
m_is_game_widescreen = true;
|
||||
|
||||
if (!was_recording)
|
||||
// If widescreen hack is disabled override game's AR if UI is set to 4:3 or 16:9.
|
||||
if (!g_ActiveConfig.bWidescreenHack)
|
||||
{
|
||||
RecordVideoMemory();
|
||||
const auto aspect_mode = g_ActiveConfig.aspect_mode;
|
||||
if (aspect_mode == AspectMode::Analog)
|
||||
m_is_game_widescreen = false;
|
||||
else if (aspect_mode == AspectMode::AnalogWide)
|
||||
m_is_game_widescreen = true;
|
||||
}
|
||||
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& command_processor = system.GetCommandProcessor();
|
||||
const auto& fifo = command_processor.GetFifo();
|
||||
FifoRecorder::GetInstance().EndFrame(fifo.CPBase.load(std::memory_order_relaxed),
|
||||
fifo.CPEnd.load(std::memory_order_relaxed));
|
||||
}
|
||||
|
||||
void Renderer::RecordVideoMemory()
|
||||
{
|
||||
const u32* bpmem_ptr = reinterpret_cast<const u32*>(&bpmem);
|
||||
u32 cpmem[256] = {};
|
||||
// The FIFO recording format splits XF memory into xfmem and xfregs; follow
|
||||
// that split here.
|
||||
const u32* xfmem_ptr = reinterpret_cast<const u32*>(&xfmem);
|
||||
const u32* xfregs_ptr = reinterpret_cast<const u32*>(&xfmem) + FifoDataFile::XF_MEM_SIZE;
|
||||
u32 xfregs_size = sizeof(XFMemory) / 4 - FifoDataFile::XF_MEM_SIZE;
|
||||
|
||||
g_main_cp_state.FillCPMemoryArray(cpmem);
|
||||
|
||||
FifoRecorder::GetInstance().SetVideoMemory(bpmem_ptr, cpmem, xfmem_ptr, xfregs_ptr, xfregs_size,
|
||||
texMem);
|
||||
}
|
||||
|
||||
void Renderer::ForceReloadTextures()
|
||||
{
|
||||
m_force_reload_textures.Set();
|
||||
}
|
||||
|
||||
// Heuristic to detect if a GameCube game is in 16:9 anamorphic widescreen mode.
|
||||
void Renderer::UpdateWidescreenHeuristic()
|
||||
{
|
||||
// VertexManager maintains no statistics in Wii mode.
|
||||
if (SConfig::GetInstance().bWii)
|
||||
return;
|
||||
|
||||
const auto flush_statistics = g_vertex_manager->ResetFlushAspectRatioCount();
|
||||
|
||||
// If suggested_aspect_mode (GameINI) is configured don't use heuristic.
|
||||
if (g_ActiveConfig.suggested_aspect_mode != AspectMode::Auto)
|
||||
return;
|
||||
|
||||
UpdateWidescreen();
|
||||
|
||||
// If widescreen hack isn't active and aspect_mode (UI) is 4:3 or 16:9 don't use heuristic.
|
||||
if (!g_ActiveConfig.bWidescreenHack && (g_ActiveConfig.aspect_mode == AspectMode::Analog ||
|
||||
g_ActiveConfig.aspect_mode == AspectMode::AnalogWide))
|
||||
|
@ -382,109 +356,16 @@ void Renderer::UpdateWidescreenHeuristic()
|
|||
m_was_orthographically_anamorphic = ortho_looks_anamorphic;
|
||||
}
|
||||
|
||||
void Renderer::OnConfigChanged(u32 bits)
|
||||
{
|
||||
if (bits & CONFIG_CHANGE_BIT_ASPECT_RATIO)
|
||||
UpdateWidescreen();
|
||||
}
|
||||
|
||||
void Renderer::Swap(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height, u64 ticks)
|
||||
{
|
||||
if (SConfig::GetInstance().bWii)
|
||||
m_is_game_widescreen = Config::Get(Config::SYSCONF_WIDESCREEN);
|
||||
|
||||
// suggested_aspect_mode overrides SYSCONF_WIDESCREEN
|
||||
if (g_ActiveConfig.suggested_aspect_mode == AspectMode::Analog)
|
||||
m_is_game_widescreen = false;
|
||||
else if (g_ActiveConfig.suggested_aspect_mode == AspectMode::AnalogWide)
|
||||
m_is_game_widescreen = true;
|
||||
|
||||
// If widescreen hack is disabled override game's AR if UI is set to 4:3 or 16:9.
|
||||
if (!g_ActiveConfig.bWidescreenHack)
|
||||
{
|
||||
const auto aspect_mode = g_ActiveConfig.aspect_mode;
|
||||
if (aspect_mode == AspectMode::Analog)
|
||||
m_is_game_widescreen = false;
|
||||
else if (aspect_mode == AspectMode::AnalogWide)
|
||||
m_is_game_widescreen = true;
|
||||
}
|
||||
UpdateWidescreenHeuristic();
|
||||
|
||||
// Ensure the last frame was written to the dump.
|
||||
// This is required even if frame dumping has stopped, since the frame dump is one frame
|
||||
// behind the renderer.
|
||||
g_frame_dumper->FlushFrameDump();
|
||||
|
||||
if (g_ActiveConfig.bGraphicMods)
|
||||
{
|
||||
g_graphics_mod_manager->EndOfFrame();
|
||||
}
|
||||
|
||||
g_framebuffer_manager->EndOfFrame();
|
||||
|
||||
if (xfb_addr && fb_width && fb_stride && fb_height)
|
||||
{
|
||||
// Get the current XFB from texture cache
|
||||
|
||||
g_presenter->ReleaseXFBContentLock();
|
||||
|
||||
MathUtil::Rectangle<int> xfb_rect;
|
||||
RcTcacheEntry xfb_entry =
|
||||
g_texture_cache->GetXFBTexture(xfb_addr, fb_width, fb_height, fb_stride, &xfb_rect);
|
||||
|
||||
bool is_duplicate_frame =
|
||||
g_presenter->SubmitXFB(std::move(xfb_entry), xfb_rect, ticks, m_frame_count);
|
||||
|
||||
if (!g_ActiveConfig.bSkipPresentingDuplicateXFBs || !is_duplicate_frame)
|
||||
{
|
||||
if (!is_duplicate_frame)
|
||||
{
|
||||
DolphinAnalytics::PerformanceSample perf_sample;
|
||||
perf_sample.speed_ratio = SystemTimers::GetEstimatedEmulationPerformance();
|
||||
perf_sample.num_prims = g_stats.this_frame.num_prims + g_stats.this_frame.num_dl_prims;
|
||||
perf_sample.num_draw_calls = g_stats.this_frame.num_draw_calls;
|
||||
DolphinAnalytics::Instance().ReportPerformanceInfo(std::move(perf_sample));
|
||||
|
||||
// Begin new frame
|
||||
m_frame_count++;
|
||||
g_stats.ResetFrame();
|
||||
}
|
||||
|
||||
g_shader_cache->RetrieveAsyncShaders();
|
||||
g_vertex_manager->OnEndFrame();
|
||||
|
||||
// We invalidate the pipeline object at the start of the frame.
|
||||
// This is for the rare case where only a single pipeline configuration is used,
|
||||
// and hybrid ubershaders have compiled the specialized shader, but without any
|
||||
// state changes the specialized shader will not take over.
|
||||
g_vertex_manager->InvalidatePipelineObject();
|
||||
|
||||
if (m_force_reload_textures.TestAndClear())
|
||||
{
|
||||
g_texture_cache->ForceReload();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Flush any outstanding EFB copies to RAM, in case the game is running at an uncapped frame
|
||||
// rate and not waiting for vblank. Otherwise, we'd end up with a huge list of pending
|
||||
// copies.
|
||||
g_texture_cache->FlushEFBCopies();
|
||||
}
|
||||
|
||||
if (!is_duplicate_frame)
|
||||
{
|
||||
// Remove stale EFB/XFB copies.
|
||||
g_texture_cache->Cleanup(m_frame_count);
|
||||
const double last_speed_denominator = g_perf_metrics.GetLastSpeedDenominator();
|
||||
// The denominator should always be > 0 but if it's not, just return 1
|
||||
const double last_speed =
|
||||
last_speed_denominator > 0.0 ? (1.0 / last_speed_denominator) : 1.0;
|
||||
Core::Callback_FramePresented(last_speed);
|
||||
}
|
||||
|
||||
// Handle any config changes, this gets propagated to the backend.
|
||||
CheckForConfigChanges();
|
||||
g_Config.iSaveTargetId = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_gfx->Flush();
|
||||
}
|
||||
|
||||
// Update our last xfb values
|
||||
m_last_xfb_addr = xfb_addr;
|
||||
m_last_xfb_ticks = ticks;
|
||||
|
@ -492,10 +373,6 @@ void Renderer::Swap(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height, u6
|
|||
m_last_xfb_stride = fb_stride;
|
||||
m_last_xfb_height = fb_height;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_gfx->Flush();
|
||||
}
|
||||
}
|
||||
|
||||
bool Renderer::UseVertexDepthRange() const
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "Common/Flag.h"
|
||||
#include "Common/MathUtil.h"
|
||||
#include "VideoCommon/RenderState.h"
|
||||
#include "VideoCommon/VideoEvents.h"
|
||||
|
||||
class AbstractFramebuffer;
|
||||
class AbstractPipeline;
|
||||
|
@ -86,8 +87,6 @@ public:
|
|||
void ClearScreen(const MathUtil::Rectangle<int>& rc, bool colorEnable, bool alphaEnable,
|
||||
bool zEnable, u32 color, u32 z);
|
||||
virtual void ReinterpretPixelData(EFBReinterpretType convtype);
|
||||
void RenderToXFB(u32 xfbAddr, const MathUtil::Rectangle<int>& sourceRc, u32 fbStride,
|
||||
u32 fbHeight, float Gamma = 1.0f);
|
||||
|
||||
virtual u32 AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data);
|
||||
virtual void PokeEFB(EFBAccessType type, const EfbPokeData* points, size_t num_points);
|
||||
|
@ -95,7 +94,6 @@ public:
|
|||
// Finish up the current frame, print some stats
|
||||
void Swap(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height, u64 ticks);
|
||||
|
||||
void UpdateWidescreenHeuristic();
|
||||
bool IsGameWidescreen() const { return m_is_game_widescreen; }
|
||||
|
||||
PixelFormat GetPrevPixelFormat() const { return m_prev_efb_format; }
|
||||
|
@ -104,16 +102,17 @@ public:
|
|||
bool UseVertexDepthRange() const;
|
||||
void DoState(PointerWrap& p);
|
||||
|
||||
// Will forcibly reload all textures on the next swap
|
||||
void ForceReloadTextures();
|
||||
|
||||
bool CalculateTargetSize();
|
||||
|
||||
protected:
|
||||
std::tuple<int, int> CalculateTargetScale(int x, int y) const;
|
||||
int m_frame_count = 0;
|
||||
|
||||
void CheckFifoRecording();
|
||||
void RecordVideoMemory();
|
||||
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;
|
||||
|
@ -122,8 +121,6 @@ protected:
|
|||
int m_target_width = 1;
|
||||
int m_target_height = 1;
|
||||
|
||||
int m_frame_count = 0;
|
||||
|
||||
private:
|
||||
PixelFormat m_prev_efb_format;
|
||||
unsigned int m_efb_scale = 1;
|
||||
|
@ -134,7 +131,8 @@ private:
|
|||
u32 m_last_xfb_stride = 0;
|
||||
u32 m_last_xfb_height = 0;
|
||||
|
||||
Common::Flag m_force_reload_textures;
|
||||
EventHook m_update_widescreen_handle;
|
||||
EventHook m_config_changed_handle;
|
||||
};
|
||||
|
||||
extern std::unique_ptr<Renderer> g_renderer;
|
||||
|
|
|
@ -46,6 +46,7 @@ bool ShaderCache::Initialize()
|
|||
return false;
|
||||
|
||||
m_async_shader_compiler = g_gfx->CreateAsyncShaderCompiler();
|
||||
m_frame_end_handler = AfterFrameEvent::Register([this] { RetrieveAsyncShaders(); }, "RetreiveAsyncShaders");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include "VideoCommon/UberShaderPixel.h"
|
||||
#include "VideoCommon/UberShaderVertex.h"
|
||||
#include "VideoCommon/VertexShaderGen.h"
|
||||
#include "VideoCommon/VideoEvents.h"
|
||||
|
||||
class NativeVertexFormat;
|
||||
enum class AbstractTextureFormat : u32;
|
||||
|
@ -250,6 +251,8 @@ private:
|
|||
|
||||
// Texture decoding shaders
|
||||
std::map<std::pair<u32, u32>, std::unique_ptr<AbstractShader>> m_texture_decoding_shaders;
|
||||
|
||||
EventHook m_frame_end_handler;
|
||||
};
|
||||
|
||||
} // namespace VideoCommon
|
||||
|
|
|
@ -8,11 +8,28 @@
|
|||
|
||||
#include <imgui.h>
|
||||
|
||||
#include "Core/DolphinAnalytics.h"
|
||||
#include "Core/HW/SystemTimers.h"
|
||||
|
||||
#include "VideoCommon/BPFunctions.h"
|
||||
#include "VideoCommon/VideoCommon.h"
|
||||
#include "VideoCommon/VideoConfig.h"
|
||||
#include "VideoCommon/VideoEvents.h"
|
||||
|
||||
Statistics g_stats;
|
||||
|
||||
static EventHook s_before_frame_event = BeforeFrameEvent::Register([] {
|
||||
g_stats.ResetFrame();
|
||||
}, "Statistics::ResetFrame");
|
||||
|
||||
static EventHook s_after_frame_event = AfterFrameEvent::Register([] {
|
||||
DolphinAnalytics::PerformanceSample perf_sample;
|
||||
perf_sample.speed_ratio = SystemTimers::GetEstimatedEmulationPerformance();
|
||||
perf_sample.num_prims = g_stats.this_frame.num_prims + g_stats.this_frame.num_dl_prims;
|
||||
perf_sample.num_draw_calls = g_stats.this_frame.num_draw_calls;
|
||||
DolphinAnalytics::Instance().ReportPerformanceInfo(std::move(perf_sample));
|
||||
}, "Statistics::PerformanceSample");
|
||||
|
||||
static bool clear_scissors;
|
||||
|
||||
void Statistics::ResetFrame()
|
||||
|
|
|
@ -769,6 +769,23 @@ void TextureCacheBase::DoLoadState(PointerWrap& p)
|
|||
}
|
||||
}
|
||||
|
||||
void TextureCacheBase::OnFrameEnd()
|
||||
{
|
||||
if (m_force_reload_textures.TestAndClear())
|
||||
{
|
||||
ForceReload();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Flush any outstanding EFB copies to RAM, in case the game is running at an uncapped frame
|
||||
// rate and not waiting for vblank. Otherwise, we'd end up with a huge list of pending
|
||||
// copies.
|
||||
g_texture_cache->FlushEFBCopies();
|
||||
}
|
||||
|
||||
g_texture_cache->Cleanup(g_renderer->m_frame_count);
|
||||
}
|
||||
|
||||
void TCacheEntry::DoState(PointerWrap& p)
|
||||
{
|
||||
p.Do(addr);
|
||||
|
|
|
@ -18,12 +18,15 @@
|
|||
|
||||
#include "Common/BitSet.h"
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/Flag.h"
|
||||
#include "Common/MathUtil.h"
|
||||
|
||||
#include "VideoCommon/AbstractTexture.h"
|
||||
#include "VideoCommon/BPMemory.h"
|
||||
#include "VideoCommon/TextureConfig.h"
|
||||
#include "VideoCommon/TextureDecoder.h"
|
||||
#include "VideoCommon/TextureInfo.h"
|
||||
#include "VideoCommon/VideoEvents.h"
|
||||
|
||||
class AbstractFramebuffer;
|
||||
class AbstractStagingTexture;
|
||||
|
@ -288,6 +291,9 @@ public:
|
|||
static bool AllCopyFilterCoefsNeeded(const std::array<u32, 3>& coefficients);
|
||||
static bool CopyFilterCanOverflow(const std::array<u32, 3>& coefficients);
|
||||
|
||||
// Will forcibly reload all textures when the frame next ends
|
||||
void ForceReloadTextures() { m_force_reload_textures.Set(); }
|
||||
|
||||
protected:
|
||||
// Decodes the specified data to the GPU texture specified by entry.
|
||||
// Returns false if the configuration is not supported.
|
||||
|
@ -428,6 +434,11 @@ private:
|
|||
// We store this in the class so that the same staging texture can be used for multiple
|
||||
// readbacks, saving the overhead of allocating a new buffer every time.
|
||||
std::unique_ptr<AbstractStagingTexture> m_readback_texture;
|
||||
|
||||
void OnFrameEnd();
|
||||
|
||||
Common::Flag m_force_reload_textures;
|
||||
EventHook m_frame_event = AfterFrameEvent::Register([this] { OnFrameEnd(); }, "TextureCache");
|
||||
};
|
||||
|
||||
extern std::unique_ptr<TextureCacheBase> g_texture_cache;
|
||||
|
|
|
@ -105,6 +105,7 @@ VertexManagerBase::~VertexManagerBase() = default;
|
|||
|
||||
bool VertexManagerBase::Initialize()
|
||||
{
|
||||
m_frame_end_event = AfterFrameEvent::Register([this] { OnEndFrame();}, "VertexManagerBase");
|
||||
m_index_generator.Init();
|
||||
m_cpu_cull.Init();
|
||||
return true;
|
||||
|
@ -996,4 +997,10 @@ void VertexManagerBase::OnEndFrame()
|
|||
#endif
|
||||
|
||||
m_cpu_accesses_this_frame.clear();
|
||||
|
||||
// We invalidate the pipeline object at the start of the frame.
|
||||
// This is for the rare case where only a single pipeline configuration is used,
|
||||
// and hybrid ubershaders have compiled the specialized shader, but without any
|
||||
// state changes the specialized shader will not take over.
|
||||
InvalidatePipelineObject();
|
||||
}
|
||||
|
|
|
@ -229,6 +229,8 @@ private:
|
|||
std::vector<u32> m_cpu_accesses_this_frame;
|
||||
std::vector<u32> m_scheduled_command_buffer_kicks;
|
||||
bool m_allow_background_execution = true;
|
||||
|
||||
EventHook m_frame_end_event;
|
||||
};
|
||||
|
||||
extern std::unique_ptr<VertexManagerBase> g_vertex_manager;
|
||||
|
|
|
@ -341,3 +341,8 @@ void CheckForConfigChanges()
|
|||
BPFunctions::SetScissorAndViewport();
|
||||
}
|
||||
}
|
||||
|
||||
static EventHook s_check_config_event = AfterFrameEvent::Register([] {
|
||||
CheckForConfigChanges();
|
||||
|
||||
}, "CheckForConfigChanges");
|
||||
|
|
Loading…
Reference in New Issue