mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2024-11-22 05:45:38 +00:00
GPUDevice: Add recovery from lost device
This commit is contained in:
parent
3a4ac13c26
commit
6336c4ee1f
|
@ -1993,7 +1993,7 @@ void GPU::SetDisplayTexture(GPUTexture* texture, GPUTexture* depth_buffer, s32 v
|
||||||
m_display_texture_view_height = view_height;
|
m_display_texture_view_height = view_height;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GPU::PresentDisplay()
|
GPUDevice::PresentResult GPU::PresentDisplay()
|
||||||
{
|
{
|
||||||
FlushRender();
|
FlushRender();
|
||||||
|
|
||||||
|
@ -2004,7 +2004,8 @@ bool GPU::PresentDisplay()
|
||||||
return RenderDisplay(nullptr, display_rect, draw_rect, !g_settings.debugging.show_vram);
|
return RenderDisplay(nullptr, display_rect, draw_rect, !g_settings.debugging.show_vram);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GPU::RenderDisplay(GPUTexture* target, const GSVector4i display_rect, const GSVector4i draw_rect, bool postfx)
|
GPUDevice::PresentResult GPU::RenderDisplay(GPUTexture* target, const GSVector4i display_rect,
|
||||||
|
const GSVector4i draw_rect, bool postfx)
|
||||||
{
|
{
|
||||||
GL_SCOPE_FMT("RenderDisplay: {}", draw_rect);
|
GL_SCOPE_FMT("RenderDisplay: {}", draw_rect);
|
||||||
|
|
||||||
|
@ -2027,10 +2028,15 @@ bool GPU::RenderDisplay(GPUTexture* target, const GSVector4i display_rect, const
|
||||||
|
|
||||||
// Now we can apply the post chain.
|
// Now we can apply the post chain.
|
||||||
GPUTexture* post_output_texture = PostProcessing::InternalChain.GetOutputTexture();
|
GPUTexture* post_output_texture = PostProcessing::InternalChain.GetOutputTexture();
|
||||||
if (PostProcessing::InternalChain.Apply(display_texture, m_display_depth_buffer, post_output_texture,
|
if (const GPUDevice::PresentResult pres = PostProcessing::InternalChain.Apply(
|
||||||
GSVector4i(0, 0, display_texture_view_width, display_texture_view_height),
|
display_texture, m_display_depth_buffer, post_output_texture,
|
||||||
display_texture_view_width, display_texture_view_height,
|
GSVector4i(0, 0, display_texture_view_width, display_texture_view_height), display_texture_view_width,
|
||||||
m_crtc_state.display_width, m_crtc_state.display_height))
|
display_texture_view_height, m_crtc_state.display_width, m_crtc_state.display_height);
|
||||||
|
pres != GPUDevice::PresentResult::OK)
|
||||||
|
{
|
||||||
|
return pres;
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
display_texture_view_x = 0;
|
display_texture_view_x = 0;
|
||||||
display_texture_view_y = 0;
|
display_texture_view_y = 0;
|
||||||
|
@ -2057,8 +2063,9 @@ bool GPU::RenderDisplay(GPUTexture* target, const GSVector4i display_rect, const
|
||||||
{
|
{
|
||||||
if (target)
|
if (target)
|
||||||
g_gpu_device->SetRenderTarget(target);
|
g_gpu_device->SetRenderTarget(target);
|
||||||
else if (!g_gpu_device->BeginPresent(false))
|
else if (const GPUDevice::PresentResult pres = g_gpu_device->BeginPresent(false);
|
||||||
return false;
|
pres != GPUDevice::PresentResult::OK)
|
||||||
|
return pres;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (display_texture)
|
if (display_texture)
|
||||||
|
@ -2167,7 +2174,9 @@ bool GPU::RenderDisplay(GPUTexture* target, const GSVector4i display_rect, const
|
||||||
m_crtc_state.display_height);
|
m_crtc_state.display_height);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return true;
|
{
|
||||||
|
return GPUDevice::PresentResult::OK;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GPU::SendDisplayToMediaCapture(MediaCapture* cap)
|
bool GPU::SendDisplayToMediaCapture(MediaCapture* cap)
|
||||||
|
@ -2186,7 +2195,7 @@ bool GPU::SendDisplayToMediaCapture(MediaCapture* cap)
|
||||||
// Not cleared by RenderDisplay().
|
// Not cleared by RenderDisplay().
|
||||||
g_gpu_device->ClearRenderTarget(target, GPUDevice::DEFAULT_CLEAR_COLOR);
|
g_gpu_device->ClearRenderTarget(target, GPUDevice::DEFAULT_CLEAR_COLOR);
|
||||||
|
|
||||||
if (!RenderDisplay(target, display_rect, draw_rect, postfx)) [[unlikely]]
|
if (RenderDisplay(target, display_rect, draw_rect, postfx) != GPUDevice::PresentResult::OK) [[unlikely]]
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return cap->DeliverVideoFrame(target);
|
return cap->DeliverVideoFrame(target);
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include "timing_event.h"
|
#include "timing_event.h"
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
|
#include "util/gpu_device.h"
|
||||||
#include "util/gpu_texture.h"
|
#include "util/gpu_texture.h"
|
||||||
|
|
||||||
#include "common/bitfield.h"
|
#include "common/bitfield.h"
|
||||||
|
@ -233,7 +234,7 @@ public:
|
||||||
bool show_osd_message);
|
bool show_osd_message);
|
||||||
|
|
||||||
/// Draws the current display texture, with any post-processing.
|
/// Draws the current display texture, with any post-processing.
|
||||||
bool PresentDisplay();
|
GPUDevice::PresentResult PresentDisplay();
|
||||||
|
|
||||||
/// Sends the current frame to media capture.
|
/// Sends the current frame to media capture.
|
||||||
bool SendDisplayToMediaCapture(MediaCapture* cap);
|
bool SendDisplayToMediaCapture(MediaCapture* cap);
|
||||||
|
@ -630,7 +631,8 @@ protected:
|
||||||
void SetDisplayTexture(GPUTexture* texture, GPUTexture* depth_texture, s32 view_x, s32 view_y, s32 view_width,
|
void SetDisplayTexture(GPUTexture* texture, GPUTexture* depth_texture, s32 view_x, s32 view_y, s32 view_width,
|
||||||
s32 view_height);
|
s32 view_height);
|
||||||
|
|
||||||
bool RenderDisplay(GPUTexture* target, const GSVector4i display_rect, const GSVector4i draw_rect, bool postfx);
|
GPUDevice::PresentResult RenderDisplay(GPUTexture* target, const GSVector4i display_rect, const GSVector4i draw_rect,
|
||||||
|
bool postfx);
|
||||||
|
|
||||||
bool Deinterlace(u32 field, u32 line_skip);
|
bool Deinterlace(u32 field, u32 line_skip);
|
||||||
bool DeinterlaceExtractField(u32 dst_bufidx, GPUTexture* src, u32 x, u32 y, u32 width, u32 height, u32 line_skip);
|
bool DeinterlaceExtractField(u32 dst_bufidx, GPUTexture* src, u32 x, u32 y, u32 width, u32 height, u32 line_skip);
|
||||||
|
|
|
@ -160,7 +160,7 @@ void Host::DisplayLoadingScreen(const char* message, int progress_min /*= -1*/,
|
||||||
|
|
||||||
// TODO: Glass effect or something.
|
// TODO: Glass effect or something.
|
||||||
|
|
||||||
if (g_gpu_device->BeginPresent(false))
|
if (g_gpu_device->BeginPresent(false) == GPUDevice::PresentResult::OK)
|
||||||
{
|
{
|
||||||
g_gpu_device->RenderImGui();
|
g_gpu_device->RenderImGui();
|
||||||
g_gpu_device->EndPresent(false);
|
g_gpu_device->EndPresent(false);
|
||||||
|
|
|
@ -162,6 +162,7 @@ static void DestroySystem();
|
||||||
|
|
||||||
static bool CreateGPU(GPURenderer renderer, bool is_switching, Error* error);
|
static bool CreateGPU(GPURenderer renderer, bool is_switching, Error* error);
|
||||||
static bool RecreateGPU(GPURenderer renderer, bool force_recreate_device = false, bool update_display = true);
|
static bool RecreateGPU(GPURenderer renderer, bool force_recreate_device = false, bool update_display = true);
|
||||||
|
static void HandleHostGPUDeviceLost();
|
||||||
|
|
||||||
/// Updates the throttle period, call when target emulation speed changes.
|
/// Updates the throttle period, call when target emulation speed changes.
|
||||||
static void UpdateThrottlePeriod();
|
static void UpdateThrottlePeriod();
|
||||||
|
@ -1202,6 +1203,45 @@ bool System::RecreateGPU(GPURenderer renderer, bool force_recreate_device, bool
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void System::HandleHostGPUDeviceLost()
|
||||||
|
{
|
||||||
|
static Common::Timer::Value s_last_gpu_reset_time = 0;
|
||||||
|
static constexpr float MIN_TIME_BETWEEN_RESETS = 15.0f;
|
||||||
|
|
||||||
|
// If we're constantly crashing on something in particular, we don't want to end up in an
|
||||||
|
// endless reset loop.. that'd probably end up leaking memory and/or crashing us for other
|
||||||
|
// reasons. So just abort in such case.
|
||||||
|
const Common::Timer::Value current_time = Common::Timer::GetCurrentValue();
|
||||||
|
if (s_last_gpu_reset_time != 0 &&
|
||||||
|
Common::Timer::ConvertValueToSeconds(current_time - s_last_gpu_reset_time) < MIN_TIME_BETWEEN_RESETS)
|
||||||
|
{
|
||||||
|
Panic("Host GPU lost too many times, device is probably completely wedged.");
|
||||||
|
}
|
||||||
|
s_last_gpu_reset_time = current_time;
|
||||||
|
|
||||||
|
// Little bit janky, but because the device is lost, the VRAM readback is going to give us garbage.
|
||||||
|
// So back up what we have, it's probably missing bits, but whatever...
|
||||||
|
DynamicHeapArray<u8> vram_backup(VRAM_SIZE);
|
||||||
|
std::memcpy(vram_backup.data(), g_vram, VRAM_SIZE);
|
||||||
|
|
||||||
|
// Device lost, something went really bad.
|
||||||
|
// Let's just toss out everything, and try to hobble on.
|
||||||
|
if (!RecreateGPU(g_gpu->IsHardwareRenderer() ? g_settings.gpu_renderer : GPURenderer::Software, true, false))
|
||||||
|
{
|
||||||
|
Panic("Failed to recreate GS device after loss.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore backed-up VRAM.
|
||||||
|
std::memcpy(g_vram, vram_backup.data(), VRAM_SIZE);
|
||||||
|
|
||||||
|
// First frame after reopening is definitely going to be trash, so skip it.
|
||||||
|
Host::AddIconOSDMessage(
|
||||||
|
"HostGPUDeviceLost", ICON_EMOJI_WARNING,
|
||||||
|
TRANSLATE_STR("System", "Host GPU device encountered an error and has recovered. This may cause broken rendering."),
|
||||||
|
Host::OSD_CRITICAL_ERROR_DURATION);
|
||||||
|
}
|
||||||
|
|
||||||
void System::LoadSettings(bool display_osd_messages)
|
void System::LoadSettings(bool display_osd_messages)
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> lock = Host::GetSettingsLock();
|
std::unique_lock<std::mutex> lock = Host::GetSettingsLock();
|
||||||
|
@ -5713,13 +5753,13 @@ bool System::PresentDisplay(bool skip_present, bool explicit_present)
|
||||||
ImGuiManager::RenderOverlayWindows();
|
ImGuiManager::RenderOverlayWindows();
|
||||||
ImGuiManager::RenderDebugWindows();
|
ImGuiManager::RenderDebugWindows();
|
||||||
|
|
||||||
bool do_present;
|
GPUDevice::PresentResult pres;
|
||||||
if (g_gpu && !skip_present)
|
if (g_gpu && !skip_present)
|
||||||
do_present = g_gpu->PresentDisplay();
|
pres = g_gpu->PresentDisplay();
|
||||||
else
|
else
|
||||||
do_present = g_gpu_device->BeginPresent(skip_present);
|
pres = g_gpu_device->BeginPresent(skip_present);
|
||||||
|
|
||||||
if (do_present)
|
if (pres == GPUDevice::PresentResult::OK)
|
||||||
{
|
{
|
||||||
g_gpu_device->RenderImGui();
|
g_gpu_device->RenderImGui();
|
||||||
g_gpu_device->EndPresent(explicit_present);
|
g_gpu_device->EndPresent(explicit_present);
|
||||||
|
@ -5732,13 +5772,16 @@ bool System::PresentDisplay(bool skip_present, bool explicit_present)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
if (pres == GPUDevice::PresentResult::DeviceLost) [[unlikely]]
|
||||||
|
HandleHostGPUDeviceLost();
|
||||||
|
|
||||||
// Still need to kick ImGui or it gets cranky.
|
// Still need to kick ImGui or it gets cranky.
|
||||||
ImGui::Render();
|
ImGui::Render();
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGuiManager::NewFrame();
|
ImGuiManager::NewFrame();
|
||||||
|
|
||||||
return do_present;
|
return (pres == GPUDevice::PresentResult::OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
void System::InvalidateDisplay()
|
void System::InvalidateDisplay()
|
||||||
|
|
|
@ -639,17 +639,17 @@ void D3D11Device::SetVSyncMode(GPUVSyncMode mode, bool allow_present_throttle)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool D3D11Device::BeginPresent(bool skip_present, u32 clear_color)
|
GPUDevice::PresentResult D3D11Device::BeginPresent(bool skip_present, u32 clear_color)
|
||||||
{
|
{
|
||||||
if (skip_present)
|
if (skip_present)
|
||||||
return false;
|
return PresentResult::SkipPresent;
|
||||||
|
|
||||||
if (!m_swap_chain)
|
if (!m_swap_chain)
|
||||||
{
|
{
|
||||||
// Note: Really slow on Intel...
|
// Note: Really slow on Intel...
|
||||||
m_context->Flush();
|
m_context->Flush();
|
||||||
TrimTexturePool();
|
TrimTexturePool();
|
||||||
return false;
|
return PresentResult::SkipPresent;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if we lost exclusive fullscreen. If so, notify the host, so it can switch to windowed mode.
|
// Check if we lost exclusive fullscreen. If so, notify the host, so it can switch to windowed mode.
|
||||||
|
@ -660,7 +660,7 @@ bool D3D11Device::BeginPresent(bool skip_present, u32 clear_color)
|
||||||
{
|
{
|
||||||
Host::SetFullscreen(false);
|
Host::SetFullscreen(false);
|
||||||
TrimTexturePool();
|
TrimTexturePool();
|
||||||
return false;
|
return PresentResult::SkipPresent;
|
||||||
}
|
}
|
||||||
|
|
||||||
// When using vsync, the time here seems to include the time for the buffer to become available.
|
// When using vsync, the time here seems to include the time for the buffer to become available.
|
||||||
|
@ -677,7 +677,7 @@ bool D3D11Device::BeginPresent(bool skip_present, u32 clear_color)
|
||||||
m_current_render_pass_flags = GPUPipeline::NoRenderPassFlags;
|
m_current_render_pass_flags = GPUPipeline::NoRenderPassFlags;
|
||||||
std::memset(m_current_render_targets.data(), 0, sizeof(m_current_render_targets));
|
std::memset(m_current_render_targets.data(), 0, sizeof(m_current_render_targets));
|
||||||
m_current_depth_target = nullptr;
|
m_current_depth_target = nullptr;
|
||||||
return true;
|
return PresentResult::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void D3D11Device::EndPresent(bool explicit_present)
|
void D3D11Device::EndPresent(bool explicit_present)
|
||||||
|
|
|
@ -104,7 +104,7 @@ public:
|
||||||
bool SetGPUTimingEnabled(bool enabled) override;
|
bool SetGPUTimingEnabled(bool enabled) override;
|
||||||
float GetAndResetAccumulatedGPUTime() override;
|
float GetAndResetAccumulatedGPUTime() override;
|
||||||
|
|
||||||
bool BeginPresent(bool skip_present, u32 clear_color) override;
|
PresentResult BeginPresent(bool skip_present, u32 clear_color) override;
|
||||||
void EndPresent(bool explicit_present) override;
|
void EndPresent(bool explicit_present) override;
|
||||||
void SubmitPresent() override;
|
void SubmitPresent() override;
|
||||||
|
|
||||||
|
|
|
@ -532,6 +532,9 @@ ID3D12GraphicsCommandList4* D3D12Device::GetInitCommandList()
|
||||||
|
|
||||||
void D3D12Device::SubmitCommandList(bool wait_for_completion)
|
void D3D12Device::SubmitCommandList(bool wait_for_completion)
|
||||||
{
|
{
|
||||||
|
if (m_device_was_lost) [[unlikely]]
|
||||||
|
return;
|
||||||
|
|
||||||
CommandList& res = m_command_lists[m_current_command_list];
|
CommandList& res = m_command_lists[m_current_command_list];
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
|
||||||
|
@ -553,7 +556,8 @@ void D3D12Device::SubmitCommandList(bool wait_for_completion)
|
||||||
if (FAILED(hr)) [[unlikely]]
|
if (FAILED(hr)) [[unlikely]]
|
||||||
{
|
{
|
||||||
ERROR_LOG("Closing init command list failed with HRESULT {:08X}", static_cast<unsigned>(hr));
|
ERROR_LOG("Closing init command list failed with HRESULT {:08X}", static_cast<unsigned>(hr));
|
||||||
Panic("TODO cannot continue");
|
m_device_was_lost = true;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -562,7 +566,8 @@ void D3D12Device::SubmitCommandList(bool wait_for_completion)
|
||||||
if (FAILED(hr)) [[unlikely]]
|
if (FAILED(hr)) [[unlikely]]
|
||||||
{
|
{
|
||||||
ERROR_LOG("Closing main command list failed with HRESULT {:08X}", static_cast<unsigned>(hr));
|
ERROR_LOG("Closing main command list failed with HRESULT {:08X}", static_cast<unsigned>(hr));
|
||||||
Panic("TODO cannot continue");
|
m_device_was_lost = true;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (res.init_list_used)
|
if (res.init_list_used)
|
||||||
|
@ -578,7 +583,12 @@ void D3D12Device::SubmitCommandList(bool wait_for_completion)
|
||||||
|
|
||||||
// Update fence when GPU has completed.
|
// Update fence when GPU has completed.
|
||||||
hr = m_command_queue->Signal(m_fence.Get(), res.fence_counter);
|
hr = m_command_queue->Signal(m_fence.Get(), res.fence_counter);
|
||||||
DebugAssertMsg(SUCCEEDED(hr), "Signal fence");
|
if (FAILED(hr))
|
||||||
|
{
|
||||||
|
ERROR_LOG("Signal command queue fence failed with HRESULT {:08X}", static_cast<unsigned>(hr));
|
||||||
|
m_device_was_lost = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
MoveToNextCommandList();
|
MoveToNextCommandList();
|
||||||
|
|
||||||
|
@ -606,6 +616,9 @@ void D3D12Device::SubmitCommandListAndRestartRenderPass(const std::string_view r
|
||||||
|
|
||||||
void D3D12Device::WaitForFence(u64 fence)
|
void D3D12Device::WaitForFence(u64 fence)
|
||||||
{
|
{
|
||||||
|
if (m_device_was_lost) [[unlikely]]
|
||||||
|
return;
|
||||||
|
|
||||||
if (m_completed_fence_value >= fence)
|
if (m_completed_fence_value >= fence)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -1110,20 +1123,23 @@ void D3D12Device::SetVSyncMode(GPUVSyncMode mode, bool allow_present_throttle)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool D3D12Device::BeginPresent(bool frame_skip, u32 clear_color)
|
GPUDevice::PresentResult D3D12Device::BeginPresent(bool frame_skip, u32 clear_color)
|
||||||
{
|
{
|
||||||
if (InRenderPass())
|
if (InRenderPass())
|
||||||
EndRenderPass();
|
EndRenderPass();
|
||||||
|
|
||||||
|
if (m_device_was_lost) [[unlikely]]
|
||||||
|
return PresentResult::DeviceLost;
|
||||||
|
|
||||||
if (frame_skip)
|
if (frame_skip)
|
||||||
return false;
|
return PresentResult::SkipPresent;
|
||||||
|
|
||||||
// If we're running surfaceless, kick the command buffer so we don't run out of descriptors.
|
// If we're running surfaceless, kick the command buffer so we don't run out of descriptors.
|
||||||
if (!m_swap_chain)
|
if (!m_swap_chain)
|
||||||
{
|
{
|
||||||
SubmitCommandList(false);
|
SubmitCommandList(false);
|
||||||
TrimTexturePool();
|
TrimTexturePool();
|
||||||
return false;
|
return PresentResult::SkipPresent;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Check if the device was lost.
|
// TODO: Check if the device was lost.
|
||||||
|
@ -1136,11 +1152,11 @@ bool D3D12Device::BeginPresent(bool frame_skip, u32 clear_color)
|
||||||
{
|
{
|
||||||
Host::RunOnCPUThread([]() { Host::SetFullscreen(false); });
|
Host::RunOnCPUThread([]() { Host::SetFullscreen(false); });
|
||||||
TrimTexturePool();
|
TrimTexturePool();
|
||||||
return false;
|
return PresentResult::SkipPresent;
|
||||||
}
|
}
|
||||||
|
|
||||||
BeginSwapChainRenderPass(clear_color);
|
BeginSwapChainRenderPass(clear_color);
|
||||||
return true;
|
return PresentResult::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void D3D12Device::EndPresent(bool explicit_present)
|
void D3D12Device::EndPresent(bool explicit_present)
|
||||||
|
@ -1165,6 +1181,8 @@ void D3D12Device::EndPresent(bool explicit_present)
|
||||||
void D3D12Device::SubmitPresent()
|
void D3D12Device::SubmitPresent()
|
||||||
{
|
{
|
||||||
DebugAssert(m_swap_chain);
|
DebugAssert(m_swap_chain);
|
||||||
|
if (m_device_was_lost) [[unlikely]]
|
||||||
|
return;
|
||||||
|
|
||||||
const UINT sync_interval = static_cast<UINT>(m_vsync_mode == GPUVSyncMode::FIFO);
|
const UINT sync_interval = static_cast<UINT>(m_vsync_mode == GPUVSyncMode::FIFO);
|
||||||
const UINT flags = (m_vsync_mode == GPUVSyncMode::Disabled && m_using_allow_tearing) ? DXGI_PRESENT_ALLOW_TEARING : 0;
|
const UINT flags = (m_vsync_mode == GPUVSyncMode::Disabled && m_using_allow_tearing) ? DXGI_PRESENT_ALLOW_TEARING : 0;
|
||||||
|
|
|
@ -126,7 +126,7 @@ public:
|
||||||
bool SetGPUTimingEnabled(bool enabled) override;
|
bool SetGPUTimingEnabled(bool enabled) override;
|
||||||
float GetAndResetAccumulatedGPUTime() override;
|
float GetAndResetAccumulatedGPUTime() override;
|
||||||
|
|
||||||
bool BeginPresent(bool skip_present, u32 clear_color) override;
|
PresentResult BeginPresent(bool skip_present, u32 clear_color) override;
|
||||||
void EndPresent(bool explicit_present) override;
|
void EndPresent(bool explicit_present) override;
|
||||||
void SubmitPresent() override;
|
void SubmitPresent() override;
|
||||||
|
|
||||||
|
@ -300,6 +300,7 @@ private:
|
||||||
bool m_allow_tearing_supported = false;
|
bool m_allow_tearing_supported = false;
|
||||||
bool m_using_allow_tearing = false;
|
bool m_using_allow_tearing = false;
|
||||||
bool m_is_exclusive_fullscreen = false;
|
bool m_is_exclusive_fullscreen = false;
|
||||||
|
bool m_device_was_lost = false;
|
||||||
|
|
||||||
D3D12DescriptorHeapManager m_descriptor_heap_manager;
|
D3D12DescriptorHeapManager m_descriptor_heap_manager;
|
||||||
D3D12DescriptorHeapManager m_rtv_heap_manager;
|
D3D12DescriptorHeapManager m_rtv_heap_manager;
|
||||||
|
|
|
@ -481,6 +481,13 @@ public:
|
||||||
Full
|
Full
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class PresentResult : u32
|
||||||
|
{
|
||||||
|
OK,
|
||||||
|
SkipPresent,
|
||||||
|
DeviceLost,
|
||||||
|
};
|
||||||
|
|
||||||
struct Features
|
struct Features
|
||||||
{
|
{
|
||||||
bool dual_source_blend : 1;
|
bool dual_source_blend : 1;
|
||||||
|
@ -702,7 +709,7 @@ public:
|
||||||
virtual void DrawIndexedWithBarrier(u32 index_count, u32 base_index, u32 base_vertex, DrawBarrier type) = 0;
|
virtual void DrawIndexedWithBarrier(u32 index_count, u32 base_index, u32 base_vertex, DrawBarrier type) = 0;
|
||||||
|
|
||||||
/// Returns false if the window was completely occluded.
|
/// Returns false if the window was completely occluded.
|
||||||
virtual bool BeginPresent(bool skip_present, u32 clear_color = DEFAULT_CLEAR_COLOR) = 0;
|
virtual PresentResult BeginPresent(bool skip_present, u32 clear_color = DEFAULT_CLEAR_COLOR) = 0;
|
||||||
virtual void EndPresent(bool explicit_submit) = 0;
|
virtual void EndPresent(bool explicit_submit) = 0;
|
||||||
virtual void SubmitPresent() = 0;
|
virtual void SubmitPresent() = 0;
|
||||||
|
|
||||||
|
|
|
@ -265,7 +265,7 @@ public:
|
||||||
|
|
||||||
void SetVSyncMode(GPUVSyncMode mode, bool allow_present_throttle) override;
|
void SetVSyncMode(GPUVSyncMode mode, bool allow_present_throttle) override;
|
||||||
|
|
||||||
bool BeginPresent(bool skip_present, u32 clear_color) override;
|
PresentResult BeginPresent(bool skip_present, u32 clear_color) override;
|
||||||
void EndPresent(bool explicit_submit) override;
|
void EndPresent(bool explicit_submit) override;
|
||||||
void SubmitPresent() override;
|
void SubmitPresent() override;
|
||||||
|
|
||||||
|
|
|
@ -2312,17 +2312,17 @@ id<MTLBlitCommandEncoder> MetalDevice::GetBlitEncoder(bool is_inline)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MetalDevice::BeginPresent(bool skip_present, u32 clear_color)
|
GPUDevice::PresentResult MetalDevice::BeginPresent(bool skip_present, u32 clear_color)
|
||||||
{
|
{
|
||||||
@autoreleasepool
|
@autoreleasepool
|
||||||
{
|
{
|
||||||
if (skip_present)
|
if (skip_present)
|
||||||
return false;
|
return PresentResult::SkipPresent;
|
||||||
|
|
||||||
if (m_layer == nil)
|
if (m_layer == nil)
|
||||||
{
|
{
|
||||||
TrimTexturePool();
|
TrimTexturePool();
|
||||||
return false;
|
return PresentResult::SkipPresent;
|
||||||
}
|
}
|
||||||
|
|
||||||
EndAnyEncoding();
|
EndAnyEncoding();
|
||||||
|
@ -2331,7 +2331,7 @@ bool MetalDevice::BeginPresent(bool skip_present, u32 clear_color)
|
||||||
if (m_layer_drawable == nil)
|
if (m_layer_drawable == nil)
|
||||||
{
|
{
|
||||||
TrimTexturePool();
|
TrimTexturePool();
|
||||||
return false;
|
return PresentResult::SkipPresent;
|
||||||
}
|
}
|
||||||
|
|
||||||
SetViewportAndScissor(0, 0, m_window_info.surface_width, m_window_info.surface_height);
|
SetViewportAndScissor(0, 0, m_window_info.surface_width, m_window_info.surface_height);
|
||||||
|
@ -2351,7 +2351,7 @@ bool MetalDevice::BeginPresent(bool skip_present, u32 clear_color)
|
||||||
m_current_pipeline = nullptr;
|
m_current_pipeline = nullptr;
|
||||||
m_current_depth_state = nil;
|
m_current_depth_state = nil;
|
||||||
SetInitialEncoderState();
|
SetInitialEncoderState();
|
||||||
return true;
|
return PresentResult::OK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -740,7 +740,7 @@ void OpenGLDevice::DestroyBuffers()
|
||||||
m_vertex_buffer.reset();
|
m_vertex_buffer.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OpenGLDevice::BeginPresent(bool skip_present, u32 clear_color)
|
GPUDevice::PresentResult OpenGLDevice::BeginPresent(bool skip_present, u32 clear_color)
|
||||||
{
|
{
|
||||||
if (skip_present || m_window_info.type == WindowInfo::Type::Surfaceless)
|
if (skip_present || m_window_info.type == WindowInfo::Type::Surfaceless)
|
||||||
{
|
{
|
||||||
|
@ -750,7 +750,7 @@ bool OpenGLDevice::BeginPresent(bool skip_present, u32 clear_color)
|
||||||
TrimTexturePool();
|
TrimTexturePool();
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return PresentResult::SkipPresent;
|
||||||
}
|
}
|
||||||
|
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
|
@ -771,7 +771,7 @@ bool OpenGLDevice::BeginPresent(bool skip_present, u32 clear_color)
|
||||||
m_last_scissor = window_rc;
|
m_last_scissor = window_rc;
|
||||||
UpdateViewport();
|
UpdateViewport();
|
||||||
UpdateScissor();
|
UpdateScissor();
|
||||||
return true;
|
return PresentResult::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLDevice::EndPresent(bool explicit_present)
|
void OpenGLDevice::EndPresent(bool explicit_present)
|
||||||
|
|
|
@ -104,7 +104,7 @@ public:
|
||||||
|
|
||||||
void SetVSyncMode(GPUVSyncMode mode, bool allow_present_throttle) override;
|
void SetVSyncMode(GPUVSyncMode mode, bool allow_present_throttle) override;
|
||||||
|
|
||||||
bool BeginPresent(bool skip_present, u32 clear_color) override;
|
PresentResult BeginPresent(bool skip_present, u32 clear_color) override;
|
||||||
void EndPresent(bool explicit_present) override;
|
void EndPresent(bool explicit_present) override;
|
||||||
void SubmitPresent() override;
|
void SubmitPresent() override;
|
||||||
|
|
||||||
|
|
|
@ -619,9 +619,9 @@ void PostProcessing::Chain::DestroyTextures()
|
||||||
g_gpu_device->RecycleTexture(std::move(m_input_texture));
|
g_gpu_device->RecycleTexture(std::move(m_input_texture));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PostProcessing::Chain::Apply(GPUTexture* input_color, GPUTexture* input_depth, GPUTexture* final_target,
|
GPUDevice::PresentResult PostProcessing::Chain::Apply(GPUTexture* input_color, GPUTexture* input_depth,
|
||||||
GSVector4i final_rect, s32 orig_width, s32 orig_height, s32 native_width,
|
GPUTexture* final_target, GSVector4i final_rect, s32 orig_width,
|
||||||
s32 native_height)
|
s32 orig_height, s32 native_width, s32 native_height)
|
||||||
{
|
{
|
||||||
GL_SCOPE_FMT("{} Apply", m_section);
|
GL_SCOPE_FMT("{} Apply", m_section);
|
||||||
|
|
||||||
|
@ -634,10 +634,12 @@ bool PostProcessing::Chain::Apply(GPUTexture* input_color, GPUTexture* input_dep
|
||||||
{
|
{
|
||||||
const bool is_final = (stage.get() == m_stages.back().get());
|
const bool is_final = (stage.get() == m_stages.back().get());
|
||||||
|
|
||||||
if (!stage->Apply(input_color, input_depth, is_final ? final_target : output, final_rect, orig_width, orig_height,
|
if (const GPUDevice::PresentResult pres =
|
||||||
native_width, native_height, m_target_width, m_target_height))
|
stage->Apply(input_color, input_depth, is_final ? final_target : output, final_rect, orig_width, orig_height,
|
||||||
|
native_width, native_height, m_target_width, m_target_height);
|
||||||
|
pres != GPUDevice::PresentResult::OK)
|
||||||
{
|
{
|
||||||
return false;
|
return pres;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_final)
|
if (!is_final)
|
||||||
|
@ -648,7 +650,7 @@ bool PostProcessing::Chain::Apply(GPUTexture* input_color, GPUTexture* input_dep
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return GPUDevice::PresentResult::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PostProcessing::Initialize()
|
void PostProcessing::Initialize()
|
||||||
|
|
|
@ -134,8 +134,9 @@ public:
|
||||||
bool CheckTargets(GPUTexture::Format target_format, u32 target_width, u32 target_height,
|
bool CheckTargets(GPUTexture::Format target_format, u32 target_width, u32 target_height,
|
||||||
ProgressCallback* progress = nullptr);
|
ProgressCallback* progress = nullptr);
|
||||||
|
|
||||||
bool Apply(GPUTexture* input_color, GPUTexture* input_depth, GPUTexture* final_target, const GSVector4i final_rect,
|
GPUDevice::PresentResult Apply(GPUTexture* input_color, GPUTexture* input_depth, GPUTexture* final_target,
|
||||||
s32 orig_width, s32 orig_height, s32 native_width, s32 native_height);
|
const GSVector4i final_rect, s32 orig_width, s32 orig_height, s32 native_width,
|
||||||
|
s32 native_height);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void ClearStagesWithError(const Error& error);
|
void ClearStagesWithError(const Error& error);
|
||||||
|
|
|
@ -3,15 +3,14 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "postprocessing.h"
|
#include "gpu_device.h"
|
||||||
|
|
||||||
#include "gpu_texture.h"
|
#include "gpu_texture.h"
|
||||||
|
#include "postprocessing.h"
|
||||||
|
|
||||||
#include "common/gsvector.h"
|
#include "common/gsvector.h"
|
||||||
#include "common/settings_interface.h"
|
#include "common/settings_interface.h"
|
||||||
#include "common/timer.h"
|
#include "common/timer.h"
|
||||||
#include "common/types.h"
|
#include "common/types.h"
|
||||||
#include "gpu_device.h"
|
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
@ -49,9 +48,9 @@ public:
|
||||||
|
|
||||||
virtual bool CompilePipeline(GPUTexture::Format format, u32 width, u32 height, ProgressCallback* progress) = 0;
|
virtual bool CompilePipeline(GPUTexture::Format format, u32 width, u32 height, ProgressCallback* progress) = 0;
|
||||||
|
|
||||||
virtual bool Apply(GPUTexture* input_color, GPUTexture* input_depth, GPUTexture* final_target, GSVector4i final_rect,
|
virtual GPUDevice::PresentResult Apply(GPUTexture* input_color, GPUTexture* input_depth, GPUTexture* final_target,
|
||||||
s32 orig_width, s32 orig_height, s32 native_width, s32 native_height, u32 target_width,
|
GSVector4i final_rect, s32 orig_width, s32 orig_height, s32 native_width,
|
||||||
u32 target_height) = 0;
|
s32 native_height, u32 target_width, u32 target_height) = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
using OptionList = std::vector<ShaderOption>;
|
using OptionList = std::vector<ShaderOption>;
|
||||||
|
|
|
@ -1491,9 +1491,10 @@ bool PostProcessing::ReShadeFXShader::ResizeOutput(GPUTexture::Format format, u3
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PostProcessing::ReShadeFXShader::Apply(GPUTexture* input_color, GPUTexture* input_depth, GPUTexture* final_target,
|
GPUDevice::PresentResult PostProcessing::ReShadeFXShader::Apply(GPUTexture* input_color, GPUTexture* input_depth,
|
||||||
GSVector4i final_rect, s32 orig_width, s32 orig_height, s32 native_width,
|
GPUTexture* final_target, GSVector4i final_rect,
|
||||||
s32 native_height, u32 target_width, u32 target_height)
|
s32 orig_width, s32 orig_height, s32 native_width,
|
||||||
|
s32 native_height, u32 target_width, u32 target_height)
|
||||||
{
|
{
|
||||||
GL_PUSH_FMT("PostProcessingShaderFX {}", m_name);
|
GL_PUSH_FMT("PostProcessingShaderFX {}", m_name);
|
||||||
|
|
||||||
|
@ -1783,10 +1784,10 @@ bool PostProcessing::ReShadeFXShader::Apply(GPUTexture* input_color, GPUTexture*
|
||||||
if (pass.render_targets.size() == 1 && pass.render_targets[0] == OUTPUT_COLOR_TEXTURE && !final_target)
|
if (pass.render_targets.size() == 1 && pass.render_targets[0] == OUTPUT_COLOR_TEXTURE && !final_target)
|
||||||
{
|
{
|
||||||
// Special case: drawing to final buffer.
|
// Special case: drawing to final buffer.
|
||||||
if (!g_gpu_device->BeginPresent(false))
|
if (const GPUDevice::PresentResult pres = g_gpu_device->BeginPresent(false); pres != GPUDevice::PresentResult::OK)
|
||||||
{
|
{
|
||||||
GL_POP();
|
GL_POP();
|
||||||
return false;
|
return pres;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -1842,5 +1843,5 @@ bool PostProcessing::ReShadeFXShader::Apply(GPUTexture* input_color, GPUTexture*
|
||||||
|
|
||||||
GL_POP();
|
GL_POP();
|
||||||
m_frame_timer.Reset();
|
m_frame_timer.Reset();
|
||||||
return true;
|
return GPUDevice::PresentResult::OK;
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,9 +31,9 @@ public:
|
||||||
|
|
||||||
bool ResizeOutput(GPUTexture::Format format, u32 width, u32 height) override;
|
bool ResizeOutput(GPUTexture::Format format, u32 width, u32 height) override;
|
||||||
bool CompilePipeline(GPUTexture::Format format, u32 width, u32 height, ProgressCallback* progress) override;
|
bool CompilePipeline(GPUTexture::Format format, u32 width, u32 height, ProgressCallback* progress) override;
|
||||||
bool Apply(GPUTexture* input_color, GPUTexture* input_depth, GPUTexture* final_target, GSVector4i final_rect,
|
GPUDevice::PresentResult Apply(GPUTexture* input_color, GPUTexture* input_depth, GPUTexture* final_target,
|
||||||
s32 orig_width, s32 orig_height, s32 native_width, s32 native_height, u32 target_width,
|
GSVector4i final_rect, s32 orig_width, s32 orig_height, s32 native_width,
|
||||||
u32 target_height) override;
|
s32 native_height, u32 target_width, u32 target_height) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
using TextureID = s32;
|
using TextureID = s32;
|
||||||
|
|
|
@ -167,17 +167,18 @@ bool PostProcessing::GLSLShader::CompilePipeline(GPUTexture::Format format, u32
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PostProcessing::GLSLShader::Apply(GPUTexture* input_color, GPUTexture* input_depth, GPUTexture* final_target,
|
GPUDevice::PresentResult PostProcessing::GLSLShader::Apply(GPUTexture* input_color, GPUTexture* input_depth,
|
||||||
GSVector4i final_rect, s32 orig_width, s32 orig_height, s32 native_width,
|
GPUTexture* final_target, GSVector4i final_rect,
|
||||||
s32 native_height, u32 target_width, u32 target_height)
|
s32 orig_width, s32 orig_height, s32 native_width,
|
||||||
|
s32 native_height, u32 target_width, u32 target_height)
|
||||||
{
|
{
|
||||||
GL_SCOPE_FMT("GLSL Shader {}", m_name);
|
GL_SCOPE_FMT("GLSL Shader {}", m_name);
|
||||||
|
|
||||||
// Assumes final stage has been cleared already.
|
// Assumes final stage has been cleared already.
|
||||||
if (!final_target)
|
if (!final_target)
|
||||||
{
|
{
|
||||||
if (!g_gpu_device->BeginPresent(false))
|
if (const GPUDevice::PresentResult pres = g_gpu_device->BeginPresent(false); pres != GPUDevice::PresentResult::OK)
|
||||||
return false;
|
return pres;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -196,7 +197,7 @@ bool PostProcessing::GLSLShader::Apply(GPUTexture* input_color, GPUTexture* inpu
|
||||||
static_cast<float>(PostProcessing::GetTimer().GetTimeSeconds()));
|
static_cast<float>(PostProcessing::GetTimer().GetTimeSeconds()));
|
||||||
g_gpu_device->UnmapUniformBuffer(uniforms_size);
|
g_gpu_device->UnmapUniformBuffer(uniforms_size);
|
||||||
g_gpu_device->Draw(3, 0);
|
g_gpu_device->Draw(3, 0);
|
||||||
return true;
|
return GPUDevice::PresentResult::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PostProcessing::GLSLShader::ResizeOutput(GPUTexture::Format format, u32 width, u32 height)
|
bool PostProcessing::GLSLShader::ResizeOutput(GPUTexture::Format format, u32 width, u32 height)
|
||||||
|
|
|
@ -24,9 +24,9 @@ public:
|
||||||
|
|
||||||
bool ResizeOutput(GPUTexture::Format format, u32 width, u32 height) override;
|
bool ResizeOutput(GPUTexture::Format format, u32 width, u32 height) override;
|
||||||
bool CompilePipeline(GPUTexture::Format format, u32 width, u32 height, ProgressCallback* progress) override;
|
bool CompilePipeline(GPUTexture::Format format, u32 width, u32 height, ProgressCallback* progress) override;
|
||||||
bool Apply(GPUTexture* input_color, GPUTexture* input_depth, GPUTexture* final_target, GSVector4i final_rect,
|
GPUDevice::PresentResult Apply(GPUTexture* input_color, GPUTexture* input_depth, GPUTexture* final_target,
|
||||||
s32 orig_width, s32 orig_height, s32 native_width, s32 native_height, u32 target_width,
|
GSVector4i final_rect, s32 orig_width, s32 orig_height, s32 native_width,
|
||||||
u32 target_height) override;
|
s32 native_height, u32 target_width, u32 target_height) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct CommonUniforms
|
struct CommonUniforms
|
||||||
|
|
|
@ -1286,6 +1286,9 @@ bool VulkanDevice::SetGPUTimingEnabled(bool enabled)
|
||||||
|
|
||||||
void VulkanDevice::WaitForCommandBufferCompletion(u32 index)
|
void VulkanDevice::WaitForCommandBufferCompletion(u32 index)
|
||||||
{
|
{
|
||||||
|
if (m_device_was_lost)
|
||||||
|
return;
|
||||||
|
|
||||||
// Wait for this command buffer to be completed.
|
// Wait for this command buffer to be completed.
|
||||||
static constexpr u32 MAX_TIMEOUTS = 10;
|
static constexpr u32 MAX_TIMEOUTS = 10;
|
||||||
u32 timeouts = 0;
|
u32 timeouts = 0;
|
||||||
|
@ -1303,7 +1306,7 @@ void VulkanDevice::WaitForCommandBufferCompletion(u32 index)
|
||||||
else if (res != VK_SUCCESS)
|
else if (res != VK_SUCCESS)
|
||||||
{
|
{
|
||||||
LOG_VULKAN_ERROR(res, TinyString::from_format("vkWaitForFences() for cmdbuffer {} failed: ", index));
|
LOG_VULKAN_ERROR(res, TinyString::from_format("vkWaitForFences() for cmdbuffer {} failed: ", index));
|
||||||
m_device_is_lost = true;
|
m_device_was_lost = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1357,7 +1360,7 @@ void VulkanDevice::WaitForCommandBufferCompletion(u32 index)
|
||||||
|
|
||||||
void VulkanDevice::EndAndSubmitCommandBuffer(VulkanSwapChain* present_swap_chain, bool explicit_present)
|
void VulkanDevice::EndAndSubmitCommandBuffer(VulkanSwapChain* present_swap_chain, bool explicit_present)
|
||||||
{
|
{
|
||||||
if (m_device_is_lost)
|
if (m_device_was_lost) [[unlikely]]
|
||||||
return;
|
return;
|
||||||
|
|
||||||
CommandBuffer& resources = m_frame_resources[m_current_frame];
|
CommandBuffer& resources = m_frame_resources[m_current_frame];
|
||||||
|
@ -1416,7 +1419,7 @@ void VulkanDevice::EndAndSubmitCommandBuffer(VulkanSwapChain* present_swap_chain
|
||||||
if (res != VK_SUCCESS)
|
if (res != VK_SUCCESS)
|
||||||
{
|
{
|
||||||
LOG_VULKAN_ERROR(res, "vkQueueSubmit failed: ");
|
LOG_VULKAN_ERROR(res, "vkQueueSubmit failed: ");
|
||||||
m_device_is_lost = true;
|
m_device_was_lost = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2339,28 +2342,23 @@ void VulkanDevice::SetVSyncMode(GPUVSyncMode mode, bool allow_present_throttle)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VulkanDevice::BeginPresent(bool frame_skip, u32 clear_color)
|
GPUDevice::PresentResult VulkanDevice::BeginPresent(bool frame_skip, u32 clear_color)
|
||||||
{
|
{
|
||||||
if (InRenderPass())
|
if (InRenderPass())
|
||||||
EndRenderPass();
|
EndRenderPass();
|
||||||
|
|
||||||
|
if (m_device_was_lost) [[unlikely]]
|
||||||
|
return PresentResult::DeviceLost;
|
||||||
|
|
||||||
if (frame_skip)
|
if (frame_skip)
|
||||||
return false;
|
return PresentResult::SkipPresent;
|
||||||
|
|
||||||
// If we're running surfaceless, kick the command buffer so we don't run out of descriptors.
|
// If we're running surfaceless, kick the command buffer so we don't run out of descriptors.
|
||||||
if (!m_swap_chain)
|
if (!m_swap_chain)
|
||||||
{
|
{
|
||||||
SubmitCommandBuffer(false);
|
SubmitCommandBuffer(false);
|
||||||
TrimTexturePool();
|
TrimTexturePool();
|
||||||
return false;
|
return PresentResult::SkipPresent;
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the device was lost.
|
|
||||||
if (m_device_is_lost)
|
|
||||||
{
|
|
||||||
Panic("Fixme"); // TODO
|
|
||||||
TrimTexturePool();
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VkResult res = m_swap_chain->AcquireNextImage();
|
VkResult res = m_swap_chain->AcquireNextImage();
|
||||||
|
@ -2382,7 +2380,7 @@ bool VulkanDevice::BeginPresent(bool frame_skip, u32 clear_color)
|
||||||
ERROR_LOG("Failed to recreate surface after loss");
|
ERROR_LOG("Failed to recreate surface after loss");
|
||||||
SubmitCommandBuffer(false);
|
SubmitCommandBuffer(false);
|
||||||
TrimTexturePool();
|
TrimTexturePool();
|
||||||
return false;
|
return PresentResult::SkipPresent;
|
||||||
}
|
}
|
||||||
|
|
||||||
res = m_swap_chain->AcquireNextImage();
|
res = m_swap_chain->AcquireNextImage();
|
||||||
|
@ -2395,12 +2393,12 @@ bool VulkanDevice::BeginPresent(bool frame_skip, u32 clear_color)
|
||||||
// Still submit the command buffer, otherwise we'll end up with several frames waiting.
|
// Still submit the command buffer, otherwise we'll end up with several frames waiting.
|
||||||
SubmitCommandBuffer(false);
|
SubmitCommandBuffer(false);
|
||||||
TrimTexturePool();
|
TrimTexturePool();
|
||||||
return false;
|
return PresentResult::SkipPresent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BeginSwapChainRenderPass(clear_color);
|
BeginSwapChainRenderPass(clear_color);
|
||||||
return true;
|
return PresentResult::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanDevice::EndPresent(bool explicit_present)
|
void VulkanDevice::EndPresent(bool explicit_present)
|
||||||
|
@ -2421,6 +2419,9 @@ void VulkanDevice::EndPresent(bool explicit_present)
|
||||||
void VulkanDevice::SubmitPresent()
|
void VulkanDevice::SubmitPresent()
|
||||||
{
|
{
|
||||||
DebugAssert(m_swap_chain);
|
DebugAssert(m_swap_chain);
|
||||||
|
if (m_device_was_lost) [[unlikely]]
|
||||||
|
return;
|
||||||
|
|
||||||
QueuePresent(m_swap_chain.get());
|
QueuePresent(m_swap_chain.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -142,7 +142,7 @@ public:
|
||||||
|
|
||||||
void SetVSyncMode(GPUVSyncMode mode, bool allow_present_throttle) override;
|
void SetVSyncMode(GPUVSyncMode mode, bool allow_present_throttle) override;
|
||||||
|
|
||||||
bool BeginPresent(bool skip_present, u32 clear_color) override;
|
PresentResult BeginPresent(bool skip_present, u32 clear_color) override;
|
||||||
void EndPresent(bool explicit_present) override;
|
void EndPresent(bool explicit_present) override;
|
||||||
void SubmitPresent() override;
|
void SubmitPresent() override;
|
||||||
|
|
||||||
|
@ -414,7 +414,7 @@ private:
|
||||||
u64 m_completed_fence_counter = 0;
|
u64 m_completed_fence_counter = 0;
|
||||||
u32 m_current_frame = 0;
|
u32 m_current_frame = 0;
|
||||||
|
|
||||||
bool m_device_is_lost = false;
|
bool m_device_was_lost = false;
|
||||||
|
|
||||||
std::unordered_map<RenderPassCacheKey, VkRenderPass, RenderPassCacheKeyHash> m_render_pass_cache;
|
std::unordered_map<RenderPassCacheKey, VkRenderPass, RenderPassCacheKeyHash> m_render_pass_cache;
|
||||||
GPUFramebufferManager<VkFramebuffer, CreateFramebuffer, DestroyFramebuffer> m_framebuffer_manager;
|
GPUFramebufferManager<VkFramebuffer, CreateFramebuffer, DestroyFramebuffer> m_framebuffer_manager;
|
||||||
|
|
Loading…
Reference in a new issue