From e891fa11f57da6d9915ca42c18b7e5bb90489fc2 Mon Sep 17 00:00:00 2001 From: kkEngine <78795688+kkEngine@users.noreply.github.com> Date: Mon, 29 Dec 2025 14:27:45 +0300 Subject: [PATCH 1/3] - Added sync render classes - Added command line switch for possible future use --- src/UIPlatform/CEF/NirnLabCefApp.cpp | 3 + src/UIPlatform/CEF/NirnLabCefClient.cpp | 2 +- src/UIPlatform/CEF/NirnLabCefClient.h | 4 +- .../Render/CEFSyncCopyRenderLayer.cpp | 210 ++++++++++++++++++ .../Render/CEFSyncCopyRenderLayer.h | 46 ++++ 5 files changed, 262 insertions(+), 3 deletions(-) create mode 100644 src/UIPlatform/Render/CEFSyncCopyRenderLayer.cpp create mode 100644 src/UIPlatform/Render/CEFSyncCopyRenderLayer.h diff --git a/src/UIPlatform/CEF/NirnLabCefApp.cpp b/src/UIPlatform/CEF/NirnLabCefApp.cpp index ab2d94b..ed53f96 100644 --- a/src/UIPlatform/CEF/NirnLabCefApp.cpp +++ b/src/UIPlatform/CEF/NirnLabCefApp.cpp @@ -39,6 +39,9 @@ namespace NL::CEF // command_line->AppendSwitch("disable-gpu-vsync"); + // Disables lazy loading of images and frames + // command_line->AppendSwitch("disable-lazy-loading"); + // Most systems would not need to use this switch - but on older hardware, // Chromium may still choose to disable D3D11 for gpu workarounds. // Accelerated OSR will not at all with D3D11 disabled, so we force it on. diff --git a/src/UIPlatform/CEF/NirnLabCefClient.cpp b/src/UIPlatform/CEF/NirnLabCefClient.cpp index d12ed62..5e06cf8 100644 --- a/src/UIPlatform/CEF/NirnLabCefClient.cpp +++ b/src/UIPlatform/CEF/NirnLabCefClient.cpp @@ -4,7 +4,7 @@ namespace NL::CEF { NirnLabCefClient::NirnLabCefClient() { - m_cefRenderLayer = NL::Render::CEFCopyRenderLayer::make_shared(); + m_cefRenderLayer = NL::Render::CEFSyncCopyRenderLayer::make_shared(); } std::shared_ptr NirnLabCefClient::GetRenderLayer() diff --git a/src/UIPlatform/CEF/NirnLabCefClient.h b/src/UIPlatform/CEF/NirnLabCefClient.h index 257efd7..e06bc17 100644 --- a/src/UIPlatform/CEF/NirnLabCefClient.h +++ b/src/UIPlatform/CEF/NirnLabCefClient.h @@ -1,7 +1,7 @@ #pragma once #include "PCH.h" -#include "Render/CEFCopyRenderLayer.h" +#include "Render/CEFSyncCopyRenderLayer.h" #include "Render/CEFRenderLayer.h" namespace NL::CEF @@ -14,7 +14,7 @@ namespace NL::CEF IMPLEMENT_REFCOUNTING(NirnLabCefClient); protected: - std::shared_ptr m_cefRenderLayer = nullptr; + std::shared_ptr m_cefRenderLayer = nullptr; CefRefPtr m_cefBrowser = nullptr; public: diff --git a/src/UIPlatform/Render/CEFSyncCopyRenderLayer.cpp b/src/UIPlatform/Render/CEFSyncCopyRenderLayer.cpp new file mode 100644 index 0000000..eea012c --- /dev/null +++ b/src/UIPlatform/Render/CEFSyncCopyRenderLayer.cpp @@ -0,0 +1,210 @@ +#include "CEFSyncCopyRenderLayer.h" + +namespace NL::Render +{ + std::shared_ptr CEFSyncCopyRenderLayer::make_shared() + { + const auto cefRender = new CEFSyncCopyRenderLayer(); + cefRender->AddRef(); + return std::shared_ptr(cefRender, CEFSyncCopyRenderLayer::release_shared); + } + + void CEFSyncCopyRenderLayer::release_shared(CEFSyncCopyRenderLayer* a_render) + { + a_render->Release(); + } + + void CEFSyncCopyRenderLayer::Init(RenderData* a_renderData) + { + IRenderLayer::Init(a_renderData); + + const auto hr = m_renderData->device->QueryInterface(IID_PPV_ARGS(&m_device1)); + if (FAILED(hr)) + { + spdlog::error("CEFSyncCopyRenderLayer::Init() - failed QueryInterface(), code {:X}", hr); + } + } + + const inline ::DirectX::SimpleMath::Vector2 _Cef_Menu_Draw_Vector = {0.f, 0.f}; + void CEFSyncCopyRenderLayer::Draw() + { + if (!m_isVisible) + { + return; + } + + if (m_renderData->deviceContext->GetType() == D3D11_DEVICE_CONTEXT_DEFERRED) + { + spdlog::error("D3D11_DEVICE_CONTEXT_DEFERRED_____________________"); + return; + } + + if (!m_acceleratedPaintReady.test(std::memory_order_acquire)) + { + if (m_cefSRV != nullptr) + { + m_renderData->spriteBatch->Draw( + m_cefSRV.Get(), + _Cef_Menu_Draw_Vector, + nullptr, + ::DirectX::Colors::White, + 0.f); + } + + return; + } + + Microsoft::WRL::ComPtr sharedTexture = nullptr; + auto hr = m_device1->OpenSharedResource1(m_acceleratedPaintInfo->shared_texture_handle, IID_PPV_ARGS(sharedTexture.ReleaseAndGetAddressOf())); + if (FAILED(hr)) + { + _com_error err(hr); + LPCTSTR errMsg = err.ErrorMessage(); + spdlog::error("CEFSyncCopyRenderLayer::Draw() - failed to OpenSharedResource1(), unexpected HRESULT {:#X}: {}", static_cast(hr), errMsg); + m_acceleratedPaintReady.clear(std::memory_order_release); + m_acceleratedPaintReady.notify_all(); + return; + } + + if (m_cefSRV == nullptr) + { + D3D11_TEXTURE2D_DESC sharedTextureDesc = {}; + sharedTexture->GetDesc(&sharedTextureDesc); + + auto hResult = m_renderData->device->CreateTexture2D(&sharedTextureDesc, nullptr, m_cefTexture.ReleaseAndGetAddressOf()); + if (FAILED(hResult)) + { + spdlog::error("CEFSyncCopyRenderLayer::Draw() - failed CreateTexture2D(), code {:X}", hResult); + return; + } + + D3D11_SHADER_RESOURCE_VIEW_DESC sharedResourceViewDesc = {}; + sharedResourceViewDesc.Format = sharedTextureDesc.Format; + sharedResourceViewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; + sharedResourceViewDesc.Texture2D.MostDetailedMip = 0; + sharedResourceViewDesc.Texture2D.MipLevels = 1; + + hResult = m_renderData->device->CreateShaderResourceView(m_cefTexture.Get(), &sharedResourceViewDesc, m_cefSRV.ReleaseAndGetAddressOf()); + if (FAILED(hResult)) + { + spdlog::error("CEFSyncCopyRenderLayer::Draw() - failed CreateShaderResourceView(), code {:X}", hResult); + return; + } + + spdlog::info("CEFSyncCopyRenderLayer::Draw() - texture created"); + } + + m_renderData->deviceContext->CopyResource(m_cefTexture.Get(), sharedTexture.Get()); + // The CopyResource call is asynchronous by default + m_renderData->deviceContext->Flush(); + + D3D11_QUERY_DESC QueryDesc = {}; + QueryDesc.Query = D3D11_QUERY_EVENT; + QueryDesc.MiscFlags = 0; + Microsoft::WRL::ComPtr Query; + if (HRESULT hr = m_device1->CreateQuery(&QueryDesc, &Query); FAILED(hr)) + { + spdlog::error("CEFSyncCopyRenderLayer::Draw() - falied CreateQuery(), code {:X}", hr); + return; + } + m_renderData->deviceContext->End(Query.Get()); + + while (S_FALSE == m_renderData->deviceContext->GetData(Query.Get(), NULL, 0, 0)) + { + // Optional: Sleep briefly to prevent a 100% CPU core usage busy-wait + // Sleep(1); + } + + //bool isDone = false; + //hr = S_OK; + //for (;;) + //{ + // hr = m_renderData->deviceContext->GetData(Query.Get(), &isDone, sizeof(isDone), 0); + // if (FAILED(hr)) + // { + // _com_error err(hr); + // LPCTSTR errMsg = err.ErrorMessage(); + // spdlog::error("CEFSyncCopyRenderLayer::Draw() - falied GetData(), code {:#X}: {}", static_cast(hr), errMsg); + // m_acceleratedPaintReady.clear(std::memory_order_release); + // m_acceleratedPaintReady.notify_all(); + // return; + // } + // + // // We need to check for S_OK specifically as S_FALSE is also considered a success return code + // if (hr == S_OK && isDone) + // { + // break; + // } + //} + + m_renderData->spriteBatch->Draw( + m_cefSRV.Get(), + _Cef_Menu_Draw_Vector, + nullptr, + ::DirectX::Colors::White, + 0.f); + + m_acceleratedPaintReady.clear(std::memory_order_release); + m_acceleratedPaintReady.notify_all(); + } + + void CEFSyncCopyRenderLayer::GetViewRect(CefRefPtr browser, CefRect& rect) + { + if (m_renderData) + { + rect.x = 0; + rect.y = 0; + rect.width = m_renderData->width; + rect.height = m_renderData->height; + } + else + { + rect.x = 0; + rect.y = 0; + rect.width = 800; + rect.height = 600; + } + } + + void CEFSyncCopyRenderLayer::OnPaint(CefRefPtr browser, + PaintElementType type, + const RectList& dirtyRects, + const void* buffer, + int width, + int height) + { + } + + void CEFSyncCopyRenderLayer::OnAcceleratedPaint(CefRefPtr browser, + PaintElementType type, + const RectList& dirtyRects, + const CefAcceleratedPaintInfo& info) + { + if (type == PaintElementType::PET_POPUP) + { + return; + } + + if (m_renderData == nullptr || + m_device1 == nullptr || + info.shared_texture_handle == nullptr) + { + spdlog::error("CEFSyncCopyRenderLayer::OnAcceleratedPaint() - device or renderData is nullptr"); + return; + } + + m_acceleratedPaintReady.test_and_set(std::memory_order_acquire); + + // while (m_acceleratedPaintReady.test_and_set(std::memory_order_acquire)) + //{ + // m_acceleratedPaintReady.wait(true, std::memory_order_relaxed); + // } + + m_acceleratedPaintInfo = &info; + + // m_acceleratedPaintReady.clear(std::memory_order_release); + m_acceleratedPaintReady.wait(true, std::memory_order_acquire); + + spdlog::info("OnAcceleratedPaint"); + } +} diff --git a/src/UIPlatform/Render/CEFSyncCopyRenderLayer.h b/src/UIPlatform/Render/CEFSyncCopyRenderLayer.h new file mode 100644 index 0000000..e2859fc --- /dev/null +++ b/src/UIPlatform/Render/CEFSyncCopyRenderLayer.h @@ -0,0 +1,46 @@ +#pragma once + +#include "PCH.h" +#include "IRenderLayer.h" + +namespace NL::Render +{ + class CEFSyncCopyRenderLayer : public IRenderLayer, + public CefRenderHandler + { + IMPLEMENT_REFCOUNTING(CEFSyncCopyRenderLayer); + + public: + static std::shared_ptr make_shared(); + static void release_shared(CEFSyncCopyRenderLayer* a_render); + + protected: + Microsoft::WRL::ComPtr m_device1 = nullptr; + Microsoft::WRL::ComPtr m_cefTexture = nullptr; + Microsoft::WRL::ComPtr m_cefSRV = nullptr; + const CefAcceleratedPaintInfo* m_acceleratedPaintInfo = nullptr; + std::atomic_flag m_acceleratedPaintReady = ATOMIC_FLAG_INIT; + + public: + ~CEFSyncCopyRenderLayer() override = default; + + // IRenderLayer + void Init(RenderData* a_renderData) override; + void Draw() override; + + // CefRenderHandler + void GetViewRect(CefRefPtr browser, CefRect& rect) override; + void OnPaint( + CefRefPtr browser, + PaintElementType type, + const RectList& dirtyRects, + const void* buffer, + int width, + int height) override; + void OnAcceleratedPaint( + CefRefPtr browser, + PaintElementType type, + const RectList& dirtyRects, + const CefAcceleratedPaintInfo& info) override; + }; +} From 428c3b321d7305d40f1dd972814cd34e3a3d1172 Mon Sep 17 00:00:00 2001 From: kkEngine <78795688+kkEngine@users.noreply.github.com> Date: Mon, 29 Dec 2025 17:12:23 +0300 Subject: [PATCH 2/3] - Refactoring and optimization --- .../Render/CEFSyncCopyRenderLayer.cpp | 187 +++++++----------- .../Render/CEFSyncCopyRenderLayer.h | 2 + src/UIPlatform/Utils/CheckHresult.h | 10 + 3 files changed, 82 insertions(+), 117 deletions(-) diff --git a/src/UIPlatform/Render/CEFSyncCopyRenderLayer.cpp b/src/UIPlatform/Render/CEFSyncCopyRenderLayer.cpp index eea012c..1164cd7 100644 --- a/src/UIPlatform/Render/CEFSyncCopyRenderLayer.cpp +++ b/src/UIPlatform/Render/CEFSyncCopyRenderLayer.cpp @@ -14,69 +14,19 @@ namespace NL::Render a_render->Release(); } - void CEFSyncCopyRenderLayer::Init(RenderData* a_renderData) - { - IRenderLayer::Init(a_renderData); - - const auto hr = m_renderData->device->QueryInterface(IID_PPV_ARGS(&m_device1)); - if (FAILED(hr)) - { - spdlog::error("CEFSyncCopyRenderLayer::Init() - failed QueryInterface(), code {:X}", hr); - } - } - - const inline ::DirectX::SimpleMath::Vector2 _Cef_Menu_Draw_Vector = {0.f, 0.f}; - void CEFSyncCopyRenderLayer::Draw() + void CEFSyncCopyRenderLayer::CopySharedTexure() { - if (!m_isVisible) - { - return; - } - - if (m_renderData->deviceContext->GetType() == D3D11_DEVICE_CONTEXT_DEFERRED) - { - spdlog::error("D3D11_DEVICE_CONTEXT_DEFERRED_____________________"); - return; - } - - if (!m_acceleratedPaintReady.test(std::memory_order_acquire)) - { - if (m_cefSRV != nullptr) - { - m_renderData->spriteBatch->Draw( - m_cefSRV.Get(), - _Cef_Menu_Draw_Vector, - nullptr, - ::DirectX::Colors::White, - 0.f); - } - - return; - } - Microsoft::WRL::ComPtr sharedTexture = nullptr; auto hr = m_device1->OpenSharedResource1(m_acceleratedPaintInfo->shared_texture_handle, IID_PPV_ARGS(sharedTexture.ReleaseAndGetAddressOf())); - if (FAILED(hr)) - { - _com_error err(hr); - LPCTSTR errMsg = err.ErrorMessage(); - spdlog::error("CEFSyncCopyRenderLayer::Draw() - failed to OpenSharedResource1(), unexpected HRESULT {:#X}: {}", static_cast(hr), errMsg); - m_acceleratedPaintReady.clear(std::memory_order_release); - m_acceleratedPaintReady.notify_all(); - return; - } + FAST_CHECK_HRESULT_LOG_AND_RETURN(hr, "CEFSyncCopyRenderLayer::CopySharedTexure() - OpenSharedResource1()"); if (m_cefSRV == nullptr) { D3D11_TEXTURE2D_DESC sharedTextureDesc = {}; sharedTexture->GetDesc(&sharedTextureDesc); - auto hResult = m_renderData->device->CreateTexture2D(&sharedTextureDesc, nullptr, m_cefTexture.ReleaseAndGetAddressOf()); - if (FAILED(hResult)) - { - spdlog::error("CEFSyncCopyRenderLayer::Draw() - failed CreateTexture2D(), code {:X}", hResult); - return; - } + hr = m_renderData->device->CreateTexture2D(&sharedTextureDesc, nullptr, m_cefTexture.ReleaseAndGetAddressOf()); + FAST_CHECK_HRESULT_LOG_AND_RETURN(hr, "CEFSyncCopyRenderLayer::CopySharedTexure() - CreateTexture2D()"); D3D11_SHADER_RESOURCE_VIEW_DESC sharedResourceViewDesc = {}; sharedResourceViewDesc.Format = sharedTextureDesc.Format; @@ -84,68 +34,82 @@ namespace NL::Render sharedResourceViewDesc.Texture2D.MostDetailedMip = 0; sharedResourceViewDesc.Texture2D.MipLevels = 1; - hResult = m_renderData->device->CreateShaderResourceView(m_cefTexture.Get(), &sharedResourceViewDesc, m_cefSRV.ReleaseAndGetAddressOf()); - if (FAILED(hResult)) - { - spdlog::error("CEFSyncCopyRenderLayer::Draw() - failed CreateShaderResourceView(), code {:X}", hResult); - return; - } + hr = m_renderData->device->CreateShaderResourceView(m_cefTexture.Get(), &sharedResourceViewDesc, m_cefSRV.ReleaseAndGetAddressOf()); + FAST_CHECK_HRESULT_LOG_AND_RETURN(hr, "CEFSyncCopyRenderLayer::CopySharedTexure() - CreateShaderResourceView()"); - spdlog::info("CEFSyncCopyRenderLayer::Draw() - texture created"); + spdlog::info("CEFSyncCopyRenderLayer: texture created"); } - m_renderData->deviceContext->CopyResource(m_cefTexture.Get(), sharedTexture.Get()); + spdlog::info("Dirty rect - {}:{}:{}:{}", + m_acceleratedPaintInfo->extra.capture_update_rect.x, + m_acceleratedPaintInfo->extra.capture_update_rect.y, + m_acceleratedPaintInfo->extra.capture_update_rect.width, + m_acceleratedPaintInfo->extra.capture_update_rect.height); + + D3D11_BOX dirtyRect{}; + dirtyRect.left = m_acceleratedPaintInfo->extra.capture_update_rect.x; + dirtyRect.top = m_acceleratedPaintInfo->extra.capture_update_rect.y; + dirtyRect.right = m_acceleratedPaintInfo->extra.capture_update_rect.x + m_acceleratedPaintInfo->extra.capture_update_rect.width; + dirtyRect.bottom = m_acceleratedPaintInfo->extra.capture_update_rect.y + m_acceleratedPaintInfo->extra.capture_update_rect.height; + dirtyRect.front = 0; + dirtyRect.back = 1; + + m_renderData->deviceContext->CopySubresourceRegion(m_cefTexture.Get(), + 0, + m_acceleratedPaintInfo->extra.capture_update_rect.x, + m_acceleratedPaintInfo->extra.capture_update_rect.y, + 0, + sharedTexture.Get(), + 0, + &dirtyRect); // The CopyResource call is asynchronous by default m_renderData->deviceContext->Flush(); - D3D11_QUERY_DESC QueryDesc = {}; - QueryDesc.Query = D3D11_QUERY_EVENT; - QueryDesc.MiscFlags = 0; - Microsoft::WRL::ComPtr Query; - if (HRESULT hr = m_device1->CreateQuery(&QueryDesc, &Query); FAILED(hr)) + D3D11_QUERY_DESC queryDesc = {}; + queryDesc.Query = D3D11_QUERY_EVENT; + queryDesc.MiscFlags = 0; + + Microsoft::WRL::ComPtr query; + hr = m_device1->CreateQuery(&queryDesc, &query); + FAST_CHECK_HRESULT_LOG_AND_RETURN(hr, "CEFSyncCopyRenderLayer::CopySharedTexure() - CreateQuery()"); + + m_renderData->deviceContext->End(query.Get()); + + while (S_FALSE == m_renderData->deviceContext->GetData(query.Get(), NULL, 0, 0)) { - spdlog::error("CEFSyncCopyRenderLayer::Draw() - falied CreateQuery(), code {:X}", hr); - return; } - m_renderData->deviceContext->End(Query.Get()); + } + + void CEFSyncCopyRenderLayer::Init(RenderData* a_renderData) + { + IRenderLayer::Init(a_renderData); + + const auto hr = m_renderData->device->QueryInterface(IID_PPV_ARGS(&m_device1)); + if (FAILED(hr)) + { + spdlog::error("CEFSyncCopyRenderLayer::Init() - failed QueryInterface(), code {:X}", hr); + } + } - while (S_FALSE == m_renderData->deviceContext->GetData(Query.Get(), NULL, 0, 0)) + const inline ::DirectX::SimpleMath::Vector2 _Cef_Menu_Draw_Vector = {0.f, 0.f}; + void CEFSyncCopyRenderLayer::Draw() + { + if (m_acceleratedPaintReady.test(std::memory_order_acquire)) { - // Optional: Sleep briefly to prevent a 100% CPU core usage busy-wait - // Sleep(1); + CopySharedTexure(); + m_acceleratedPaintReady.clear(std::memory_order_release); + m_acceleratedPaintReady.notify_all(); } - //bool isDone = false; - //hr = S_OK; - //for (;;) - //{ - // hr = m_renderData->deviceContext->GetData(Query.Get(), &isDone, sizeof(isDone), 0); - // if (FAILED(hr)) - // { - // _com_error err(hr); - // LPCTSTR errMsg = err.ErrorMessage(); - // spdlog::error("CEFSyncCopyRenderLayer::Draw() - falied GetData(), code {:#X}: {}", static_cast(hr), errMsg); - // m_acceleratedPaintReady.clear(std::memory_order_release); - // m_acceleratedPaintReady.notify_all(); - // return; - // } - // - // // We need to check for S_OK specifically as S_FALSE is also considered a success return code - // if (hr == S_OK && isDone) - // { - // break; - // } - //} - - m_renderData->spriteBatch->Draw( - m_cefSRV.Get(), - _Cef_Menu_Draw_Vector, - nullptr, - ::DirectX::Colors::White, - 0.f); - - m_acceleratedPaintReady.clear(std::memory_order_release); - m_acceleratedPaintReady.notify_all(); + if (m_isVisible && m_cefSRV != nullptr) + { + m_renderData->spriteBatch->Draw( + m_cefSRV.Get(), + _Cef_Menu_Draw_Vector, + nullptr, + ::DirectX::Colors::White, + 0.f); + } } void CEFSyncCopyRenderLayer::GetViewRect(CefRefPtr browser, CefRect& rect) @@ -186,25 +150,14 @@ namespace NL::Render } if (m_renderData == nullptr || - m_device1 == nullptr || - info.shared_texture_handle == nullptr) + m_device1 == nullptr) { spdlog::error("CEFSyncCopyRenderLayer::OnAcceleratedPaint() - device or renderData is nullptr"); return; } - m_acceleratedPaintReady.test_and_set(std::memory_order_acquire); - - // while (m_acceleratedPaintReady.test_and_set(std::memory_order_acquire)) - //{ - // m_acceleratedPaintReady.wait(true, std::memory_order_relaxed); - // } - m_acceleratedPaintInfo = &info; - - // m_acceleratedPaintReady.clear(std::memory_order_release); + m_acceleratedPaintReady.test_and_set(std::memory_order_acquire); m_acceleratedPaintReady.wait(true, std::memory_order_acquire); - - spdlog::info("OnAcceleratedPaint"); } } diff --git a/src/UIPlatform/Render/CEFSyncCopyRenderLayer.h b/src/UIPlatform/Render/CEFSyncCopyRenderLayer.h index e2859fc..cf1ca62 100644 --- a/src/UIPlatform/Render/CEFSyncCopyRenderLayer.h +++ b/src/UIPlatform/Render/CEFSyncCopyRenderLayer.h @@ -21,6 +21,8 @@ namespace NL::Render const CefAcceleratedPaintInfo* m_acceleratedPaintInfo = nullptr; std::atomic_flag m_acceleratedPaintReady = ATOMIC_FLAG_INIT; + void CopySharedTexure(); + public: ~CEFSyncCopyRenderLayer() override = default; diff --git a/src/UIPlatform/Utils/CheckHresult.h b/src/UIPlatform/Utils/CheckHresult.h index 3a92da8..752f1f3 100644 --- a/src/UIPlatform/Utils/CheckHresult.h +++ b/src/UIPlatform/Utils/CheckHresult.h @@ -31,3 +31,13 @@ inline void CheckHresultThrow(HRESULT hr, const std::string& userMsg) return; \ } \ } while (0) + +#define FAST_CHECK_HRESULT_LOG_AND_RETURN(hr, userMsg) \ + do \ + { \ + if (FAILED(hr)) \ + { \ + spdlog::error("{}", CheckHresultMessage(hr, userMsg)); \ + return; \ + } \ + } while (0) From 1610d57424424448ede85a7c0e5a7e1871fe0f4c Mon Sep 17 00:00:00 2001 From: kkEngine <78795688+kkEngine@users.noreply.github.com> Date: Tue, 30 Dec 2025 14:34:26 +0300 Subject: [PATCH 3/3] - Fixed accelerated paint deadlock when exiting the game - RAII unlock guard - Minor fixes --- CMakeLists.txt | 4 +-- src/UIPlatform/NirnLabUIPlatformAPI/Version.h | 8 ++--- .../Render/CEFSyncCopyRenderLayer.cpp | 32 +++++++++++++------ .../Render/CEFSyncCopyRenderLayer.h | 11 ++++++- .../NirnLabUIPlatformAPI/Version.h | 8 ++--- .../TestCases/LoadYoutubeTestCase.cpp | 6 ++-- src/UIPlatformTest/main.cpp | 4 +-- 7 files changed, 47 insertions(+), 26 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ce925ce..67b9a37 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,9 +4,9 @@ option(BUILD_AS_SHARED "Build as dll skse plugin else build as static lib" ON) # Version set(LIB_MAJOR_VERSION 3) -set(LIB_MINOR_VERSION 2) +set(LIB_MINOR_VERSION 3) set(API_MAJOR_VERSION 3) -set(API_MINOR_VERSION 2) +set(API_MINOR_VERSION 3) # VCPKG config string(REPLACE "\\" "/" ENV_VCPKG_ROOT "$ENV{VCPKG_ROOT}") diff --git a/src/UIPlatform/NirnLabUIPlatformAPI/Version.h b/src/UIPlatform/NirnLabUIPlatformAPI/Version.h index 1b27e85..8685822 100644 --- a/src/UIPlatform/NirnLabUIPlatformAPI/Version.h +++ b/src/UIPlatform/NirnLabUIPlatformAPI/Version.h @@ -5,11 +5,11 @@ namespace NL::UI::LibVersion { inline constexpr std::uint32_t MAJOR = 3; - inline constexpr std::uint32_t MINOR = 2; + inline constexpr std::uint32_t MINOR = 3; inline constexpr auto PROJECT_NAME = "NirnLabUIPlatform"; inline constexpr auto MAJOR_MULT = 100000; - inline constexpr auto AS_STRING = "3.2"; + inline constexpr auto AS_STRING = "3.3"; inline constexpr std::uint32_t AS_INT = (static_cast(MAJOR * MAJOR_MULT + MINOR)); inline std::uint32_t GetMajorVersion(std::uint32_t a_version) @@ -26,10 +26,10 @@ namespace NL::UI::LibVersion namespace NL::UI::APIVersion { inline constexpr std::uint32_t MAJOR = 3; - inline constexpr std::uint32_t MINOR = 2; + inline constexpr std::uint32_t MINOR = 3; inline constexpr auto MAJOR_MULT = 100000; - inline constexpr auto AS_STRING = "3.2"; + inline constexpr auto AS_STRING = "3.3"; inline constexpr std::uint32_t AS_INT = (static_cast(MAJOR * MAJOR_MULT + MINOR)); inline std::uint32_t GetMajorVersion(std::uint32_t a_version) diff --git a/src/UIPlatform/Render/CEFSyncCopyRenderLayer.cpp b/src/UIPlatform/Render/CEFSyncCopyRenderLayer.cpp index 1164cd7..83b4e3a 100644 --- a/src/UIPlatform/Render/CEFSyncCopyRenderLayer.cpp +++ b/src/UIPlatform/Render/CEFSyncCopyRenderLayer.cpp @@ -14,6 +14,17 @@ namespace NL::Render a_render->Release(); } + CEFSyncCopyRenderLayer::AtomicFlagGuard::AtomicFlagGuard(std::atomic_flag& a_flag) + : m_flag(a_flag) + { + } + + CEFSyncCopyRenderLayer::AtomicFlagGuard::~AtomicFlagGuard() + { + m_flag.clear(std::memory_order_release); + m_flag.notify_all(); + } + void CEFSyncCopyRenderLayer::CopySharedTexure() { Microsoft::WRL::ComPtr sharedTexture = nullptr; @@ -40,13 +51,7 @@ namespace NL::Render spdlog::info("CEFSyncCopyRenderLayer: texture created"); } - spdlog::info("Dirty rect - {}:{}:{}:{}", - m_acceleratedPaintInfo->extra.capture_update_rect.x, - m_acceleratedPaintInfo->extra.capture_update_rect.y, - m_acceleratedPaintInfo->extra.capture_update_rect.width, - m_acceleratedPaintInfo->extra.capture_update_rect.height); - - D3D11_BOX dirtyRect{}; + D3D11_BOX dirtyRect; dirtyRect.left = m_acceleratedPaintInfo->extra.capture_update_rect.x; dirtyRect.top = m_acceleratedPaintInfo->extra.capture_update_rect.y; dirtyRect.right = m_acceleratedPaintInfo->extra.capture_update_rect.x + m_acceleratedPaintInfo->extra.capture_update_rect.width; @@ -96,9 +101,8 @@ namespace NL::Render { if (m_acceleratedPaintReady.test(std::memory_order_acquire)) { + AtomicFlagGuard guard(m_acceleratedPaintReady); CopySharedTexure(); - m_acceleratedPaintReady.clear(std::memory_order_release); - m_acceleratedPaintReady.notify_all(); } if (m_isVisible && m_cefSRV != nullptr) @@ -137,6 +141,7 @@ namespace NL::Render int width, int height) { + spdlog::error("CEFCopyRenderLayer::OnPaint called"); } void CEFSyncCopyRenderLayer::OnAcceleratedPaint(CefRefPtr browser, @@ -158,6 +163,13 @@ namespace NL::Render m_acceleratedPaintInfo = &info; m_acceleratedPaintReady.test_and_set(std::memory_order_acquire); - m_acceleratedPaintReady.wait(true, std::memory_order_acquire); + while (m_acceleratedPaintReady.test(std::memory_order_acquire)) + { + if (NL::Hooks::ShutdownHook::IsGameClosing) + { + m_acceleratedPaintReady.clear(std::memory_order_release); + break; + } + } } } diff --git a/src/UIPlatform/Render/CEFSyncCopyRenderLayer.h b/src/UIPlatform/Render/CEFSyncCopyRenderLayer.h index cf1ca62..b618fed 100644 --- a/src/UIPlatform/Render/CEFSyncCopyRenderLayer.h +++ b/src/UIPlatform/Render/CEFSyncCopyRenderLayer.h @@ -2,6 +2,7 @@ #include "PCH.h" #include "IRenderLayer.h" +#include "Hooks/ShutdownHook.hpp" namespace NL::Render { @@ -15,6 +16,14 @@ namespace NL::Render static void release_shared(CEFSyncCopyRenderLayer* a_render); protected: + struct AtomicFlagGuard + { + std::atomic_flag& m_flag; + + AtomicFlagGuard(std::atomic_flag& a_flag); + ~AtomicFlagGuard(); + }; + Microsoft::WRL::ComPtr m_device1 = nullptr; Microsoft::WRL::ComPtr m_cefTexture = nullptr; Microsoft::WRL::ComPtr m_cefSRV = nullptr; @@ -24,7 +33,7 @@ namespace NL::Render void CopySharedTexure(); public: - ~CEFSyncCopyRenderLayer() override = default; + virtual ~CEFSyncCopyRenderLayer() override = default; // IRenderLayer void Init(RenderData* a_renderData) override; diff --git a/src/UIPlatformTest/NirnLabUIPlatformAPI/Version.h b/src/UIPlatformTest/NirnLabUIPlatformAPI/Version.h index 1b27e85..8685822 100644 --- a/src/UIPlatformTest/NirnLabUIPlatformAPI/Version.h +++ b/src/UIPlatformTest/NirnLabUIPlatformAPI/Version.h @@ -5,11 +5,11 @@ namespace NL::UI::LibVersion { inline constexpr std::uint32_t MAJOR = 3; - inline constexpr std::uint32_t MINOR = 2; + inline constexpr std::uint32_t MINOR = 3; inline constexpr auto PROJECT_NAME = "NirnLabUIPlatform"; inline constexpr auto MAJOR_MULT = 100000; - inline constexpr auto AS_STRING = "3.2"; + inline constexpr auto AS_STRING = "3.3"; inline constexpr std::uint32_t AS_INT = (static_cast(MAJOR * MAJOR_MULT + MINOR)); inline std::uint32_t GetMajorVersion(std::uint32_t a_version) @@ -26,10 +26,10 @@ namespace NL::UI::LibVersion namespace NL::UI::APIVersion { inline constexpr std::uint32_t MAJOR = 3; - inline constexpr std::uint32_t MINOR = 2; + inline constexpr std::uint32_t MINOR = 3; inline constexpr auto MAJOR_MULT = 100000; - inline constexpr auto AS_STRING = "3.2"; + inline constexpr auto AS_STRING = "3.3"; inline constexpr std::uint32_t AS_INT = (static_cast(MAJOR * MAJOR_MULT + MINOR)); inline std::uint32_t GetMajorVersion(std::uint32_t a_version) diff --git a/src/UIPlatformTest/TestCases/LoadYoutubeTestCase.cpp b/src/UIPlatformTest/TestCases/LoadYoutubeTestCase.cpp index 30b493b..850ce33 100644 --- a/src/UIPlatformTest/TestCases/LoadYoutubeTestCase.cpp +++ b/src/UIPlatformTest/TestCases/LoadYoutubeTestCase.cpp @@ -4,10 +4,10 @@ namespace NL::UI::TestCase { void LoadYoutubeTestCase::Start(NL::UI::IUIPlatformAPI* a_api) { - NL::UI::BrowserSettings bSettings; - bSettings.frameRate = 30; + NL::UI::BrowserSettings bSettings{}; + // bSettings.frameRate = 30; - //m_browserHandle = a_api->AddOrGetBrowser("YOUTUBE_TEST_CEF", nullptr, 0, "https://youtube.com", m_browser); + // m_browserHandle = a_api->AddOrGetBrowser("YOUTUBE_TEST_CEF", nullptr, 0, "https://youtube.com", m_browser); m_browserHandle = a_api->AddOrGetBrowser("YOUTUBE_TEST_CEF", nullptr, 0, "https://google.com", &bSettings, m_browser); if (m_browserHandle == NL::UI::IUIPlatformAPI::InvalidBrowserRefHandle) diff --git a/src/UIPlatformTest/main.cpp b/src/UIPlatformTest/main.cpp index c253600..26bc70c 100644 --- a/src/UIPlatformTest/main.cpp +++ b/src/UIPlatformTest/main.cpp @@ -54,7 +54,7 @@ void Init1stMethodToGetAPI() case SKSE::MessagingInterface::kInputLoaded: if (s_canUseAPI) { - NL::UI::Settings defaultSettings; + NL::UI::Settings defaultSettings{}; // API version is ok. Request interface. SKSE::GetMessagingInterface()->Dispatch(NL::UI::APIMessageType::RequestAPI, &defaultSettings, sizeof(defaultSettings), NL::UI::LibVersion::PROJECT_NAME); } @@ -119,7 +119,7 @@ void Init2ndMethodToGetAPI() try { NL::UI::IUIPlatformAPI* api = nullptr; - NL::UI::Settings defaultSettings; + NL::UI::Settings defaultSettings{}; if (NL::UI::DllLoader::CreateOrGetUIPlatformAPIWithVersionCheck(&api, &defaultSettings, NL::UI::APIVersion::AS_INT, PLUGIN_NAME)) {