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/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/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 new file mode 100644 index 0000000..83b4e3a --- /dev/null +++ b/src/UIPlatform/Render/CEFSyncCopyRenderLayer.cpp @@ -0,0 +1,175 @@ +#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(); + } + + 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; + auto hr = m_device1->OpenSharedResource1(m_acceleratedPaintInfo->shared_texture_handle, IID_PPV_ARGS(sharedTexture.ReleaseAndGetAddressOf())); + FAST_CHECK_HRESULT_LOG_AND_RETURN(hr, "CEFSyncCopyRenderLayer::CopySharedTexure() - OpenSharedResource1()"); + + if (m_cefSRV == nullptr) + { + D3D11_TEXTURE2D_DESC sharedTextureDesc = {}; + sharedTexture->GetDesc(&sharedTextureDesc); + + 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; + sharedResourceViewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; + sharedResourceViewDesc.Texture2D.MostDetailedMip = 0; + sharedResourceViewDesc.Texture2D.MipLevels = 1; + + 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: texture created"); + } + + 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; + 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)) + { + } + } + + 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_acceleratedPaintReady.test(std::memory_order_acquire)) + { + AtomicFlagGuard guard(m_acceleratedPaintReady); + CopySharedTexure(); + } + + 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) + { + 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) + { + spdlog::error("CEFCopyRenderLayer::OnPaint called"); + } + + 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) + { + spdlog::error("CEFSyncCopyRenderLayer::OnAcceleratedPaint() - device or renderData is nullptr"); + return; + } + + m_acceleratedPaintInfo = &info; + m_acceleratedPaintReady.test_and_set(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 new file mode 100644 index 0000000..b618fed --- /dev/null +++ b/src/UIPlatform/Render/CEFSyncCopyRenderLayer.h @@ -0,0 +1,57 @@ +#pragma once + +#include "PCH.h" +#include "IRenderLayer.h" +#include "Hooks/ShutdownHook.hpp" + +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: + 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; + const CefAcceleratedPaintInfo* m_acceleratedPaintInfo = nullptr; + std::atomic_flag m_acceleratedPaintReady = ATOMIC_FLAG_INIT; + + void CopySharedTexure(); + + public: + virtual ~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; + }; +} 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) 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)) {