diff --git a/render/GpuRender/GpuRender.upp b/render/GpuRender/GpuRender.upp index 5f48979..168ee66 100644 --- a/render/GpuRender/GpuRender.upp +++ b/render/GpuRender/GpuRender.upp @@ -19,8 +19,6 @@ file GpuWindow.h, GpuWindow.cpp, RenderPresentation.h, - RenderPresentationBackend.h, RenderPresentation.cpp, - RenderPresentationVulkan.cpp, RenderCtrlBridge.h, RenderCtrlBridge.cpp; diff --git a/render/GpuRender/RenderPresentation.cpp b/render/GpuRender/RenderPresentation.cpp index 800ffcc..35cd417 100644 --- a/render/GpuRender/RenderPresentation.cpp +++ b/render/GpuRender/RenderPresentation.cpp @@ -1,53 +1,26 @@ #include "RenderPresentation.h" -#include "RenderPresentationBackend.h" + +#include +#include +#include namespace Upp { namespace { -struct BackendRegistration : Moveable { - GpuBackendKind kind = GpuBackendKind::Unknown; - GpuPresentationBackend *backend = nullptr; -}; - -static Vector& BackendRegistry() +static GpuClearColor ToClearColor(Rgba8 color) { - static Vector registry; - return registry; -} - -static int FindBackendIndex(GpuBackendKind kind) -{ - const Vector& registry = BackendRegistry(); - for(int i = 0; i < registry.GetCount(); ++i) - if(registry[i].kind == kind) - return i; - return -1; + const float scale = 1.0f / 255.0f; + GpuClearColor out; + out.red = color.r * scale; + out.green = color.g * scale; + out.blue = color.b * scale; + out.alpha = color.a * scale; + return out; } } // namespace -bool RegisterGpuPresentationBackend(GpuBackendKind kind, GpuPresentationBackend& backend) -{ - if(kind == GpuBackendKind::Unknown || FindBackendIndex(kind) >= 0) - return false; - BackendRegistration& registration = BackendRegistry().Add(); - registration.kind = kind; - registration.backend = &backend; - return true; -} - -GpuPresentationBackend *FindGpuPresentationBackend(GpuBackendKind kind) -{ - int index = FindBackendIndex(kind); - return index >= 0 ? BackendRegistry()[index].backend : nullptr; -} - -bool IsGpuPresentationBackendRegistered(GpuBackendKind kind) -{ - return FindGpuPresentationBackend(kind) != nullptr; -} - struct GpuContext::Impl { struct ContextEntry : Moveable { GpuBackendKind kind = GpuBackendKind::Unknown; @@ -99,9 +72,131 @@ GpuContext& GpuContext::Default() struct GpuDisplayPresenter::Impl { One session; + std::unique_ptr renderer; GpuContext *context = nullptr; GpuBackendKind backend = GpuBackendKind::Unknown; + GpuNativeWindowDesc native_window; + GpuSurfaceId surface; + GpuSwapchainId swapchain; + Size swapchain_request_size = Size(0, 0); String error; + + GpuDevice *GetDevice() const + { + return session ? session->GetDevice() : nullptr; + } + + void DestroyPresentationObjects() + { + renderer.reset(); + GpuDevice *device = GetDevice(); + if(device) { + if(swapchain.IsValid()) + device->DestroySwapchain(swapchain); + if(surface.IsValid()) + device->DestroySurface(surface); + } + swapchain = GpuSwapchainId(); + surface = GpuSurfaceId(); + swapchain_request_size = Size(0, 0); + native_window = GpuNativeWindowDesc(); + } + + bool EnsureSwapchain(Size requested_size, String& out_error) + { + GpuDevice *device = GetDevice(); + if(!device) { + error = "GPU presentation backend exposes no device"; + out_error = error; + return false; + } + + if(!surface.IsValid()) { + GpuSurfaceDesc desc; + desc.label = "GPU presentation surface"; + desc.size = requested_size; + desc.native_window = native_window; + GpuResult result = device->CreateSurface(desc, surface); + if(result != GpuResult::Ok) { + error = device->GetLastError(); + if(error.IsEmpty()) + error = "logical GPU surface creation failed"; + out_error = error; + return false; + } + } + + if(!swapchain.IsValid()) { + GpuSwapchainDesc desc; + desc.label = "GPU presentation swapchain"; + desc.surface = surface; + desc.size = requested_size; + desc.color_format = GpuFormat::RGBA8; + desc.image_count = 2; + GpuResult result = device->CreateSwapchain(desc, swapchain); + if(result != GpuResult::Ok) { + error = device->GetLastError(); + if(error.IsEmpty()) + error = "logical GPU swapchain creation failed"; + out_error = error; + return false; + } + swapchain_request_size = requested_size; + } + else if(requested_size != swapchain_request_size) { + GpuResult result = device->ResizeSwapchain(swapchain, requested_size); + if(result != GpuResult::Ok) { + error = device->GetLastError(); + if(error.IsEmpty()) + error = "logical GPU swapchain resize failed"; + out_error = error; + return false; + } + swapchain_request_size = requested_size; + } + return true; + } + + GpuResult PresentOnce(const UiDisplayList& list, Rgba8 background, String& out_error) + { + GpuDevice *device = GetDevice(); + if(!device || !renderer) { + error = "GPU presentation session is not ready"; + out_error = error; + return GpuResult::InvalidState; + } + + GpuFrameInfo frame; + GpuResult result = device->BeginFrame(swapchain, frame); + if(result != GpuResult::Ok) { + error = device->GetLastError(); + if(error.IsEmpty()) + error = "GPU BeginFrame failed"; + out_error = error; + return result; + } + + if(!renderer->RenderFrame(list, frame, ToClearColor(background))) { + String render_error = renderer->GetError(); + device->Present(frame.frame); // Release the acquired frame on the failure path. + error = render_error.IsEmpty() ? String("UiRenderer2D frame render failed") : render_error; + out_error = error; + return GpuResult::InvalidState; + } + + result = device->Present(frame.frame); + if(result != GpuResult::Ok) { + error = device->GetLastError(); + if(error.IsEmpty()) + error = "GPU Present failed"; + out_error = error; + return result; + } + + error.Clear(); + out_error.Clear(); + return GpuResult::Ok; + } }; GpuDisplayPresenter::GpuDisplayPresenter() @@ -130,6 +225,7 @@ bool GpuDisplayPresenter::Open(GpuContext& context, GpuBackendKind backend, out_error.Clear(); impl->context = &context; impl->backend = backend; + impl->native_window = native_window; GpuPresentationBackend *provider = FindGpuPresentationBackend(backend); if(!provider) { @@ -171,6 +267,27 @@ bool GpuDisplayPresenter::Open(GpuContext& context, GpuBackendKind backend, impl->session.Clear(); return false; } + + GpuDevice *device = impl->GetDevice(); + if(!device || device->GetBackendKind() != backend) { + impl->error = "GPU presentation backend returned an incompatible device"; + out_error = impl->error; + impl->session->Close(); + impl->session.Clear(); + return false; + } + + impl->renderer.reset(new UiRenderer2D(*device)); + if(!impl->renderer->IsReady()) { + String failure = impl->renderer->GetError(); + impl->renderer.reset(); + impl->session->Close(); + impl->session.Clear(); + impl->error = failure.IsEmpty() ? String("UiRenderer2D initialization failed") : failure; + out_error = impl->error; + return false; + } + impl->error.Clear(); out_error.Clear(); return true; @@ -180,6 +297,7 @@ void GpuDisplayPresenter::Close() { if(!impl) return; + impl->DestroyPresentationObjects(); if(impl->session) impl->session->Close(); impl->session.Clear(); @@ -190,7 +308,8 @@ void GpuDisplayPresenter::Close() bool GpuDisplayPresenter::IsReady() const { - return impl && impl->session && impl->session->IsReady(); + return impl && impl->session && impl->session->IsReady() && impl->GetDevice() && + impl->renderer && impl->renderer->IsReady(); } GpuBackendKind GpuDisplayPresenter::GetBackend() const @@ -211,6 +330,8 @@ bool GpuDisplayPresenter::Present(Size requested_size, const UiDisplayList& list Rgba8 background, String& out_error) { out_error.Clear(); + if(requested_size.cx <= 0 || requested_size.cy <= 0) + return true; if(!IsReady()) { impl->error = GetError(); if(impl->error.IsEmpty()) @@ -218,14 +339,25 @@ bool GpuDisplayPresenter::Present(Size requested_size, const UiDisplayList& list out_error = impl->error; return false; } - if(!impl->session->Present(requested_size, list, background, out_error)) { - impl->error = out_error.IsEmpty() ? impl->session->GetError() : out_error; + if(!impl->EnsureSwapchain(requested_size, out_error)) + return false; + + GpuResult result = impl->PresentOnce(list, background, out_error); + if(result == GpuResult::Ok) + return true; + if(result != GpuResult::OutOfDate) + return false; + + GpuDevice *device = impl->GetDevice(); + if(!device || device->ResizeSwapchain(impl->swapchain, requested_size) != GpuResult::Ok) { + impl->error = device ? device->GetLastError() : String(); + if(impl->error.IsEmpty()) + impl->error = "GPU swapchain recreation after out-of-date presentation failed"; out_error = impl->error; return false; } - impl->error.Clear(); - out_error.Clear(); - return true; + impl->swapchain_request_size = requested_size; + return impl->PresentOnce(list, background, out_error) == GpuResult::Ok; } } diff --git a/render/GpuRender/RenderPresentationVulkan.cpp b/render/GpuRender/RenderPresentationVulkan.cpp deleted file mode 100644 index 36ce193..0000000 --- a/render/GpuRender/RenderPresentationVulkan.cpp +++ /dev/null @@ -1,253 +0,0 @@ -#include "RenderPresentationBackend.h" - -#include -#include - -#include - -namespace Upp { - -namespace { - -static GpuClearColor ToClearColor(Rgba8 color) -{ - const float scale = 1.0f / 255.0f; - GpuClearColor out; - out.red = color.r * scale; - out.green = color.g * scale; - out.blue = color.b * scale; - out.alpha = color.a * scale; - return out; -} - -class VulkanPresentationContext : public GpuPresentationBackendContext { -public: - VulkanSurfaceSessionGroup group; -}; - -class VulkanPresentationSession : public GpuPresentationBackendSession { -public: - explicit VulkanPresentationSession(VulkanPresentationContext& context) - : session(context.group) - { - } - - ~VulkanPresentationSession() override - { - Close(); - } - - bool Open(bool request_validation, const GpuNativeWindowDesc& window, - String& out_error) override - { - Close(); - error.Clear(); - native_window = window; - if(!session.Open(request_validation, native_window)) { - error = session.GetError(); - out_error = error; - return false; - } - - device.reset(new VulkanGpuDevice(session)); - if(!device->IsReady()) { - String failure = device->GetError(); - Close(); - error = failure.IsEmpty() ? String("VulkanGpuDevice initialization failed") : failure; - out_error = error; - return false; - } - - renderer.reset(new UiRenderer2D(*device)); - if(!renderer->IsReady()) { - String failure = renderer->GetError(); - Close(); - error = failure.IsEmpty() ? String("UiRenderer2D initialization failed") : failure; - out_error = error; - return false; - } - - out_error.Clear(); - return true; - } - - void Close() override - { - renderer.reset(); - if(device) { - if(swapchain.IsValid()) - device->DestroySwapchain(swapchain); - swapchain = GpuSwapchainId(); - if(surface.IsValid()) - device->DestroySurface(surface); - surface = GpuSurfaceId(); - } - device.reset(); - session.Close(); - native_window = GpuNativeWindowDesc(); - swapchain_request_size = Size(0, 0); - error.Clear(); - } - - bool IsReady() const override - { - return session.IsReady() && device && device->IsReady() && - renderer && renderer->IsReady(); - } - - String GetError() const override - { - return error; - } - - bool Present(Size requested_size, const UiDisplayList& list, - Rgba8 background, String& out_error) override - { - out_error.Clear(); - if(requested_size.cx <= 0 || requested_size.cy <= 0) - return true; - if(!IsReady()) { - error = !device ? session.GetError() : device->GetError(); - if(error.IsEmpty()) - error = "GPU presentation session is not ready"; - out_error = error; - return false; - } - if(!EnsureSwapchain(requested_size, out_error)) - return false; - if(PresentOnce(list, background, out_error)) - return true; - - if(!session.GetFrameReport().out_of_date) - return false; - if(device->ResizeSwapchain(swapchain, requested_size) != GpuResult::Ok) { - error = device->GetError(); - if(error.IsEmpty()) - error = "GPU swapchain recreation after out-of-date presentation failed"; - out_error = error; - return false; - } - swapchain_request_size = requested_size; - if(PresentOnce(list, background, out_error)) { - out_error.Clear(); - return true; - } - return false; - } - -private: - bool EnsureSwapchain(Size requested_size, String& out_error) - { - if(!surface.IsValid()) { - GpuSurfaceDesc desc; - desc.label = "GPU presentation surface"; - desc.size = requested_size; - desc.native_window = native_window; - GpuResult result = device->CreateSurface(desc, surface); - if(result != GpuResult::Ok) { - error = device->GetError(); - if(error.IsEmpty()) - error = "logical GPU surface creation failed"; - out_error = error; - return false; - } - } - - if(!swapchain.IsValid()) { - GpuSwapchainDesc desc; - desc.label = "GPU presentation swapchain"; - desc.surface = surface; - desc.size = requested_size; - desc.color_format = GpuFormat::RGBA8; - desc.image_count = 2; - GpuResult result = device->CreateSwapchain(desc, swapchain); - if(result != GpuResult::Ok) { - error = device->GetError(); - if(error.IsEmpty()) - error = "logical GPU swapchain creation failed"; - out_error = error; - return false; - } - swapchain_request_size = requested_size; - } - else if(requested_size != swapchain_request_size) { - GpuResult result = device->ResizeSwapchain(swapchain, requested_size); - if(result != GpuResult::Ok) { - error = device->GetError(); - if(error.IsEmpty()) - error = "logical GPU swapchain resize failed"; - out_error = error; - return false; - } - swapchain_request_size = requested_size; - } - return true; - } - - bool PresentOnce(const UiDisplayList& list, Rgba8 background, String& out_error) - { - GpuFrameInfo frame; - GpuResult result = device->BeginFrame(swapchain, frame); - if(result != GpuResult::Ok) { - error = device->GetError(); - if(error.IsEmpty()) - error = "GPU BeginFrame failed"; - out_error = error; - return false; - } - - if(!renderer->RenderFrame(list, frame, ToClearColor(background))) { - String render_error = renderer->GetError(); - device->Present(frame.frame); - error = render_error.IsEmpty() ? String("UiRenderer2D frame render failed") : render_error; - out_error = error; - return false; - } - - result = device->Present(frame.frame); - if(result != GpuResult::Ok) { - error = device->GetError(); - if(error.IsEmpty()) - error = "GPU Present failed"; - out_error = error; - return false; - } - - error.Clear(); - out_error.Clear(); - return true; - } - - VulkanSurfaceSession session; - std::unique_ptr device; - std::unique_ptr renderer; - GpuNativeWindowDesc native_window; - GpuSurfaceId surface; - GpuSwapchainId swapchain; - Size swapchain_request_size = Size(0, 0); - String error; -}; - -class VulkanPresentationBackend : public GpuPresentationBackend { -public: - One CreateContext(String& error) override - { - error.Clear(); - return new VulkanPresentationContext; - } - - One CreateSession(GpuPresentationBackendContext& context, - String& error) override - { - error.Clear(); - return new VulkanPresentationSession(static_cast(context)); - } -}; - -static VulkanPresentationBackend s_vulkan_backend; -static bool s_vulkan_backend_registered = - RegisterGpuPresentationBackend(GpuBackendKind::Vulkan, s_vulkan_backend); - -} // namespace - -} diff --git a/render/RenderRhi/RenderRhi.cpp b/render/RenderRhi/RenderRhi.cpp index b97a198..8be9518 100644 --- a/render/RenderRhi/RenderRhi.cpp +++ b/render/RenderRhi/RenderRhi.cpp @@ -196,6 +196,7 @@ String DumpGpuResult(GpuResult result) case GpuResult::InvalidArgument: return "InvalidArgument"; case GpuResult::InvalidHandle: return "InvalidHandle"; case GpuResult::InvalidState: return "InvalidState"; + case GpuResult::OutOfDate: return "OutOfDate"; case GpuResult::NotFound: return "NotFound"; case GpuResult::Unsupported: return "Unsupported"; } diff --git a/render/RenderRhi/RenderRhi.h b/render/RenderRhi/RenderRhi.h index b0d4e1b..6a32baf 100644 --- a/render/RenderRhi/RenderRhi.h +++ b/render/RenderRhi/RenderRhi.h @@ -108,6 +108,7 @@ enum class GpuResult { InvalidArgument, InvalidHandle, InvalidState, + OutOfDate, NotFound, Unsupported, }; @@ -253,6 +254,7 @@ class GpuDevice { virtual GpuDeviceId GetDeviceId() const = 0; virtual GpuBackendKind GetBackendKind() const = 0; virtual GpuAdapterInfo GetAdapterInfo() const = 0; + virtual String GetLastError() const { return String(); } virtual GpuResult CreateBuffer(const GpuBufferDesc& desc, GpuBufferId& out) = 0; virtual GpuResult WriteBuffer(GpuBufferId id, int64 offset, const void *data, int64 size) = 0; diff --git a/render/RenderRhi/RenderRhi.upp b/render/RenderRhi/RenderRhi.upp index 129e72a..0d80806 100644 --- a/render/RenderRhi/RenderRhi.upp +++ b/render/RenderRhi/RenderRhi.upp @@ -3,4 +3,6 @@ uses file RenderRhi.h, - RenderRhi.cpp; + RenderRhiBackend.h, + RenderRhi.cpp, + RenderRhiBackend.cpp; diff --git a/render/RenderRhi/RenderRhiBackend.cpp b/render/RenderRhi/RenderRhiBackend.cpp new file mode 100644 index 0000000..8dcceae --- /dev/null +++ b/render/RenderRhi/RenderRhiBackend.cpp @@ -0,0 +1,50 @@ +#include "RenderRhiBackend.h" + +namespace Upp { + +namespace { + +struct BackendRegistration : Moveable { + GpuBackendKind kind = GpuBackendKind::Unknown; + GpuPresentationBackend *backend = nullptr; +}; + +static Vector& BackendRegistry() +{ + static Vector registry; + return registry; +} + +static int FindBackendIndex(GpuBackendKind kind) +{ + const Vector& registry = BackendRegistry(); + for(int i = 0; i < registry.GetCount(); ++i) + if(registry[i].kind == kind) + return i; + return -1; +} + +} // namespace + +bool RegisterGpuPresentationBackend(GpuBackendKind kind, GpuPresentationBackend& backend) +{ + if(kind == GpuBackendKind::Unknown || FindBackendIndex(kind) >= 0) + return false; + BackendRegistration& registration = BackendRegistry().Add(); + registration.kind = kind; + registration.backend = &backend; + return true; +} + +GpuPresentationBackend *FindGpuPresentationBackend(GpuBackendKind kind) +{ + int index = FindBackendIndex(kind); + return index >= 0 ? BackendRegistry()[index].backend : nullptr; +} + +bool IsGpuPresentationBackendRegistered(GpuBackendKind kind) +{ + return FindGpuPresentationBackend(kind) != nullptr; +} + +} diff --git a/render/GpuRender/RenderPresentationBackend.h b/render/RenderRhi/RenderRhiBackend.h similarity index 66% rename from render/GpuRender/RenderPresentationBackend.h rename to render/RenderRhi/RenderRhiBackend.h index 2c0804f..2fd8839 100644 --- a/render/GpuRender/RenderPresentationBackend.h +++ b/render/RenderRhi/RenderRhiBackend.h @@ -1,12 +1,11 @@ #pragma once -#include "RenderPresentation.h" +#include namespace Upp { -// Internal backend plug-in seam for GpuRender presentation. -// Application-facing GpuCtrl/GpuWindow/GpuTopWindow code never depends on this -// interface and never sees backend-native types. +// Internal provider seam between application presentation and a compiled GPU backend. +// It contains no backend-native types and deliberately stops at the neutral GpuDevice. class GpuPresentationBackendContext { public: virtual ~GpuPresentationBackendContext() {} @@ -21,8 +20,7 @@ class GpuPresentationBackendSession { virtual void Close() = 0; virtual bool IsReady() const = 0; virtual String GetError() const = 0; - virtual bool Present(Size requested_size, const UiDisplayList& list, - Rgba8 background, String& error) = 0; + virtual GpuDevice *GetDevice() const = 0; }; class GpuPresentationBackend { @@ -34,8 +32,8 @@ class GpuPresentationBackend { String& error) = 0; }; -// Registration is intended for compiled backend packages during process start. -// One provider owns each backend kind; duplicate registration is rejected. +// Compiled backend packages register during process start. One provider owns each +// backend kind; duplicate registration and Unknown are rejected. bool RegisterGpuPresentationBackend(GpuBackendKind kind, GpuPresentationBackend& backend); GpuPresentationBackend *FindGpuPresentationBackend(GpuBackendKind kind); bool IsGpuPresentationBackendRegistered(GpuBackendKind kind); diff --git a/render/RenderVulkan/RenderVulkan.upp b/render/RenderVulkan/RenderVulkan.upp index 6b96963..df0d33e 100644 --- a/render/RenderVulkan/RenderVulkan.upp +++ b/render/RenderVulkan/RenderVulkan.upp @@ -11,4 +11,5 @@ file RenderVulkanFrame.cpp, RenderVulkanClearFrame.cpp, RenderVulkanRhiBase.inc, - RenderVulkanRhi.cpp; + RenderVulkanRhi.cpp, + RenderVulkanPresentation.cpp; diff --git a/render/RenderVulkan/RenderVulkanPresentation.cpp b/render/RenderVulkan/RenderVulkanPresentation.cpp new file mode 100644 index 0000000..0222c7a --- /dev/null +++ b/render/RenderVulkan/RenderVulkanPresentation.cpp @@ -0,0 +1,106 @@ +#include "RenderVulkanRhi.h" + +#include +#include + +namespace Upp { + +namespace { + +class VulkanPresentationContext : public GpuPresentationBackendContext { +public: + VulkanSurfaceSessionGroup group; +}; + +class VulkanPresentationSession : public GpuPresentationBackendSession { +public: + explicit VulkanPresentationSession(VulkanPresentationContext& context) + : session(context.group) + { + } + + ~VulkanPresentationSession() override + { + Close(); + } + + bool Open(bool request_validation, const GpuNativeWindowDesc& native_window, + String& out_error) override + { + Close(); + error.Clear(); + out_error.Clear(); + if(!session.Open(request_validation, native_window)) { + error = session.GetError(); + out_error = error; + return false; + } + + device.reset(new VulkanGpuDevice(session)); + if(!device->IsReady()) { + String failure = device->GetError(); + device.reset(); + session.Close(); + error = failure.IsEmpty() ? String("VulkanGpuDevice initialization failed") : failure; + out_error = error; + return false; + } + + return true; + } + + void Close() override + { + device.reset(); + session.Close(); + error.Clear(); + } + + bool IsReady() const override + { + return session.IsReady() && device && device->IsReady(); + } + + String GetError() const override + { + if(!error.IsEmpty()) + return error; + if(device && !device->GetError().IsEmpty()) + return device->GetError(); + return session.GetError(); + } + + GpuDevice *GetDevice() const override + { + return IsReady() ? device.get() : nullptr; + } + +private: + VulkanSurfaceSession session; + std::unique_ptr device; + String error; +}; + +class VulkanPresentationBackend : public GpuPresentationBackend { +public: + One CreateContext(String& error) override + { + error.Clear(); + return new VulkanPresentationContext; + } + + One CreateSession(GpuPresentationBackendContext& context, + String& error) override + { + error.Clear(); + return new VulkanPresentationSession(static_cast(context)); + } +}; + +static VulkanPresentationBackend s_vulkan_backend; +static bool s_vulkan_backend_registered = + RegisterGpuPresentationBackend(GpuBackendKind::Vulkan, s_vulkan_backend); + +} // namespace + +} diff --git a/render/RenderVulkan/RenderVulkanRhi.h b/render/RenderVulkan/RenderVulkanRhi.h index 014d668..e0ea213 100644 --- a/render/RenderVulkan/RenderVulkanRhi.h +++ b/render/RenderVulkan/RenderVulkanRhi.h @@ -31,6 +31,7 @@ class VulkanGpuDevice final : public GpuDevice { GpuDeviceId GetDeviceId() const override; GpuBackendKind GetBackendKind() const override; GpuAdapterInfo GetAdapterInfo() const override; + String GetLastError() const override; GpuResult CreateBuffer(const GpuBufferDesc& desc, GpuBufferId& out) override; GpuResult WriteBuffer(GpuBufferId id, int64 offset, const void *data, int64 size) override; diff --git a/render/RenderVulkan/RenderVulkanRhiBase.inc b/render/RenderVulkan/RenderVulkanRhiBase.inc index ad6b1b9..b770273 100644 --- a/render/RenderVulkan/RenderVulkanRhiBase.inc +++ b/render/RenderVulkan/RenderVulkanRhiBase.inc @@ -893,6 +893,7 @@ int VulkanGpuDevice::GetLiveFrameCount() const GpuDeviceId VulkanGpuDevice::GetDeviceId() const { return impl->device_id; } GpuBackendKind VulkanGpuDevice::GetBackendKind() const { return GpuBackendKind::Vulkan; } GpuAdapterInfo VulkanGpuDevice::GetAdapterInfo() const { return impl->adapter_info; } +String VulkanGpuDevice::GetLastError() const { return impl ? impl->error : String(); } GpuResult VulkanGpuDevice::CreateBuffer(const GpuBufferDesc& desc, GpuBufferId& out) { @@ -1150,7 +1151,7 @@ GpuResult VulkanGpuDevice::BeginFrame(GpuSwapchainId swapchain, GpuFrameInfo& ou if(!impl->session->AcquireFrame()) { impl->error = impl->session->GetFrameReport().error; if(impl->error.IsEmpty()) impl->error = "VulkanSurfaceSession frame acquisition failed"; - return GpuResult::InvalidState; + return impl->session->GetFrameReport().out_of_date ? GpuResult::OutOfDate : GpuResult::InvalidState; } VulkanSurfaceSession::FrameInterop interop; uint32_t image_index = UINT32_MAX; @@ -1205,7 +1206,7 @@ GpuResult VulkanGpuDevice::Present(GpuFrameId frame) state->active = false; swapchain->active_frame = GpuFrameId(); } - return GpuResult::InvalidState; + return impl->session->GetFrameReport().out_of_date ? GpuResult::OutOfDate : GpuResult::InvalidState; } Impl::TextureState *texture = impl->FindTexture(state->color_target); if(texture) impl->ClearBorrowedTexture(*texture); diff --git a/tests/GpuBackendRegistryTest/main.cpp b/tests/GpuBackendRegistryTest/main.cpp index bdb0d9c..e122a33 100644 --- a/tests/GpuBackendRegistryTest/main.cpp +++ b/tests/GpuBackendRegistryTest/main.cpp @@ -1,4 +1,4 @@ -#include +#include using namespace Upp;