Rewrite host GPU abstraction

- Don't have to repeat the same thing for 4 renderers.
 - Add native Metal renderer.
This commit is contained in:
Stenzek
2023-08-13 13:42:02 +10:00
parent bfa792ddbf
commit e3d9ba4c99
249 changed files with 28851 additions and 32222 deletions

View File

@ -8,13 +8,6 @@
#include "bus.h"
#include "cdrom.h"
#include "cheats.h"
#include "common/error.h"
#include "common/file_system.h"
#include "common/log.h"
#include "common/make_array.h"
#include "common/path.h"
#include "common/string_util.h"
#include "common/threading.h"
#include "controller.h"
#include "cpu_code_cache.h"
#include "cpu_core.h"
@ -40,13 +33,24 @@
#include "spu.h"
#include "texture_replacements.h"
#include "timers.h"
#include "util/audio_stream.h"
#include "util/cd_image.h"
#include "util/host_display.h"
#include "util/gpu_device.h"
#include "util/ini_settings_interface.h"
#include "util/iso_reader.h"
#include "util/state_wrapper.h"
#include "common/error.h"
#include "common/file_system.h"
#include "common/log.h"
#include "common/make_array.h"
#include "common/path.h"
#include "common/string_util.h"
#include "common/threading.h"
#include "xxhash.h"
#include <cctype>
#include <cinttypes>
#include <cmath>
@ -55,6 +59,7 @@
#include <fstream>
#include <limits>
#include <thread>
Log_SetChannel(System);
#ifdef _WIN32
@ -70,7 +75,9 @@ SystemBootParameters::SystemBootParameters(const SystemBootParameters&) = defaul
SystemBootParameters::SystemBootParameters(SystemBootParameters&& other) = default;
SystemBootParameters::SystemBootParameters(std::string filename_) : filename(std::move(filename_)) {}
SystemBootParameters::SystemBootParameters(std::string filename_) : filename(std::move(filename_))
{
}
SystemBootParameters::~SystemBootParameters() = default;
@ -135,6 +142,7 @@ static std::string s_input_profile_name;
static System::State s_state = System::State::Shutdown;
static std::atomic_bool s_startup_cancelled{false};
static bool s_keep_gpu_device_on_shutdown = false;
static ConsoleRegion s_region = ConsoleRegion::NTSC_U;
TickCount System::g_ticks_per_second = System::MASTER_CLOCK;
@ -799,12 +807,10 @@ bool System::RecreateGPU(GPURenderer renderer, bool force_recreate_display, bool
if (!state_valid)
Log_ErrorPrintf("Failed to save old GPU state when switching renderers");
g_gpu->ResetGraphicsAPIState();
// create new renderer
g_gpu.reset();
if (force_recreate_display)
Host::ReleaseHostDisplay();
Host::ReleaseGPUDevice();
if (!CreateGPU(renderer))
{
@ -822,7 +828,6 @@ bool System::RecreateGPU(GPURenderer renderer, bool force_recreate_display, bool
g_gpu->RestoreGraphicsAPIState();
g_gpu->DoState(sw, nullptr, update_display);
TimingEvents::DoState(sw);
g_gpu->ResetGraphicsAPIState();
}
// fix up vsync etc
@ -1062,6 +1067,7 @@ bool System::LoadState(const char* filename)
ResetPerformanceCounters();
ResetThrottler();
Host::RenderDisplay(false);
g_gpu->RestoreGraphicsAPIState();
Log_VerbosePrintf("Loading state took %.2f msec", load_timer.GetTimeMilliseconds());
return true;
}
@ -1135,6 +1141,7 @@ bool System::BootSystem(SystemBootParameters parameters)
Assert(s_state == State::Shutdown);
s_state = State::Starting;
s_startup_cancelled.store(false);
s_keep_gpu_device_on_shutdown = static_cast<bool>(g_gpu_device);
s_region = g_settings.region;
Host::OnSystemStarting();
@ -1437,7 +1444,11 @@ bool System::Initialize(bool force_software_renderer)
if (IsStartupCancelled())
{
g_gpu.reset();
Host::ReleaseHostDisplay();
if (!s_keep_gpu_device_on_shutdown)
{
Host::ReleaseGPUDevice();
Host::ReleaseRenderWindow();
}
if (g_settings.gpu_pgxp_enable)
PGXP::Shutdown();
CPU::Shutdown();
@ -1519,8 +1530,6 @@ void System::DestroySystem()
Timers::Shutdown();
Pad::Shutdown();
CDROM::Shutdown();
if (g_gpu)
g_gpu->ResetGraphicsAPIState();
g_gpu.reset();
InterruptController::Shutdown();
DMA::Shutdown();
@ -1532,11 +1541,15 @@ void System::DestroySystem()
ClearRunningGame();
// Restore present-all-frames behavior.
if (g_host_display)
if (s_keep_gpu_device_on_shutdown && g_gpu_device)
{
g_host_display->SetDisplayMaxFPS(0.0f);
g_gpu_device->SetDisplayMaxFPS(0.0f);
UpdateSoftwareCursor();
Host::ReleaseHostDisplay();
}
else
{
Host::ReleaseGPUDevice();
Host::ReleaseRenderWindow();
}
s_bios_hash = {};
@ -1601,8 +1614,6 @@ void System::Execute()
else
CPU::Execute();
g_gpu->ResetGraphicsAPIState();
s_system_executing = false;
continue;
}
@ -1624,6 +1635,9 @@ void System::FrameDone()
{
s_frame_number++;
// Vertex buffer is shared, need to flush what we have.
g_gpu->FlushRender();
// Generate any pending samples from the SPU before sleeping, this way we reduce the chances of underruns.
SPU::GeneratePendingSamples();
@ -1680,14 +1694,11 @@ void System::FrameDone()
{
s_last_frame_skipped = false;
// TODO: Purge reset/restore
g_gpu->ResetGraphicsAPIState();
const bool skip_present = g_host_display->ShouldSkipDisplayingFrame();
const bool skip_present = g_gpu_device->ShouldSkipDisplayingFrame();
Host::RenderDisplay(skip_present);
if (!skip_present && g_host_display->IsGPUTimingEnabled())
if (!skip_present && g_gpu_device->IsGPUTimingEnabled())
{
s_accumulated_gpu_time += g_host_display->GetAndResetAccumulatedGPUTime();
s_accumulated_gpu_time += g_gpu_device->GetAndResetAccumulatedGPUTime();
s_presents_since_last_update++;
}
@ -1784,10 +1795,9 @@ void System::SingleStepCPU()
CPU::SingleStep();
g_gpu->FlushRender();
SPU::GeneratePendingSamples();
g_gpu->ResetGraphicsAPIState();
s_system_executing = false;
}
@ -1834,35 +1844,29 @@ void System::RecreateSystem()
bool System::CreateGPU(GPURenderer renderer)
{
switch (renderer)
const RenderAPI api = Settings::GetRenderAPIForRenderer(renderer);
if (!g_gpu_device || (renderer != GPURenderer::Software && g_gpu_device->GetRenderAPI() != api))
{
#ifdef WITH_OPENGL
case GPURenderer::HardwareOpenGL:
g_gpu = GPU::CreateHardwareOpenGLRenderer();
break;
#endif
if (g_gpu_device)
{
Log_WarningPrintf("Recreating GPU device, expecting %s got %s", GPUDevice::RenderAPIToString(api),
GPUDevice::RenderAPIToString(g_gpu_device->GetRenderAPI()));
}
#ifdef WITH_VULKAN
case GPURenderer::HardwareVulkan:
g_gpu = GPU::CreateHardwareVulkanRenderer();
break;
#endif
#ifdef _WIN32
case GPURenderer::HardwareD3D11:
g_gpu = GPU::CreateHardwareD3D11Renderer();
break;
case GPURenderer::HardwareD3D12:
g_gpu = GPU::CreateHardwareD3D12Renderer();
break;
#endif
case GPURenderer::Software:
default:
g_gpu = GPU::CreateSoftwareRenderer();
break;
Host::ReleaseGPUDevice();
if (!Host::CreateGPUDevice(api))
{
Host::ReleaseRenderWindow();
return false;
}
}
if (renderer == GPURenderer::Software)
g_gpu = GPU::CreateSoftwareRenderer();
else
g_gpu = GPU::CreateHardwareRenderer();
if (!g_gpu)
{
Log_ErrorPrintf("Failed to initialize %s renderer, falling back to software renderer",
@ -1875,6 +1879,11 @@ bool System::CreateGPU(GPURenderer renderer)
if (!g_gpu)
{
Log_ErrorPrintf("Failed to create fallback software renderer.");
if (!s_keep_gpu_device_on_shutdown)
{
Host::ReleaseGPUDevice();
Host::ReleaseRenderWindow();
}
return false;
}
}
@ -1934,9 +1943,7 @@ bool System::DoState(StateWrapper& sw, GPUTexture** host_texture, bool update_di
return false;
g_gpu->RestoreGraphicsAPIState();
const bool gpu_result = sw.DoMarker("GPU") && g_gpu->DoState(sw, host_texture, update_display);
g_gpu->ResetGraphicsAPIState();
if (!gpu_result)
if (!sw.DoMarker("GPU") || !g_gpu->DoState(sw, host_texture, update_display))
return false;
if (!sw.DoMarker("CDROM") || !CDROM::DoState(sw))
@ -2071,8 +2078,6 @@ void System::InternalReset()
#ifdef WITH_CHEEVOS
Achievements::ResetRuntime();
#endif
g_gpu->ResetGraphicsAPIState();
}
std::string System::GetMediaPathFromSaveState(const char* path)
@ -2283,7 +2288,7 @@ bool System::InternalSaveState(ByteStream* state, u32 screenshot_size /* = 256 *
if (screenshot_size > 0)
{
// assume this size is the width
const float display_aspect_ratio = g_host_display->GetDisplayAspectRatio();
const float display_aspect_ratio = g_gpu_device->GetDisplayAspectRatio();
const u32 screenshot_width = screenshot_size;
const u32 screenshot_height =
std::max(1u, static_cast<u32>(static_cast<float>(screenshot_width) /
@ -2293,7 +2298,7 @@ bool System::InternalSaveState(ByteStream* state, u32 screenshot_size /* = 256 *
std::vector<u32> screenshot_buffer;
u32 screenshot_stride;
GPUTexture::Format screenshot_format;
if (g_host_display->RenderScreenshot(screenshot_width, screenshot_height,
if (g_gpu_device->RenderScreenshot(screenshot_width, screenshot_height,
Common::Rectangle<s32>::FromExtents(0, 0, screenshot_width, screenshot_height),
&screenshot_buffer, &screenshot_stride, &screenshot_format) &&
GPUTexture::ConvertTextureDataToRGBA8(screenshot_width, screenshot_height, screenshot_buffer, screenshot_stride,
@ -2306,7 +2311,7 @@ bool System::InternalSaveState(ByteStream* state, u32 screenshot_size /* = 256 *
}
else
{
if (g_host_display->UsesLowerLeftOrigin())
if (g_gpu_device->UsesLowerLeftOrigin())
{
GPUTexture::FlipTextureDataRGBA8(screenshot_width, screenshot_height, screenshot_buffer, screenshot_stride);
}
@ -2350,8 +2355,6 @@ bool System::InternalSaveState(ByteStream* state, u32 screenshot_size /* = 256 *
header.data_compressed_size = static_cast<u32>(state->GetPosition() - header.offset_to_data);
}
g_gpu->ResetGraphicsAPIState();
if (!result)
return false;
}
@ -2427,7 +2430,7 @@ void System::UpdatePerformanceCounters()
s_fps_timer.ResetTo(now_ticks);
if (g_host_display->IsGPUTimingEnabled())
if (g_gpu_device->IsGPUTimingEnabled())
{
s_average_gpu_time = s_accumulated_gpu_time / static_cast<float>(std::max(s_presents_since_last_update, 1u));
s_gpu_usage = s_accumulated_gpu_time / (time * 10.0f);
@ -2474,7 +2477,7 @@ void System::UpdateSpeedLimiterState()
s_target_speed == 1.0f && IsValid())
{
float host_refresh_rate;
if (g_host_display->GetHostRefreshRate(&host_refresh_rate))
if (g_gpu_device->GetHostRefreshRate(&host_refresh_rate))
{
const float ratio = host_refresh_rate / System::GetThrottleFrequency();
s_syncing_to_host = (ratio >= 0.95f && ratio <= 1.05f);
@ -2530,8 +2533,8 @@ void System::UpdateDisplaySync()
Log_VerbosePrintf("Max display fps: %f (%s)", max_display_fps,
s_display_all_frames ? "displaying all frames" : "skipping displaying frames when needed");
g_host_display->SetDisplayMaxFPS(max_display_fps);
g_host_display->SetVSync(video_sync_enabled);
g_gpu_device->SetDisplayMaxFPS(max_display_fps);
g_gpu_device->SetVSync(video_sync_enabled);
}
bool System::ShouldUseVSync()
@ -3038,10 +3041,7 @@ bool System::DumpVRAM(const char* filename)
return false;
g_gpu->RestoreGraphicsAPIState();
const bool result = g_gpu->DumpVRAMToFile(filename);
g_gpu->ResetGraphicsAPIState();
return result;
return g_gpu->DumpVRAMToFile(filename);
}
bool System::DumpSPURAM(const char* filename)
@ -3492,12 +3492,12 @@ void System::CheckForSettingsChanges(const Settings& old_settings)
{
if (g_settings.display_post_processing && !g_settings.display_post_process_chain.empty())
{
if (!g_host_display->SetPostProcessingChain(g_settings.display_post_process_chain))
if (!g_gpu_device->SetPostProcessingChain(g_settings.display_post_process_chain))
Host::AddOSDMessage(TRANSLATE_STR("OSDMessage", "Failed to load post processing shader chain."), 20.0f);
}
else
{
g_host_display->SetPostProcessingChain({});
g_gpu_device->SetPostProcessingChain({});
}
}
}
@ -3708,8 +3708,6 @@ void System::DoRewind()
s_next_frame_time += s_frame_period;
// TODO: Purge reset/restore
g_gpu->ResetGraphicsAPIState();
Host::RenderDisplay(false);
g_gpu->RestoreGraphicsAPIState();
@ -3989,7 +3987,7 @@ bool System::SaveScreenshot(const char* filename /* = nullptr */, bool full_reso
return false;
}
const bool screenshot_saved = g_host_display->WriteScreenshotToFile(
const bool screenshot_saved = g_gpu_device->WriteScreenshotToFile(
filename, g_settings.display_internal_resolution_screenshots, compress_on_thread);
if (!screenshot_saved)
@ -4340,13 +4338,13 @@ void System::TogglePostProcessing()
{
Host::AddKeyedOSDMessage("PostProcessing", TRANSLATE_STR("OSDMessage", "Post-processing is now enabled."), 10.0f);
if (!g_host_display->SetPostProcessingChain(g_settings.display_post_process_chain))
if (!g_gpu_device->SetPostProcessingChain(g_settings.display_post_process_chain))
Host::AddOSDMessage(TRANSLATE_STR("OSDMessage", "Failed to load post processing shader chain."), 20.0f);
}
else
{
Host::AddKeyedOSDMessage("PostProcessing", TRANSLATE_STR("OSDMessage", "Post-processing is now disabled."), 10.0f);
g_host_display->SetPostProcessingChain({});
g_gpu_device->SetPostProcessingChain({});
}
}
@ -4355,7 +4353,7 @@ void System::ReloadPostProcessingShaders()
if (!IsValid() || !g_settings.display_post_processing)
return;
if (!g_host_display->SetPostProcessingChain(g_settings.display_post_process_chain))
if (!g_gpu_device->SetPostProcessingChain(g_settings.display_post_process_chain))
Host::AddOSDMessage(TRANSLATE_STR("OSDMessage", "Failed to load post-processing shader chain."), 20.0f);
else
Host::AddOSDMessage(TRANSLATE_STR("OSDMessage", "Post-processing shaders reloaded."), 10.0f);
@ -4421,7 +4419,7 @@ void System::UpdateSoftwareCursor()
if (!IsValid())
{
Host::SetMouseMode(false, false);
g_host_display->ClearSoftwareCursor();
g_gpu_device->ClearSoftwareCursor();
return;
}
@ -4444,12 +4442,12 @@ void System::UpdateSoftwareCursor()
if (image && image->IsValid())
{
g_host_display->SetSoftwareCursor(image->GetPixels(), image->GetWidth(), image->GetHeight(), image->GetPitch(),
g_gpu_device->SetSoftwareCursor(image->GetPixels(), image->GetWidth(), image->GetHeight(), image->GetPitch(),
image_scale);
}
else
{
g_host_display->ClearSoftwareCursor();
g_gpu_device->ClearSoftwareCursor();
}
}
@ -4462,13 +4460,13 @@ void System::RequestDisplaySize(float scale /*= 0.0f*/)
scale = g_gpu->IsHardwareRenderer() ? static_cast<float>(g_settings.gpu_resolution_scale) : 1.0f;
const float y_scale =
(static_cast<float>(g_host_display->GetDisplayWidth()) / static_cast<float>(g_host_display->GetDisplayHeight())) /
g_host_display->GetDisplayAspectRatio();
(static_cast<float>(g_gpu_device->GetDisplayWidth()) / static_cast<float>(g_gpu_device->GetDisplayHeight())) /
g_gpu_device->GetDisplayAspectRatio();
const u32 requested_width =
std::max<u32>(static_cast<u32>(std::ceil(static_cast<float>(g_host_display->GetDisplayWidth()) * scale)), 1);
std::max<u32>(static_cast<u32>(std::ceil(static_cast<float>(g_gpu_device->GetDisplayWidth()) * scale)), 1);
const u32 requested_height = std::max<u32>(
static_cast<u32>(std::ceil(static_cast<float>(g_host_display->GetDisplayHeight()) * y_scale * scale)), 1);
static_cast<u32>(std::ceil(static_cast<float>(g_gpu_device->GetDisplayHeight()) * y_scale * scale)), 1);
Host::RequestResizeHostDisplay(static_cast<s32>(requested_width), static_cast<s32>(requested_height));
}