From 52916db08f34f5476aac0e1f839d072f4ea5735e Mon Sep 17 00:00:00 2001 From: yyc12345 Date: Mon, 5 Jan 2026 16:51:58 +0800 Subject: [PATCH] optimize dx11 engine --- .../Plugins/Engine/DirectX11Engine/main.cpp | 150 ++++++++++++++---- BasaltPresenter/Presenter/dll_loader.cpp | 11 +- BasaltPresenter/Presenter/dll_loader.hpp | 2 +- BasaltPresenter/Presenter/main.cpp | 6 +- BasaltPresenter/Shared/CMakeLists.txt | 3 +- BasaltPresenter/Shared/basalt_char.hpp | 9 ++ BasaltPresenter/Shared/directx_util.cpp | 67 -------- BasaltPresenter/Shared/directx_util.hpp | 10 -- BasaltPresenter/Shared/engine.cpp | 3 +- BasaltPresenter/Shared/engine.hpp | 8 +- 10 files changed, 152 insertions(+), 117 deletions(-) delete mode 100644 BasaltPresenter/Shared/directx_util.cpp delete mode 100644 BasaltPresenter/Shared/directx_util.hpp diff --git a/BasaltPresenter/Plugins/Engine/DirectX11Engine/main.cpp b/BasaltPresenter/Plugins/Engine/DirectX11Engine/main.cpp index a953c5e..970ab6f 100644 --- a/BasaltPresenter/Plugins/Engine/DirectX11Engine/main.cpp +++ b/BasaltPresenter/Plugins/Engine/DirectX11Engine/main.cpp @@ -1,5 +1,4 @@ #include -#include #include #include #include @@ -14,6 +13,91 @@ using Microsoft::WRL::ComPtr; throw std::runtime_error("bad DirectX calling"); \ } +#pragma region Win32 Window Creation + +// Window procedure for the render window +static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { + switch (msg) { + case WM_CLOSE: + PostQuitMessage(0); + return 0; + default: + break; + } + return DefWindowProcW(hwnd, msg, wParam, lParam); +} + +// Create a render window for DirectX +static HWND CreateRenderWindow(std::uint32_t width, std::uint32_t height, const std::wstring_view& title) { + static bool g_CLSREG = false; + constexpr wchar_t class_name[] = L"DirectXRenderWindowClass"; + std::wstring c_title(title); + + if (!g_CLSREG) { + WNDCLASSEXW wc = {0}; + wc.cbSize = sizeof(WNDCLASSEXW); + wc.style = CS_HREDRAW | CS_VREDRAW; + wc.lpfnWndProc = WndProc; + wc.hInstance = GetModuleHandleW(nullptr); + wc.hCursor = LoadCursorW(nullptr, IDC_ARROW); + wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1); + wc.lpszClassName = class_name; + + if (!RegisterClassExW(&wc)) { + throw std::runtime_error("Failed to register window class"); + } + g_CLSREG = true; + } + + // Calculate window size including borders + RECT rect = {0, 0, static_cast(width), static_cast(height)}; + AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE); + + HWND hwnd = CreateWindowExW(0, + class_name, + c_title.c_str(), + WS_OVERLAPPEDWINDOW ^ WS_THICKFRAME ^ WS_MAXIMIZEBOX, + CW_USEDEFAULT, + CW_USEDEFAULT, + rect.right - rect.left, + rect.bottom - rect.top, + nullptr, + nullptr, + GetModuleHandleW(nullptr), + nullptr); + if (!hwnd) { + throw std::runtime_error("Failed to create render window"); + } + + return hwnd; +} + +static void DestroyRenderWindow(HWND hwnd) { + DestroyWindow(hwnd); +} + +/** + * @brief Non-block event loop. + * @return True for indicate active exit. + */ +static bool EventLoop() { + MSG msg; + if (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE) == 0) { + // No msg + return false; + } else { + if (msg.message == WM_QUIT) { + return true; + } else { + TranslateMessage(&msg); + DispatchMessageW(&msg); + return false; + } + } +} + +#pragma endregion + // 立方体顶点(位置) struct Vertex { float x, y, z; @@ -61,8 +145,7 @@ Vertex CubeVertices[] = { {1, -1, 1}, {-1, -1, -1}, {1, -1, 1}, - {1, -1, -1} -}; + {1, -1, -1}}; // 简单顶点着色器(只传位置) const char* g_VS = R"( @@ -80,7 +163,6 @@ const char* g_PS = R"( using ::Basalt::Shared::Engine::EngineConfig; using ::Basalt::Shared::Engine::IEngine; -namespace DxUtil = ::Basalt::Shared::DirectX; class DirectX11Engine : public IEngine { public: @@ -88,28 +170,38 @@ public: virtual ~DirectX11Engine() {} private: - ComPtr device; ///< 设备 - ComPtr context; ///< 上下文 - ComPtr swap_chain; ///< 交换链 - ComPtr rtv; ///< 渲染目标视图 - ComPtr back_buffer; ///< 后缓冲 - ComPtr depth_buffer; ///< 深度缓冲 - ComPtr dsv; ///< 深度模板视图 - ComPtr depth_staging; ///< 用于CPU读取的深度暂存纹理 - ComPtr vs; ///< 顶点着色器 - ComPtr ps; ///< 像素着色器 - ComPtr vs_blob; ///< 顶点着色器字节码 - ComPtr ps_blob; ///< 像素着色器字节码 - ComPtr input_layout; ///< 输入布局 - ComPtr vertex_buffer; ///< 顶点缓冲 - ComPtr depth_state; ///< 深度状态 + HWND window; ///< Win32窗口 + ComPtr device; ///< 设备 + ComPtr context; ///< 上下文 + ComPtr swap_chain; ///< 交换链 + ComPtr rtv; ///< 渲染目标视图 + ComPtr back_buffer; ///< 后缓冲 + ComPtr depth_buffer; ///< 深度缓冲 + ComPtr dsv; ///< 深度模板视图 + ComPtr depth_staging; ///< 用于CPU读取的深度暂存纹理 + ComPtr vs; ///< 顶点着色器 + ComPtr ps; ///< 像素着色器 + ComPtr vs_blob; ///< 顶点着色器字节码 + ComPtr ps_blob; ///< 像素着色器字节码 + ComPtr input_layout; ///< 输入布局 + ComPtr vertex_buffer; ///< 顶点缓冲 + ComPtr depth_state; ///< 深度状态 ComPtr rasterizer_state; ///< 光栅化状态 - std::vector depth_data; ///< 深度数据 + std::vector depth_data; ///< 深度数据 public: virtual void Startup(EngineConfig&& config) override { IEngine::Startup(std::move(config)); + // 创建Win32窗口并显示 + if (this->config.headless) { + window = NULL; + } else { + window = CreateRenderWindow(this->config.width, this->config.height, this->config.title); + ShowWindow(window, SW_SHOW); + UpdateWindow(window); + } + // 初始化 COM DXCHK(CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED)); @@ -133,7 +225,7 @@ public: sd.SampleDesc.Count = 1; sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; sd.BufferCount = 1; - sd.OutputWindow = DxUtil::CreateRenderWindow(this->config.width, this->config.height, this->config.title); // 创建窗口 + sd.OutputWindow = window; sd.Windowed = TRUE; ComPtr dxgi_device; @@ -228,13 +320,11 @@ public: //frameCount = 0; } - virtual void Tick() override { - IEngine::Tick(); + virtual bool Tick() override { + if (IEngine::Tick()) return true; - MSG msg; - GetMessage(&msg, nullptr, 0, 0); - TranslateMessage(&msg); - DispatchMessage(&msg); + // Event loop + if (EventLoop()) return true; // 清屏 float clear_color[] = {0.8f, 0.1f, 0.1f, 1.0f}; @@ -274,6 +364,8 @@ public: DXCHK(swap_chain->Present(0, 0)); //frameCount++; + + return false; } virtual void Shutdown() override { @@ -283,6 +375,10 @@ public: // CloseHandle(hPipe); //} CoUninitialize(); + if (!this->config.headless) { + CloseWindow(window); + DestroyRenderWindow(window); + } } }; diff --git a/BasaltPresenter/Presenter/dll_loader.cpp b/BasaltPresenter/Presenter/dll_loader.cpp index dd00b4e..c68ef57 100644 --- a/BasaltPresenter/Presenter/dll_loader.cpp +++ b/BasaltPresenter/Presenter/dll_loader.cpp @@ -1,5 +1,4 @@ #include "dll_loader.hpp" -#include #include #include @@ -9,16 +8,18 @@ #include #endif +using ::Basalt::Shared::Char::BSStringView; + namespace Basalt::Presenter { static std::filesystem::path get_executable() { #if defined(BASALT_OS_WINDOWS) wchar_t buffer[MAX_PATH]; DWORD hr = GetModuleFileNameW(NULL, buffer, MAX_PATH); - if (hr == 0) { - throw std::runtime_error("Failed to get executable path"); - } else { + if (hr > 0 && hr < MAX_PATH) { return std::filesystem::path(buffer); + } else { + throw std::runtime_error("Failed to get executable path"); } #else char buffer[PATH_MAX]; @@ -32,7 +33,7 @@ namespace Basalt::Presenter { #endif } - DllLoader::DllLoader(DllKind kind, const std::basic_string_view filename) { + DllLoader::DllLoader(DllKind kind, const BSStringView& filename) { // Build DLL full path auto dll_path = get_executable().parent_path(); dll_path /= BSTEXT("plugin"); diff --git a/BasaltPresenter/Presenter/dll_loader.hpp b/BasaltPresenter/Presenter/dll_loader.hpp index ef507ce..01c893e 100644 --- a/BasaltPresenter/Presenter/dll_loader.hpp +++ b/BasaltPresenter/Presenter/dll_loader.hpp @@ -25,7 +25,7 @@ namespace Basalt::Presenter { #endif public: - DllLoader(DllKind kind, const std::basic_string_view filename); + DllLoader(DllKind kind, const Shared::Char::BSStringView& filename); ~DllLoader(); private: diff --git a/BasaltPresenter/Presenter/main.cpp b/BasaltPresenter/Presenter/main.cpp index 8545383..ac0ecca 100644 --- a/BasaltPresenter/Presenter/main.cpp +++ b/BasaltPresenter/Presenter/main.cpp @@ -8,12 +8,14 @@ namespace Shared = ::Basalt::Shared; int main(int argc, char* argv[]) { auto engine_dll = Presenter::DllLoader(Presenter::DllKind::Engine, BSTEXT("BasaltDirectX11Engine")); auto* engine = engine_dll.CreateInstance(); - Shared::Engine::EngineConfig engine_config{.is_headless = false, .title = BSTEXT("Fuck You"), .width = 800, .height = 600}; + + Shared::Engine::EngineConfig engine_config{.headless = false, .title = BSTEXT("Fuck You"), .width = 800, .height = 600}; engine->Startup(std::move(engine_config)); while (true) { - engine->Tick(); + if (engine->Tick()) break; } engine->Shutdown(); + engine_dll.DestroyInstance(engine); } diff --git a/BasaltPresenter/Shared/CMakeLists.txt b/BasaltPresenter/Shared/CMakeLists.txt index f9050d6..e50810c 100644 --- a/BasaltPresenter/Shared/CMakeLists.txt +++ b/BasaltPresenter/Shared/CMakeLists.txt @@ -5,7 +5,7 @@ PRIVATE pipe_operator.cpp engine.cpp deliver.cpp - directx_util.cpp + ) target_sources(BasaltShared PUBLIC @@ -17,7 +17,6 @@ FILES pipe_operator.hpp engine.hpp deliver.hpp - directx_util.hpp ) target_include_directories(BasaltShared PUBLIC diff --git a/BasaltPresenter/Shared/basalt_char.hpp b/BasaltPresenter/Shared/basalt_char.hpp index 587d170..bdb4d00 100644 --- a/BasaltPresenter/Shared/basalt_char.hpp +++ b/BasaltPresenter/Shared/basalt_char.hpp @@ -1,4 +1,6 @@ #include +#include +#include #if defined(BASALT_OS_WINDOWS) #define BSCHAR wchar_t @@ -8,3 +10,10 @@ #define BSCHAR char #define BSTEXT(x) x #endif + +namespace Basalt::Shared::Char { + + using BSString = std::basic_string; + using BSStringView = std::basic_string_view; + +}; // namespace Basalt::Shared::Char diff --git a/BasaltPresenter/Shared/directx_util.cpp b/BasaltPresenter/Shared/directx_util.cpp deleted file mode 100644 index b5ddd8a..0000000 --- a/BasaltPresenter/Shared/directx_util.cpp +++ /dev/null @@ -1,67 +0,0 @@ -#include "directx_util.hpp" -#include -#include - -namespace Basalt::Shared::DirectX { - - // Window procedure for the render window - LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { - switch (msg) { - case WM_CLOSE: - PostQuitMessage(0); - return 0; - default: - break; - } - return DefWindowProcW(hwnd, msg, wParam, lParam); - } - - // Create a render window for DirectX - HWND CreateRenderWindow(std::uint32_t width, std::uint32_t height, const std::wstring_view& title) { - static bool g_CLSREG = false; - constexpr wchar_t class_name[] = L"DirectXRenderWindowClass"; - std::wstring c_title(title); - - if (!g_CLSREG) { - WNDCLASSEXW wc = {0}; - wc.cbSize = sizeof(WNDCLASSEXW); - wc.style = CS_HREDRAW | CS_VREDRAW; - wc.lpfnWndProc = WndProc; - wc.hInstance = GetModuleHandleW(nullptr); - wc.hCursor = LoadCursorW(nullptr, IDC_ARROW); - wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1); - wc.lpszClassName = class_name; - - if (!RegisterClassExW(&wc)) { - throw std::runtime_error("Failed to register window class"); - } - g_CLSREG = true; - } - - // Calculate window size including borders - RECT rect = {0, 0, static_cast(width), static_cast(height)}; - AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE); - - HWND hwnd = CreateWindowExW(0, - class_name, - c_title.c_str(), - WS_OVERLAPPEDWINDOW, - CW_USEDEFAULT, - CW_USEDEFAULT, - rect.right - rect.left, - rect.bottom - rect.top, - nullptr, - nullptr, - GetModuleHandleW(nullptr), - nullptr); - if (!hwnd) { - throw std::runtime_error("Failed to create render window"); - } - - ShowWindow(hwnd, SW_SHOW); - UpdateWindow(hwnd); - - return hwnd; - } - -} diff --git a/BasaltPresenter/Shared/directx_util.hpp b/BasaltPresenter/Shared/directx_util.hpp deleted file mode 100644 index 1d022a8..0000000 --- a/BasaltPresenter/Shared/directx_util.hpp +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once -#include -#include -#include - -namespace Basalt::Shared::DirectX { - - HWND CreateRenderWindow(std::uint32_t width, std::uint32_t height, const std::wstring_view& title); - -} diff --git a/BasaltPresenter/Shared/engine.cpp b/BasaltPresenter/Shared/engine.cpp index 6a7d8bc..3d318ee 100644 --- a/BasaltPresenter/Shared/engine.cpp +++ b/BasaltPresenter/Shared/engine.cpp @@ -17,8 +17,9 @@ namespace Basalt::Shared::Engine { this->status = EngineStatus::Running; } - void IEngine::Tick() { + bool IEngine::Tick() { if (this->status != EngineStatus::Running) throw std::runtime_error("unexpected engine status"); + return false; } void IEngine::Shutdown() { diff --git a/BasaltPresenter/Shared/engine.hpp b/BasaltPresenter/Shared/engine.hpp index e172d0a..724f657 100644 --- a/BasaltPresenter/Shared/engine.hpp +++ b/BasaltPresenter/Shared/engine.hpp @@ -15,7 +15,7 @@ namespace Basalt::Shared::Engine { }; struct EngineConfig { - bool is_headless; ///< Whether enable headless mode (No Window created). + bool headless; ///< Whether enable headless mode (No Window created). std::basic_string title; ///< Window title. std::uint32_t width; ///< Window width. std::uint32_t height; ///< Window height. @@ -34,7 +34,11 @@ namespace Basalt::Shared::Engine { public: virtual void Startup(EngineConfig&& config); - virtual void Tick(); + /** + * @brief + * @return True for active exit. + */ + virtual bool Tick(); virtual void Shutdown(); protected: