optimize dx11 engine
This commit is contained in:
@@ -1,5 +1,4 @@
|
|||||||
#include <basalt_export.hpp>
|
#include <basalt_export.hpp>
|
||||||
#include <directx_util.hpp>
|
|
||||||
#include <engine.hpp>
|
#include <engine.hpp>
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <d3d11.h>
|
#include <d3d11.h>
|
||||||
@@ -14,6 +13,91 @@ using Microsoft::WRL::ComPtr;
|
|||||||
throw std::runtime_error("bad DirectX calling"); \
|
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<LONG>(width), static_cast<LONG>(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 {
|
struct Vertex {
|
||||||
float x, y, z;
|
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},
|
{1, -1, 1},
|
||||||
{1, -1, -1}
|
{1, -1, -1}};
|
||||||
};
|
|
||||||
|
|
||||||
// 简单顶点着色器(只传位置)
|
// 简单顶点着色器(只传位置)
|
||||||
const char* g_VS = R"(
|
const char* g_VS = R"(
|
||||||
@@ -80,7 +163,6 @@ const char* g_PS = R"(
|
|||||||
|
|
||||||
using ::Basalt::Shared::Engine::EngineConfig;
|
using ::Basalt::Shared::Engine::EngineConfig;
|
||||||
using ::Basalt::Shared::Engine::IEngine;
|
using ::Basalt::Shared::Engine::IEngine;
|
||||||
namespace DxUtil = ::Basalt::Shared::DirectX;
|
|
||||||
|
|
||||||
class DirectX11Engine : public IEngine {
|
class DirectX11Engine : public IEngine {
|
||||||
public:
|
public:
|
||||||
@@ -88,6 +170,7 @@ public:
|
|||||||
virtual ~DirectX11Engine() {}
|
virtual ~DirectX11Engine() {}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
HWND window; ///< Win32窗口
|
||||||
ComPtr<ID3D11Device> device; ///< 设备
|
ComPtr<ID3D11Device> device; ///< 设备
|
||||||
ComPtr<ID3D11DeviceContext> context; ///< 上下文
|
ComPtr<ID3D11DeviceContext> context; ///< 上下文
|
||||||
ComPtr<IDXGISwapChain> swap_chain; ///< 交换链
|
ComPtr<IDXGISwapChain> swap_chain; ///< 交换链
|
||||||
@@ -110,6 +193,15 @@ public:
|
|||||||
virtual void Startup(EngineConfig&& config) override {
|
virtual void Startup(EngineConfig&& config) override {
|
||||||
IEngine::Startup(std::move(config));
|
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
|
// 初始化 COM
|
||||||
DXCHK(CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED));
|
DXCHK(CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED));
|
||||||
|
|
||||||
@@ -133,7 +225,7 @@ public:
|
|||||||
sd.SampleDesc.Count = 1;
|
sd.SampleDesc.Count = 1;
|
||||||
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
||||||
sd.BufferCount = 1;
|
sd.BufferCount = 1;
|
||||||
sd.OutputWindow = DxUtil::CreateRenderWindow(this->config.width, this->config.height, this->config.title); // 创建窗口
|
sd.OutputWindow = window;
|
||||||
sd.Windowed = TRUE;
|
sd.Windowed = TRUE;
|
||||||
|
|
||||||
ComPtr<IDXGIDevice> dxgi_device;
|
ComPtr<IDXGIDevice> dxgi_device;
|
||||||
@@ -228,13 +320,11 @@ public:
|
|||||||
//frameCount = 0;
|
//frameCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void Tick() override {
|
virtual bool Tick() override {
|
||||||
IEngine::Tick();
|
if (IEngine::Tick()) return true;
|
||||||
|
|
||||||
MSG msg;
|
// Event loop
|
||||||
GetMessage(&msg, nullptr, 0, 0);
|
if (EventLoop()) return true;
|
||||||
TranslateMessage(&msg);
|
|
||||||
DispatchMessage(&msg);
|
|
||||||
|
|
||||||
// 清屏
|
// 清屏
|
||||||
float clear_color[] = {0.8f, 0.1f, 0.1f, 1.0f};
|
float clear_color[] = {0.8f, 0.1f, 0.1f, 1.0f};
|
||||||
@@ -274,6 +364,8 @@ public:
|
|||||||
DXCHK(swap_chain->Present(0, 0));
|
DXCHK(swap_chain->Present(0, 0));
|
||||||
|
|
||||||
//frameCount++;
|
//frameCount++;
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void Shutdown() override {
|
virtual void Shutdown() override {
|
||||||
@@ -283,6 +375,10 @@ public:
|
|||||||
// CloseHandle(hPipe);
|
// CloseHandle(hPipe);
|
||||||
//}
|
//}
|
||||||
CoUninitialize();
|
CoUninitialize();
|
||||||
|
if (!this->config.headless) {
|
||||||
|
CloseWindow(window);
|
||||||
|
DestroyRenderWindow(window);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
#include "dll_loader.hpp"
|
#include "dll_loader.hpp"
|
||||||
#include <basalt_char.hpp>
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
|
||||||
@@ -9,16 +8,18 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
using ::Basalt::Shared::Char::BSStringView;
|
||||||
|
|
||||||
namespace Basalt::Presenter {
|
namespace Basalt::Presenter {
|
||||||
|
|
||||||
static std::filesystem::path get_executable() {
|
static std::filesystem::path get_executable() {
|
||||||
#if defined(BASALT_OS_WINDOWS)
|
#if defined(BASALT_OS_WINDOWS)
|
||||||
wchar_t buffer[MAX_PATH];
|
wchar_t buffer[MAX_PATH];
|
||||||
DWORD hr = GetModuleFileNameW(NULL, buffer, MAX_PATH);
|
DWORD hr = GetModuleFileNameW(NULL, buffer, MAX_PATH);
|
||||||
if (hr == 0) {
|
if (hr > 0 && hr < MAX_PATH) {
|
||||||
throw std::runtime_error("Failed to get executable path");
|
|
||||||
} else {
|
|
||||||
return std::filesystem::path(buffer);
|
return std::filesystem::path(buffer);
|
||||||
|
} else {
|
||||||
|
throw std::runtime_error("Failed to get executable path");
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
char buffer[PATH_MAX];
|
char buffer[PATH_MAX];
|
||||||
@@ -32,7 +33,7 @@ namespace Basalt::Presenter {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
DllLoader::DllLoader(DllKind kind, const std::basic_string_view<BSCHAR> filename) {
|
DllLoader::DllLoader(DllKind kind, const BSStringView& filename) {
|
||||||
// Build DLL full path
|
// Build DLL full path
|
||||||
auto dll_path = get_executable().parent_path();
|
auto dll_path = get_executable().parent_path();
|
||||||
dll_path /= BSTEXT("plugin");
|
dll_path /= BSTEXT("plugin");
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ namespace Basalt::Presenter {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DllLoader(DllKind kind, const std::basic_string_view<BSCHAR> filename);
|
DllLoader(DllKind kind, const Shared::Char::BSStringView& filename);
|
||||||
~DllLoader();
|
~DllLoader();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -8,12 +8,14 @@ namespace Shared = ::Basalt::Shared;
|
|||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
auto engine_dll = Presenter::DllLoader(Presenter::DllKind::Engine, BSTEXT("BasaltDirectX11Engine"));
|
auto engine_dll = Presenter::DllLoader(Presenter::DllKind::Engine, BSTEXT("BasaltDirectX11Engine"));
|
||||||
auto* engine = engine_dll.CreateInstance<Shared::Engine::IEngine>();
|
auto* engine = engine_dll.CreateInstance<Shared::Engine::IEngine>();
|
||||||
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));
|
engine->Startup(std::move(engine_config));
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
engine->Tick();
|
if (engine->Tick()) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
engine->Shutdown();
|
engine->Shutdown();
|
||||||
|
engine_dll.DestroyInstance(engine);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ PRIVATE
|
|||||||
pipe_operator.cpp
|
pipe_operator.cpp
|
||||||
engine.cpp
|
engine.cpp
|
||||||
deliver.cpp
|
deliver.cpp
|
||||||
directx_util.cpp
|
|
||||||
)
|
)
|
||||||
target_sources(BasaltShared
|
target_sources(BasaltShared
|
||||||
PUBLIC
|
PUBLIC
|
||||||
@@ -17,7 +17,6 @@ FILES
|
|||||||
pipe_operator.hpp
|
pipe_operator.hpp
|
||||||
engine.hpp
|
engine.hpp
|
||||||
deliver.hpp
|
deliver.hpp
|
||||||
directx_util.hpp
|
|
||||||
)
|
)
|
||||||
target_include_directories(BasaltShared
|
target_include_directories(BasaltShared
|
||||||
PUBLIC
|
PUBLIC
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
#include <cwchar>
|
#include <cwchar>
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
#if defined(BASALT_OS_WINDOWS)
|
#if defined(BASALT_OS_WINDOWS)
|
||||||
#define BSCHAR wchar_t
|
#define BSCHAR wchar_t
|
||||||
@@ -8,3 +10,10 @@
|
|||||||
#define BSCHAR char
|
#define BSCHAR char
|
||||||
#define BSTEXT(x) x
|
#define BSTEXT(x) x
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
namespace Basalt::Shared::Char {
|
||||||
|
|
||||||
|
using BSString = std::basic_string<BSCHAR>;
|
||||||
|
using BSStringView = std::basic_string_view<BSCHAR>;
|
||||||
|
|
||||||
|
}; // namespace Basalt::Shared::Char
|
||||||
|
|||||||
@@ -1,67 +0,0 @@
|
|||||||
#include "directx_util.hpp"
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
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<LONG>(width), static_cast<LONG>(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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <cinttypes>
|
|
||||||
#include <string_view>
|
|
||||||
#include <windows.h>
|
|
||||||
|
|
||||||
namespace Basalt::Shared::DirectX {
|
|
||||||
|
|
||||||
HWND CreateRenderWindow(std::uint32_t width, std::uint32_t height, const std::wstring_view& title);
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -17,8 +17,9 @@ namespace Basalt::Shared::Engine {
|
|||||||
this->status = EngineStatus::Running;
|
this->status = EngineStatus::Running;
|
||||||
}
|
}
|
||||||
|
|
||||||
void IEngine::Tick() {
|
bool IEngine::Tick() {
|
||||||
if (this->status != EngineStatus::Running) throw std::runtime_error("unexpected engine status");
|
if (this->status != EngineStatus::Running) throw std::runtime_error("unexpected engine status");
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void IEngine::Shutdown() {
|
void IEngine::Shutdown() {
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ namespace Basalt::Shared::Engine {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct EngineConfig {
|
struct EngineConfig {
|
||||||
bool is_headless; ///< Whether enable headless mode (No Window created).
|
bool headless; ///< Whether enable headless mode (No Window created).
|
||||||
std::basic_string<BSCHAR> title; ///< Window title.
|
std::basic_string<BSCHAR> title; ///< Window title.
|
||||||
std::uint32_t width; ///< Window width.
|
std::uint32_t width; ///< Window width.
|
||||||
std::uint32_t height; ///< Window height.
|
std::uint32_t height; ///< Window height.
|
||||||
@@ -34,7 +34,11 @@ namespace Basalt::Shared::Engine {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
virtual void Startup(EngineConfig&& config);
|
virtual void Startup(EngineConfig&& config);
|
||||||
virtual void Tick();
|
/**
|
||||||
|
* @brief
|
||||||
|
* @return True for active exit.
|
||||||
|
*/
|
||||||
|
virtual bool Tick();
|
||||||
virtual void Shutdown();
|
virtual void Shutdown();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|||||||
Reference in New Issue
Block a user