Skip to content

Commit

Permalink
GPUDevice: Extract swap chain to separate class
Browse files Browse the repository at this point in the history
  • Loading branch information
stenzek committed Oct 18, 2024
1 parent c6055af commit eb46142
Show file tree
Hide file tree
Showing 71 changed files with 2,525 additions and 2,275 deletions.
7 changes: 4 additions & 3 deletions src/core/fullscreen_ui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4341,10 +4341,11 @@ void FullscreenUI::DrawDisplaySettingsPage()
options.emplace_back(FSUI_STR("Borderless Fullscreen"), strvalue.has_value() && strvalue->empty());
if (selected_adapter)
{
for (const std::string& mode : selected_adapter->fullscreen_modes)
for (const GPUDevice::ExclusiveFullscreenMode& mode : selected_adapter->fullscreen_modes)
{
const bool checked = (strvalue.has_value() && strvalue.value() == mode);
options.emplace_back(mode, checked);
const TinyString mode_str = mode.ToString();
const bool checked = (strvalue.has_value() && strvalue.value() == mode_str);
options.emplace_back(std::string(mode_str.view()), checked);
}
}

Expand Down
49 changes: 33 additions & 16 deletions src/core/gpu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1145,8 +1145,16 @@ void GPU::UpdateCommandTickEvent()
void GPU::ConvertScreenCoordinatesToDisplayCoordinates(float window_x, float window_y, float* display_x,
float* display_y) const
{
if (!g_gpu_device->HasMainSwapChain()) [[unlikely]]
{
*display_x = 0.0f;
*display_y = 0.0f;
return;
}

GSVector4i display_rc, draw_rc;
CalculateDrawRect(g_gpu_device->GetWindowWidth(), g_gpu_device->GetWindowHeight(), true, true, &display_rc, &draw_rc);
CalculateDrawRect(g_gpu_device->GetMainSwapChain()->GetWidth(), g_gpu_device->GetMainSwapChain()->GetHeight(), true,
true, &display_rc, &draw_rc);

// convert coordinates to active display region, then to full display region
const float scaled_display_x =
Expand Down Expand Up @@ -1644,7 +1652,8 @@ bool GPU::CompileDisplayPipelines(bool display, bool deinterlace, bool chroma_sm
if (display)
{
plconfig.layout = GPUPipeline::Layout::SingleTextureAndPushConstants;
plconfig.SetTargetFormats(g_gpu_device->HasSurface() ? g_gpu_device->GetWindowFormat() : GPUTexture::Format::RGBA8);
plconfig.SetTargetFormats(g_gpu_device->HasMainSwapChain() ? g_gpu_device->GetMainSwapChain()->GetFormat() :
GPUTexture::Format::RGBA8);

std::string vs = shadergen.GenerateDisplayVertexShader();
std::string fs;
Expand Down Expand Up @@ -1839,10 +1848,13 @@ GPUDevice::PresentResult GPU::PresentDisplay()
{
FlushRender();

if (!g_gpu_device->HasMainSwapChain())
return GPUDevice::PresentResult::SkipPresent;

GSVector4i display_rect;
GSVector4i draw_rect;
CalculateDrawRect(g_gpu_device->GetWindowWidth(), g_gpu_device->GetWindowHeight(), !g_settings.debugging.show_vram,
true, &display_rect, &draw_rect);
CalculateDrawRect(g_gpu_device->GetMainSwapChain()->GetWidth(), g_gpu_device->GetMainSwapChain()->GetHeight(),
!g_settings.debugging.show_vram, true, &display_rect, &draw_rect);
return RenderDisplay(nullptr, display_rect, draw_rect, !g_settings.debugging.show_vram);
}

Expand Down Expand Up @@ -1887,13 +1899,12 @@ GPUDevice::PresentResult GPU::RenderDisplay(GPUTexture* target, const GSVector4i
}
}

const GPUTexture::Format hdformat = target ? target->GetFormat() : g_gpu_device->GetWindowFormat();
const u32 target_width = target ? target->GetWidth() : g_gpu_device->GetWindowWidth();
const u32 target_height = target ? target->GetHeight() : g_gpu_device->GetWindowHeight();
const bool really_postfx =
(postfx && PostProcessing::DisplayChain.IsActive() && !g_gpu_device->GetWindowInfo().IsSurfaceless() &&
hdformat != GPUTexture::Format::Unknown && target_width > 0 && target_height > 0 &&
PostProcessing::DisplayChain.CheckTargets(hdformat, target_width, target_height));
const GPUTexture::Format hdformat = target ? target->GetFormat() : g_gpu_device->GetMainSwapChain()->GetFormat();
const u32 target_width = target ? target->GetWidth() : g_gpu_device->GetMainSwapChain()->GetWidth();
const u32 target_height = target ? target->GetHeight() : g_gpu_device->GetMainSwapChain()->GetHeight();
const bool really_postfx = (postfx && PostProcessing::DisplayChain.IsActive() && g_gpu_device->HasMainSwapChain() &&
hdformat != GPUTexture::Format::Unknown && target_width > 0 && target_height > 0 &&
PostProcessing::DisplayChain.CheckTargets(hdformat, target_width, target_height));
const GSVector4i real_draw_rect =
g_gpu_device->UsesLowerLeftOrigin() ? GPUDevice::FlipToLowerLeft(draw_rect, target_height) : draw_rect;
if (really_postfx)
Expand All @@ -1904,9 +1915,15 @@ GPUDevice::PresentResult GPU::RenderDisplay(GPUTexture* target, const GSVector4i
else
{
if (target)
{
g_gpu_device->SetRenderTarget(target);
else if (const GPUDevice::PresentResult pres = g_gpu_device->BeginPresent(); pres != GPUDevice::PresentResult::OK)
return pres;
}
else
{
const GPUDevice::PresentResult pres = g_gpu_device->BeginPresent(g_gpu_device->GetMainSwapChain());
if (pres != GPUDevice::PresentResult::OK)
return pres;
}
}

if (display_texture)
Expand Down Expand Up @@ -2559,7 +2576,7 @@ bool GPU::RenderScreenshotToBuffer(u32 width, u32 height, const GSVector4i displ
GPUTexture::Format* out_format)
{
const GPUTexture::Format hdformat =
g_gpu_device->HasSurface() ? g_gpu_device->GetWindowFormat() : GPUTexture::Format::RGBA8;
g_gpu_device->HasMainSwapChain() ? g_gpu_device->GetMainSwapChain()->GetFormat() : GPUTexture::Format::RGBA8;

auto render_texture =
g_gpu_device->FetchAutoRecycleTexture(width, height, 1, 1, 1, GPUTexture::Type::RenderTarget, hdformat);
Expand Down Expand Up @@ -2605,8 +2622,8 @@ bool GPU::RenderScreenshotToBuffer(u32 width, u32 height, const GSVector4i displ
void GPU::CalculateScreenshotSize(DisplayScreenshotMode mode, u32* width, u32* height, GSVector4i* display_rect,
GSVector4i* draw_rect) const
{
*width = g_gpu_device->GetWindowWidth();
*height = g_gpu_device->GetWindowHeight();
*width = g_gpu_device->HasMainSwapChain() ? g_gpu_device->GetMainSwapChain()->GetWidth() : 1;
*height = g_gpu_device->HasMainSwapChain() ? g_gpu_device->GetMainSwapChain()->GetHeight() : 1;
CalculateDrawRect(*width, *height, true, !g_settings.debugging.show_vram, display_rect, draw_rect);

const bool internal_resolution = (mode != DisplayScreenshotMode::ScreenResolution || g_settings.debugging.show_vram);
Expand Down
8 changes: 4 additions & 4 deletions src/core/gpu_hw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -525,7 +525,7 @@ void GPU_HW::UpdateSettings(const Settings& old_settings)
// When using very high upscaling, it's possible that we don't have enough VRAM for two sets of buffers.
// Purge the pool, and idle the GPU so that all video memory is freed prior to creating the new buffers.
g_gpu_device->PurgeTexturePool();
g_gpu_device->ExecuteAndWaitForGPUIdle();
g_gpu_device->WaitForGPUIdle();

if (!CreateBuffers())
Panic("Failed to recreate buffers.");
Expand Down Expand Up @@ -680,7 +680,7 @@ u32 GPU_HW::CalculateResolutionScale() const
{
// Auto scaling.
if (m_crtc_state.display_width == 0 || m_crtc_state.display_height == 0 || m_crtc_state.display_vram_width == 0 ||
m_crtc_state.display_vram_height == 0 || m_GPUSTAT.display_disable)
m_crtc_state.display_vram_height == 0 || m_GPUSTAT.display_disable || !g_gpu_device->HasMainSwapChain())
{
// When the system is starting and all borders crop is enabled, the registers are zero, and
// display_height therefore is also zero. Keep the existing resolution until it updates.
Expand All @@ -689,8 +689,8 @@ u32 GPU_HW::CalculateResolutionScale() const
else
{
GSVector4i display_rect, draw_rect;
CalculateDrawRect(g_gpu_device->GetWindowWidth(), g_gpu_device->GetWindowHeight(), true, true, &display_rect,
&draw_rect);
CalculateDrawRect(g_gpu_device->GetMainSwapChain()->GetWidth(), g_gpu_device->GetMainSwapChain()->GetHeight(),
true, true, &display_rect, &draw_rect);

// We use the draw rect to determine scaling. This way we match the resolution as best we can, regardless of the
// anamorphic aspect ratio.
Expand Down
6 changes: 3 additions & 3 deletions src/core/gte.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -243,14 +243,14 @@ void GTE::UpdateAspectRatio()
{
case DisplayAspectRatio::MatchWindow:
{
if (!g_gpu_device)
if (!g_gpu_device || !g_gpu_device->HasMainSwapChain())
{
s_config.aspect_ratio = DisplayAspectRatio::R4_3;
return;
}

num = g_gpu_device->GetWindowWidth();
denom = g_gpu_device->GetWindowHeight();
num = g_gpu_device->GetMainSwapChain()->GetWidth();
denom = g_gpu_device->GetMainSwapChain()->GetHeight();
}
break;

Expand Down
87 changes: 69 additions & 18 deletions src/core/host.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -274,13 +274,19 @@ std::string Host::GetHTTPUserAgent()
return fmt::format("DuckStation for {} ({}) {}", TARGET_OS_STR, CPU_ARCH_STR, g_scm_tag_str);
}

bool Host::CreateGPUDevice(RenderAPI api, Error* error)
bool Host::CreateGPUDevice(RenderAPI api, bool fullscreen, Error* error)
{
DebugAssert(!g_gpu_device);

INFO_LOG("Trying to create a {} GPU device...", GPUDevice::RenderAPIToString(api));
g_gpu_device = GPUDevice::CreateDeviceForAPI(api);

std::optional<GPUDevice::ExclusiveFullscreenMode> fullscreen_mode;
if (fullscreen && g_gpu_device && g_gpu_device->SupportsExclusiveFullscreen())
{
fullscreen_mode =
GPUDevice::ExclusiveFullscreenMode::Parse(Host::GetTinyStringSettingValue("GPU", "FullscreenMode", ""));
}
std::optional<bool> exclusive_fullscreen_control;
if (g_settings.display_exclusive_fullscreen_control != DisplayExclusiveFullscreenControl::Automatic)
{
Expand All @@ -300,18 +306,30 @@ bool Host::CreateGPUDevice(RenderAPI api, Error* error)
if (g_settings.gpu_disable_raster_order_views)
disabled_features |= GPUDevice::FEATURE_MASK_RASTER_ORDER_VIEWS;

// Don't dump shaders on debug builds for Android, users will complain about storage...
#if !defined(__ANDROID__) || defined(_DEBUG)
const std::string_view shader_dump_directory(EmuFolders::DataRoot);
#else
const std::string_view shader_dump_directory;
#endif

Error create_error;
if (!g_gpu_device || !g_gpu_device->Create(
g_settings.gpu_adapter,
g_settings.gpu_disable_shader_cache ? std::string_view() : std::string_view(EmuFolders::Cache),
SHADER_CACHE_VERSION, g_settings.gpu_use_debug_device, System::GetEffectiveVSyncMode(),
System::ShouldAllowPresentThrottle(), exclusive_fullscreen_control,
static_cast<GPUDevice::FeatureMask>(disabled_features), &create_error))
std::optional<WindowInfo> wi;
if (!g_gpu_device ||
!(wi = Host::AcquireRenderWindow(api, fullscreen, fullscreen_mode.has_value(), &create_error)).has_value() ||
!g_gpu_device->Create(
g_settings.gpu_adapter, static_cast<GPUDevice::FeatureMask>(disabled_features), shader_dump_directory,
g_settings.gpu_disable_shader_cache ? std::string_view() : std::string_view(EmuFolders::Cache),
SHADER_CACHE_VERSION, g_settings.gpu_use_debug_device, wi.value(), System::GetEffectiveVSyncMode(),
System::ShouldAllowPresentThrottle(), fullscreen_mode.has_value() ? &fullscreen_mode.value() : nullptr,
exclusive_fullscreen_control, &create_error))
{
ERROR_LOG("Failed to create GPU device: {}", create_error.GetDescription());
if (g_gpu_device)
g_gpu_device->Destroy();
g_gpu_device.reset();
if (wi.has_value())
Host::ReleaseRenderWindow();

Error::SetStringFmt(
error,
Expand All @@ -327,27 +345,52 @@ bool Host::CreateGPUDevice(RenderAPI api, Error* error)
Error::SetStringFmt(error, "Failed to initialize ImGuiManager: {}", create_error.GetDescription());
g_gpu_device->Destroy();
g_gpu_device.reset();
Host::ReleaseRenderWindow();
return false;
}

InputManager::SetDisplayWindowSize(static_cast<float>(g_gpu_device->GetWindowWidth()),
static_cast<float>(g_gpu_device->GetWindowHeight()));
InputManager::SetDisplayWindowSize(ImGuiManager::GetWindowWidth(), ImGuiManager::GetWindowHeight());
return true;
}

void Host::UpdateDisplayWindow()
void Host::UpdateDisplayWindow(bool fullscreen)
{
if (!g_gpu_device)
return;

if (!g_gpu_device->UpdateWindow())
const GPUVSyncMode vsync_mode =
g_gpu_device->HasMainSwapChain() ? g_gpu_device->GetMainSwapChain()->GetVSyncMode() : GPUVSyncMode::Disabled;
const bool allow_present_throttle =
g_gpu_device->HasMainSwapChain() && g_gpu_device->GetMainSwapChain()->IsPresentThrottleAllowed();
std::optional<GPUDevice::ExclusiveFullscreenMode> fullscreen_mode;
if (fullscreen && g_gpu_device->SupportsExclusiveFullscreen())
{
fullscreen_mode =
GPUDevice::ExclusiveFullscreenMode::Parse(Host::GetTinyStringSettingValue("GPU", "FullscreenMode", ""));
}
std::optional<bool> exclusive_fullscreen_control;
if (g_settings.display_exclusive_fullscreen_control != DisplayExclusiveFullscreenControl::Automatic)
{
exclusive_fullscreen_control =
(g_settings.display_exclusive_fullscreen_control == DisplayExclusiveFullscreenControl::Allowed);
}

g_gpu_device->DestroyMainSwapChain();

Error error;
std::optional<WindowInfo> wi;
if (!(wi = Host::AcquireRenderWindow(g_gpu_device->GetRenderAPI(), fullscreen, fullscreen_mode.has_value(), &error))
.has_value() ||
!g_gpu_device->RecreateMainSwapChain(wi.value(), vsync_mode, allow_present_throttle,
fullscreen_mode.has_value() ? &fullscreen_mode.value() : nullptr,
exclusive_fullscreen_control, &error))
{
Host::ReportErrorAsync("Error", "Failed to change window after update. The log may contain more information.");
Host::ReportFatalError("Failed to change window after update", error.GetDescription());
return;
}

const float f_width = static_cast<float>(g_gpu_device->GetWindowWidth());
const float f_height = static_cast<float>(g_gpu_device->GetWindowHeight());
const float f_width = static_cast<float>(g_gpu_device->GetMainSwapChain()->GetWidth());
const float f_height = static_cast<float>(g_gpu_device->GetMainSwapChain()->GetHeight());
ImGuiManager::WindowResized(f_width, f_height);
InputManager::SetDisplayWindowSize(f_width, f_height);
System::HostDisplayResized();
Expand All @@ -365,15 +408,21 @@ void Host::UpdateDisplayWindow()

void Host::ResizeDisplayWindow(s32 width, s32 height, float scale)
{
if (!g_gpu_device)
if (!g_gpu_device || !g_gpu_device->HasMainSwapChain())
return;

DEV_LOG("Display window resized to {}x{}", width, height);

g_gpu_device->ResizeWindow(width, height, scale);
Error error;
if (!g_gpu_device->GetMainSwapChain()->ResizeBuffers(width, height, scale, &error))
{
ERROR_LOG("Failed to resize main swap chain: {}", error.GetDescription());
UpdateDisplayWindow(Host::IsFullscreen());
return;
}

const float f_width = static_cast<float>(g_gpu_device->GetWindowWidth());
const float f_height = static_cast<float>(g_gpu_device->GetWindowHeight());
const float f_width = static_cast<float>(g_gpu_device->GetMainSwapChain()->GetWidth());
const float f_height = static_cast<float>(g_gpu_device->GetMainSwapChain()->GetHeight());
ImGuiManager::WindowResized(f_width, f_height);
InputManager::SetDisplayWindowSize(f_width, f_height);

Expand Down Expand Up @@ -404,4 +453,6 @@ void Host::ReleaseGPUDevice()
INFO_LOG("Destroying {} GPU device...", GPUDevice::RenderAPIToString(g_gpu_device->GetRenderAPI()));
g_gpu_device->Destroy();
g_gpu_device.reset();

Host::ReleaseRenderWindow();
}
18 changes: 16 additions & 2 deletions src/core/host.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,11 +82,25 @@ void DisplayLoadingScreen(const char* message, int progress_min = -1, int progre
/// Safely executes a function on the VM thread.
void RunOnCPUThread(std::function<void()> function, bool block = false);

/// Called when the core is creating a render device.
/// This could also be fullscreen transition.
std::optional<WindowInfo> AcquireRenderWindow(RenderAPI render_api, bool fullscreen, bool exclusive_fullscreen,
Error* error);

/// Called when the core is finished with a render window.
void ReleaseRenderWindow();

/// Returns true if the hosting application is currently fullscreen.
bool IsFullscreen();

/// Alters fullscreen state of hosting application.
void SetFullscreen(bool enabled);

/// Attempts to create the rendering device backend.
bool CreateGPUDevice(RenderAPI api, Error* error);
bool CreateGPUDevice(RenderAPI api, bool fullscreen, Error* error);

/// Handles fullscreen transitions and such.
void UpdateDisplayWindow();
void UpdateDisplayWindow(bool fullscreen);

/// Called when the window is resized.
void ResizeDisplayWindow(s32 width, s32 height, float scale);
Expand Down
9 changes: 5 additions & 4 deletions src/core/imgui_overlays.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ static std::tuple<float, float> GetMinMax(std::span<const float> values)
void Host::DisplayLoadingScreen(const char* message, int progress_min /*= -1*/, int progress_max /*= -1*/,
int progress_value /*= -1*/)
{
if (!g_gpu_device)
if (!g_gpu_device || !g_gpu_device->HasMainSwapChain())
{
INFO_LOG("{}: {}/{}", message, progress_value, progress_max);
return;
Expand Down Expand Up @@ -160,10 +160,11 @@ void Host::DisplayLoadingScreen(const char* message, int progress_min /*= -1*/,

// TODO: Glass effect or something.

if (g_gpu_device->BeginPresent() == GPUDevice::PresentResult::OK)
GPUSwapChain* swap_chain = g_gpu_device->GetMainSwapChain();
if (g_gpu_device->BeginPresent(swap_chain) == GPUDevice::PresentResult::OK)
{
g_gpu_device->RenderImGui();
g_gpu_device->EndPresent(false);
g_gpu_device->RenderImGui(swap_chain);
g_gpu_device->EndPresent(swap_chain, false);
}

ImGui::NewFrame();
Expand Down
Loading

0 comments on commit eb46142

Please sign in to comment.