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/Present.h"
|
||||||
#include "VideoCommon/RenderBase.h"
|
#include "VideoCommon/RenderBase.h"
|
||||||
#include "VideoCommon/VideoBackendBase.h"
|
#include "VideoCommon/VideoBackendBase.h"
|
||||||
|
#include "VideoCommon/VideoEvents.h"
|
||||||
|
|
||||||
#ifdef ANDROID
|
#ifdef ANDROID
|
||||||
#include "jni/AndroidCommon/IDCache.h"
|
#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 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()
|
bool GetIsThrottlerTempDisabled()
|
||||||
{
|
{
|
||||||
return s_is_throttler_temp_disabled;
|
return s_is_throttler_temp_disabled;
|
||||||
|
|
|
@ -14,8 +14,13 @@
|
||||||
#include "Core/HW/Memmap.h"
|
#include "Core/HW/Memmap.h"
|
||||||
#include "Core/System.h"
|
#include "Core/System.h"
|
||||||
|
|
||||||
|
#include "VideoCommon/BPMemory.h"
|
||||||
|
#include "VideoCommon/CommandProcessor.h"
|
||||||
#include "VideoCommon/OpcodeDecoding.h"
|
#include "VideoCommon/OpcodeDecoding.h"
|
||||||
|
#include "VideoCommon/TextureDecoder.h"
|
||||||
#include "VideoCommon/XFStructs.h"
|
#include "VideoCommon/XFStructs.h"
|
||||||
|
#include "VideoCommon/XFMemory.h"
|
||||||
|
#include "VideoCommon/VideoEvents.h"
|
||||||
|
|
||||||
class FifoRecorder::FifoRecordAnalyzer : public OpcodeDecoder::Callback
|
class FifoRecorder::FifoRecordAnalyzer : public OpcodeDecoder::Callback
|
||||||
{
|
{
|
||||||
|
@ -249,6 +254,40 @@ void FifoRecorder::StartRecording(s32 numFrames, CallbackFunc finishedCb)
|
||||||
|
|
||||||
m_RequestedRecordingEnd = false;
|
m_RequestedRecordingEnd = false;
|
||||||
m_FinishedCb = finishedCb;
|
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()
|
void FifoRecorder::StopRecording()
|
||||||
|
@ -391,11 +430,14 @@ void FifoRecorder::EndFrame(u32 fifoStart, u32 fifoEnd)
|
||||||
m_SkipFutureData = true;
|
m_SkipFutureData = true;
|
||||||
// Signal video backend that it should not call this function when the next frame ends
|
// Signal video backend that it should not call this function when the next frame ends
|
||||||
m_IsRecording = false;
|
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,
|
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);
|
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);
|
u32 xfRegsCopySize = std::min((u32)FifoDataFile::XF_REGS_SIZE, xfRegsSize);
|
||||||
memcpy(m_File->GetXFRegs(), xfRegs, xfRegsCopySize * 4);
|
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);
|
m_record_analyzer = std::make_unique<FifoRecordAnalyzer>(this, cpMem);
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "Common/Assert.h"
|
#include "Common/Assert.h"
|
||||||
|
#include "Common/EventHook.h"
|
||||||
#include "Core/FifoPlayer/FifoDataFile.h"
|
#include "Core/FifoPlayer/FifoDataFile.h"
|
||||||
|
|
||||||
class FifoRecorder
|
class FifoRecorder
|
||||||
|
@ -50,6 +51,8 @@ public:
|
||||||
private:
|
private:
|
||||||
class FifoRecordAnalyzer;
|
class FifoRecordAnalyzer;
|
||||||
|
|
||||||
|
void RecordInitialVideoMemory();
|
||||||
|
|
||||||
// Accessed from both GUI and video threads
|
// Accessed from both GUI and video threads
|
||||||
|
|
||||||
std::recursive_mutex m_mutex;
|
std::recursive_mutex m_mutex;
|
||||||
|
@ -72,4 +75,6 @@ private:
|
||||||
std::vector<u8> m_FifoData;
|
std::vector<u8> m_FifoData;
|
||||||
std::vector<u8> m_Ram;
|
std::vector<u8> m_Ram;
|
||||||
std::vector<u8> m_ExRam;
|
std::vector<u8> m_ExRam;
|
||||||
|
|
||||||
|
EventHook m_end_of_frame_event;
|
||||||
};
|
};
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
|
|
||||||
#include "InputCommon/DynamicInputTextures/DITConfiguration.h"
|
#include "InputCommon/DynamicInputTextures/DITConfiguration.h"
|
||||||
#include "VideoCommon/HiresTextures.h"
|
#include "VideoCommon/HiresTextures.h"
|
||||||
#include "VideoCommon/RenderBase.h"
|
#include "VideoCommon/TextureCacheBase.h"
|
||||||
|
|
||||||
namespace InputCommon
|
namespace InputCommon
|
||||||
{
|
{
|
||||||
|
@ -48,7 +48,7 @@ void DynamicInputTextureManager::GenerateTextures(const IniFile& file,
|
||||||
any_dirty |= configuration.GenerateTextures(file, controller_names);
|
any_dirty |= configuration.GenerateTextures(file, controller_names);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (any_dirty && g_renderer && Core::GetState() != Core::State::Starting)
|
if (any_dirty && g_texture_cache && Core::GetState() != Core::State::Starting)
|
||||||
g_renderer->ForceReloadTextures();
|
g_texture_cache->ForceReloadTextures();
|
||||||
}
|
}
|
||||||
} // namespace InputCommon
|
} // namespace InputCommon
|
||||||
|
|
|
@ -28,6 +28,7 @@ static bool DumpFrameToPNG(const FrameData& frame, const std::string& file_name)
|
||||||
|
|
||||||
FrameDumper::FrameDumper()
|
FrameDumper::FrameDumper()
|
||||||
{
|
{
|
||||||
|
m_frame_end_handle = AfterFrameEvent::Register([this] { FlushFrameDump(); }, "FrameDumper");
|
||||||
}
|
}
|
||||||
|
|
||||||
FrameDumper::~FrameDumper()
|
FrameDumper::~FrameDumper()
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include "Common/Thread.h"
|
#include "Common/Thread.h"
|
||||||
|
|
||||||
#include "VideoCommon/FrameDumpFFMpeg.h"
|
#include "VideoCommon/FrameDumpFFMpeg.h"
|
||||||
|
#include "VideoCommon/VideoEvents.h"
|
||||||
|
|
||||||
class AbstractStagingTexture;
|
class AbstractStagingTexture;
|
||||||
class AbstractTexture;
|
class AbstractTexture;
|
||||||
|
@ -116,6 +117,8 @@ private:
|
||||||
Common::Event m_screenshot_completed;
|
Common::Event m_screenshot_completed;
|
||||||
std::mutex m_screenshot_lock;
|
std::mutex m_screenshot_lock;
|
||||||
std::string m_screenshot_name;
|
std::string m_screenshot_name;
|
||||||
|
|
||||||
|
EventHook m_frame_end_handle;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern std::unique_ptr<FrameDumper> g_frame_dumper;
|
extern std::unique_ptr<FrameDumper> g_frame_dumper;
|
||||||
|
|
|
@ -79,6 +79,8 @@ bool FramebufferManager::Initialize()
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_end_of_frame_event = AfterFrameEvent::Register([this] { EndOfFrame(); }, "FramebufferManager");
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include "VideoCommon/AbstractTexture.h"
|
#include "VideoCommon/AbstractTexture.h"
|
||||||
#include "VideoCommon/RenderState.h"
|
#include "VideoCommon/RenderState.h"
|
||||||
#include "VideoCommon/TextureConfig.h"
|
#include "VideoCommon/TextureConfig.h"
|
||||||
|
#include "VideoCommon/VideoEvents.h"
|
||||||
|
|
||||||
class NativeVertexFormat;
|
class NativeVertexFormat;
|
||||||
class PointerWrap;
|
class PointerWrap;
|
||||||
|
@ -213,6 +214,8 @@ protected:
|
||||||
std::unique_ptr<AbstractPipeline> m_depth_poke_pipeline;
|
std::unique_ptr<AbstractPipeline> m_depth_poke_pipeline;
|
||||||
std::vector<EFBPokeVertex> m_color_poke_vertices;
|
std::vector<EFBPokeVertex> m_color_poke_vertices;
|
||||||
std::vector<EFBPokeVertex> m_depth_poke_vertices;
|
std::vector<EFBPokeVertex> m_depth_poke_vertices;
|
||||||
|
|
||||||
|
EventHook m_end_of_frame_event;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern std::unique_ptr<FramebufferManager> g_framebuffer_manager;
|
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->Load();
|
||||||
g_ActiveConfig.graphics_mod_config->SetChangeCount(old_game_mod_changes);
|
g_ActiveConfig.graphics_mod_config->SetChangeCount(old_game_mod_changes);
|
||||||
g_graphics_mod_manager->Load(*g_ActiveConfig.graphics_mod_config);
|
g_graphics_mod_manager->Load(*g_ActiveConfig.graphics_mod_config);
|
||||||
|
|
||||||
|
m_end_of_frame_event = AfterFrameEvent::Register([this] { EndOfFrame(); }, "ModManager");
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include "VideoCommon/GraphicsModSystem/Runtime/GraphicsModAction.h"
|
#include "VideoCommon/GraphicsModSystem/Runtime/GraphicsModAction.h"
|
||||||
#include "VideoCommon/TextureInfo.h"
|
#include "VideoCommon/TextureInfo.h"
|
||||||
#include "VideoCommon/XFMemory.h"
|
#include "VideoCommon/XFMemory.h"
|
||||||
|
#include "VideoCommon/VideoEvents.h"
|
||||||
|
|
||||||
class GraphicsModGroupConfig;
|
class GraphicsModGroupConfig;
|
||||||
class GraphicsModManager
|
class GraphicsModManager
|
||||||
|
@ -34,9 +35,8 @@ public:
|
||||||
|
|
||||||
void Load(const GraphicsModGroupConfig& config);
|
void Load(const GraphicsModGroupConfig& config);
|
||||||
|
|
||||||
void EndOfFrame();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void EndOfFrame();
|
||||||
void Reset();
|
void Reset();
|
||||||
|
|
||||||
class DecoratedAction;
|
class DecoratedAction;
|
||||||
|
@ -53,6 +53,8 @@ private:
|
||||||
std::unordered_map<FBInfo, std::vector<GraphicsModAction*>, FBInfoHasher> m_xfb_target_to_actions;
|
std::unordered_map<FBInfo, std::vector<GraphicsModAction*>, FBInfoHasher> m_xfb_target_to_actions;
|
||||||
|
|
||||||
std::unordered_set<std::string> m_groups;
|
std::unordered_set<std::string> m_groups;
|
||||||
|
|
||||||
|
EventHook m_end_of_frame_event;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern std::unique_ptr<GraphicsModManager> g_graphics_mod_manager;
|
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();
|
Present();
|
||||||
ProcessFrameDumping(ticks);
|
ProcessFrameDumping(ticks);
|
||||||
|
|
||||||
|
AfterPresentEvent::Trigger(present_info);
|
||||||
}
|
}
|
||||||
else
|
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.reason = PresentInfo::PresentReason::Immediate;
|
||||||
present_info.present_count = m_present_count++;
|
present_info.present_count = m_present_count++;
|
||||||
|
|
||||||
|
BeforePresentEvent::Trigger(present_info);
|
||||||
|
|
||||||
Present();
|
Present();
|
||||||
ProcessFrameDumping(ticks);
|
ProcessFrameDumping(ticks);
|
||||||
|
|
||||||
|
AfterPresentEvent::Trigger(present_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Presenter::ProcessFrameDumping(u64 ticks) const
|
void Presenter::ProcessFrameDumping(u64 ticks) const
|
||||||
|
|
|
@ -64,6 +64,10 @@ Renderer::Renderer()
|
||||||
{
|
{
|
||||||
UpdateActiveConfig();
|
UpdateActiveConfig();
|
||||||
CalculateTargetSize();
|
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;
|
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
|
unsigned int Renderer::GetEFBScale() const
|
||||||
{
|
{
|
||||||
return m_efb_scale;
|
return m_efb_scale;
|
||||||
|
@ -288,60 +283,39 @@ MathUtil::Rectangle<int> Renderer::ConvertEFBRectangle(const MathUtil::Rectangle
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::CheckFifoRecording()
|
void Renderer::UpdateWidescreen()
|
||||||
{
|
{
|
||||||
const bool was_recording = OpcodeDecoder::g_record_fifo_data;
|
if (SConfig::GetInstance().bWii)
|
||||||
OpcodeDecoder::g_record_fifo_data = FifoRecorder::GetInstance().IsRecording();
|
m_is_game_widescreen = Config::Get(Config::SYSCONF_WIDESCREEN);
|
||||||
|
|
||||||
if (!OpcodeDecoder::g_record_fifo_data)
|
// suggested_aspect_mode overrides SYSCONF_WIDESCREEN
|
||||||
return;
|
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.
|
// Heuristic to detect if a GameCube game is in 16:9 anamorphic widescreen mode.
|
||||||
void Renderer::UpdateWidescreenHeuristic()
|
void Renderer::UpdateWidescreenHeuristic()
|
||||||
{
|
{
|
||||||
// VertexManager maintains no statistics in Wii mode.
|
|
||||||
if (SConfig::GetInstance().bWii)
|
|
||||||
return;
|
|
||||||
|
|
||||||
const auto flush_statistics = g_vertex_manager->ResetFlushAspectRatioCount();
|
const auto flush_statistics = g_vertex_manager->ResetFlushAspectRatioCount();
|
||||||
|
|
||||||
// If suggested_aspect_mode (GameINI) is configured don't use heuristic.
|
// If suggested_aspect_mode (GameINI) is configured don't use heuristic.
|
||||||
if (g_ActiveConfig.suggested_aspect_mode != AspectMode::Auto)
|
if (g_ActiveConfig.suggested_aspect_mode != AspectMode::Auto)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
UpdateWidescreen();
|
||||||
|
|
||||||
// If widescreen hack isn't active and aspect_mode (UI) is 4:3 or 16:9 don't use heuristic.
|
// 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 ||
|
if (!g_ActiveConfig.bWidescreenHack && (g_ActiveConfig.aspect_mode == AspectMode::Analog ||
|
||||||
g_ActiveConfig.aspect_mode == AspectMode::AnalogWide))
|
g_ActiveConfig.aspect_mode == AspectMode::AnalogWide))
|
||||||
|
@ -382,109 +356,16 @@ void Renderer::UpdateWidescreenHeuristic()
|
||||||
m_was_orthographically_anamorphic = ortho_looks_anamorphic;
|
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)
|
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)
|
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
|
// Update our last xfb values
|
||||||
m_last_xfb_addr = xfb_addr;
|
m_last_xfb_addr = xfb_addr;
|
||||||
m_last_xfb_ticks = ticks;
|
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_stride = fb_stride;
|
||||||
m_last_xfb_height = fb_height;
|
m_last_xfb_height = fb_height;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
g_gfx->Flush();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Renderer::UseVertexDepthRange() const
|
bool Renderer::UseVertexDepthRange() const
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include "Common/Flag.h"
|
#include "Common/Flag.h"
|
||||||
#include "Common/MathUtil.h"
|
#include "Common/MathUtil.h"
|
||||||
#include "VideoCommon/RenderState.h"
|
#include "VideoCommon/RenderState.h"
|
||||||
|
#include "VideoCommon/VideoEvents.h"
|
||||||
|
|
||||||
class AbstractFramebuffer;
|
class AbstractFramebuffer;
|
||||||
class AbstractPipeline;
|
class AbstractPipeline;
|
||||||
|
@ -86,8 +87,6 @@ public:
|
||||||
void ClearScreen(const MathUtil::Rectangle<int>& rc, bool colorEnable, bool alphaEnable,
|
void ClearScreen(const MathUtil::Rectangle<int>& rc, bool colorEnable, bool alphaEnable,
|
||||||
bool zEnable, u32 color, u32 z);
|
bool zEnable, u32 color, u32 z);
|
||||||
virtual void ReinterpretPixelData(EFBReinterpretType convtype);
|
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 u32 AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data);
|
||||||
virtual void PokeEFB(EFBAccessType type, const EfbPokeData* points, size_t num_points);
|
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
|
// 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 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; }
|
bool IsGameWidescreen() const { return m_is_game_widescreen; }
|
||||||
|
|
||||||
PixelFormat GetPrevPixelFormat() const { return m_prev_efb_format; }
|
PixelFormat GetPrevPixelFormat() const { return m_prev_efb_format; }
|
||||||
|
@ -104,16 +102,17 @@ public:
|
||||||
bool UseVertexDepthRange() const;
|
bool UseVertexDepthRange() const;
|
||||||
void DoState(PointerWrap& p);
|
void DoState(PointerWrap& p);
|
||||||
|
|
||||||
// Will forcibly reload all textures on the next swap
|
|
||||||
void ForceReloadTextures();
|
|
||||||
|
|
||||||
bool CalculateTargetSize();
|
bool CalculateTargetSize();
|
||||||
|
|
||||||
protected:
|
int m_frame_count = 0;
|
||||||
std::tuple<int, int> CalculateTargetScale(int x, int y) const;
|
|
||||||
|
|
||||||
void CheckFifoRecording();
|
void OnConfigChanged(u32 bits);
|
||||||
void RecordVideoMemory();
|
|
||||||
|
protected:
|
||||||
|
void UpdateWidescreen();
|
||||||
|
void UpdateWidescreenHeuristic();
|
||||||
|
|
||||||
|
std::tuple<int, int> CalculateTargetScale(int x, int y) const;
|
||||||
|
|
||||||
bool m_is_game_widescreen = false;
|
bool m_is_game_widescreen = false;
|
||||||
bool m_was_orthographically_anamorphic = false;
|
bool m_was_orthographically_anamorphic = false;
|
||||||
|
@ -122,8 +121,6 @@ protected:
|
||||||
int m_target_width = 1;
|
int m_target_width = 1;
|
||||||
int m_target_height = 1;
|
int m_target_height = 1;
|
||||||
|
|
||||||
int m_frame_count = 0;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PixelFormat m_prev_efb_format;
|
PixelFormat m_prev_efb_format;
|
||||||
unsigned int m_efb_scale = 1;
|
unsigned int m_efb_scale = 1;
|
||||||
|
@ -134,7 +131,8 @@ private:
|
||||||
u32 m_last_xfb_stride = 0;
|
u32 m_last_xfb_stride = 0;
|
||||||
u32 m_last_xfb_height = 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;
|
extern std::unique_ptr<Renderer> g_renderer;
|
||||||
|
|
|
@ -46,6 +46,7 @@ bool ShaderCache::Initialize()
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
m_async_shader_compiler = g_gfx->CreateAsyncShaderCompiler();
|
m_async_shader_compiler = g_gfx->CreateAsyncShaderCompiler();
|
||||||
|
m_frame_end_handler = AfterFrameEvent::Register([this] { RetrieveAsyncShaders(); }, "RetreiveAsyncShaders");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#include "VideoCommon/UberShaderPixel.h"
|
#include "VideoCommon/UberShaderPixel.h"
|
||||||
#include "VideoCommon/UberShaderVertex.h"
|
#include "VideoCommon/UberShaderVertex.h"
|
||||||
#include "VideoCommon/VertexShaderGen.h"
|
#include "VideoCommon/VertexShaderGen.h"
|
||||||
|
#include "VideoCommon/VideoEvents.h"
|
||||||
|
|
||||||
class NativeVertexFormat;
|
class NativeVertexFormat;
|
||||||
enum class AbstractTextureFormat : u32;
|
enum class AbstractTextureFormat : u32;
|
||||||
|
@ -250,6 +251,8 @@ private:
|
||||||
|
|
||||||
// Texture decoding shaders
|
// Texture decoding shaders
|
||||||
std::map<std::pair<u32, u32>, std::unique_ptr<AbstractShader>> m_texture_decoding_shaders;
|
std::map<std::pair<u32, u32>, std::unique_ptr<AbstractShader>> m_texture_decoding_shaders;
|
||||||
|
|
||||||
|
EventHook m_frame_end_handler;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace VideoCommon
|
} // namespace VideoCommon
|
||||||
|
|
|
@ -8,11 +8,28 @@
|
||||||
|
|
||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
|
|
||||||
|
#include "Core/DolphinAnalytics.h"
|
||||||
|
#include "Core/HW/SystemTimers.h"
|
||||||
|
|
||||||
#include "VideoCommon/BPFunctions.h"
|
#include "VideoCommon/BPFunctions.h"
|
||||||
#include "VideoCommon/VideoCommon.h"
|
#include "VideoCommon/VideoCommon.h"
|
||||||
#include "VideoCommon/VideoConfig.h"
|
#include "VideoCommon/VideoConfig.h"
|
||||||
|
#include "VideoCommon/VideoEvents.h"
|
||||||
|
|
||||||
Statistics g_stats;
|
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;
|
static bool clear_scissors;
|
||||||
|
|
||||||
void Statistics::ResetFrame()
|
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)
|
void TCacheEntry::DoState(PointerWrap& p)
|
||||||
{
|
{
|
||||||
p.Do(addr);
|
p.Do(addr);
|
||||||
|
|
|
@ -18,12 +18,15 @@
|
||||||
|
|
||||||
#include "Common/BitSet.h"
|
#include "Common/BitSet.h"
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
#include "Common/Flag.h"
|
||||||
#include "Common/MathUtil.h"
|
#include "Common/MathUtil.h"
|
||||||
|
|
||||||
#include "VideoCommon/AbstractTexture.h"
|
#include "VideoCommon/AbstractTexture.h"
|
||||||
#include "VideoCommon/BPMemory.h"
|
#include "VideoCommon/BPMemory.h"
|
||||||
#include "VideoCommon/TextureConfig.h"
|
#include "VideoCommon/TextureConfig.h"
|
||||||
#include "VideoCommon/TextureDecoder.h"
|
#include "VideoCommon/TextureDecoder.h"
|
||||||
#include "VideoCommon/TextureInfo.h"
|
#include "VideoCommon/TextureInfo.h"
|
||||||
|
#include "VideoCommon/VideoEvents.h"
|
||||||
|
|
||||||
class AbstractFramebuffer;
|
class AbstractFramebuffer;
|
||||||
class AbstractStagingTexture;
|
class AbstractStagingTexture;
|
||||||
|
@ -288,6 +291,9 @@ public:
|
||||||
static bool AllCopyFilterCoefsNeeded(const std::array<u32, 3>& coefficients);
|
static bool AllCopyFilterCoefsNeeded(const std::array<u32, 3>& coefficients);
|
||||||
static bool CopyFilterCanOverflow(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:
|
protected:
|
||||||
// Decodes the specified data to the GPU texture specified by entry.
|
// Decodes the specified data to the GPU texture specified by entry.
|
||||||
// Returns false if the configuration is not supported.
|
// 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
|
// 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.
|
// readbacks, saving the overhead of allocating a new buffer every time.
|
||||||
std::unique_ptr<AbstractStagingTexture> m_readback_texture;
|
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;
|
extern std::unique_ptr<TextureCacheBase> g_texture_cache;
|
||||||
|
|
|
@ -105,6 +105,7 @@ VertexManagerBase::~VertexManagerBase() = default;
|
||||||
|
|
||||||
bool VertexManagerBase::Initialize()
|
bool VertexManagerBase::Initialize()
|
||||||
{
|
{
|
||||||
|
m_frame_end_event = AfterFrameEvent::Register([this] { OnEndFrame();}, "VertexManagerBase");
|
||||||
m_index_generator.Init();
|
m_index_generator.Init();
|
||||||
m_cpu_cull.Init();
|
m_cpu_cull.Init();
|
||||||
return true;
|
return true;
|
||||||
|
@ -996,4 +997,10 @@ void VertexManagerBase::OnEndFrame()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
m_cpu_accesses_this_frame.clear();
|
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_cpu_accesses_this_frame;
|
||||||
std::vector<u32> m_scheduled_command_buffer_kicks;
|
std::vector<u32> m_scheduled_command_buffer_kicks;
|
||||||
bool m_allow_background_execution = true;
|
bool m_allow_background_execution = true;
|
||||||
|
|
||||||
|
EventHook m_frame_end_event;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern std::unique_ptr<VertexManagerBase> g_vertex_manager;
|
extern std::unique_ptr<VertexManagerBase> g_vertex_manager;
|
||||||
|
|
|
@ -341,3 +341,8 @@ void CheckForConfigChanges()
|
||||||
BPFunctions::SetScissorAndViewport();
|
BPFunctions::SetScissorAndViewport();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static EventHook s_check_config_event = AfterFrameEvent::Register([] {
|
||||||
|
CheckForConfigChanges();
|
||||||
|
|
||||||
|
}, "CheckForConfigChanges");
|
||||||
|
|
Loading…
Reference in New Issue