optimize dx11 engine
This commit is contained in:
@@ -1,5 +1,4 @@
|
||||
#include <basalt_export.hpp>
|
||||
#include <directx_util.hpp>
|
||||
#include <engine.hpp>
|
||||
#include <windows.h>
|
||||
#include <d3d11.h>
|
||||
@@ -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<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 {
|
||||
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<ID3D11Device> device; ///< 设备
|
||||
ComPtr<ID3D11DeviceContext> context; ///< 上下文
|
||||
ComPtr<IDXGISwapChain> swap_chain; ///< 交换链
|
||||
ComPtr<ID3D11RenderTargetView> rtv; ///< 渲染目标视图
|
||||
ComPtr<ID3D11Texture2D> back_buffer; ///< 后缓冲
|
||||
ComPtr<ID3D11Texture2D> depth_buffer; ///< 深度缓冲
|
||||
ComPtr<ID3D11DepthStencilView> dsv; ///< 深度模板视图
|
||||
ComPtr<ID3D11Texture2D> depth_staging; ///< 用于CPU读取的深度暂存纹理
|
||||
ComPtr<ID3D11VertexShader> vs; ///< 顶点着色器
|
||||
ComPtr<ID3D11PixelShader> ps; ///< 像素着色器
|
||||
ComPtr<ID3DBlob> vs_blob; ///< 顶点着色器字节码
|
||||
ComPtr<ID3DBlob> ps_blob; ///< 像素着色器字节码
|
||||
ComPtr<ID3D11InputLayout> input_layout; ///< 输入布局
|
||||
ComPtr<ID3D11Buffer> vertex_buffer; ///< 顶点缓冲
|
||||
ComPtr<ID3D11DepthStencilState> depth_state; ///< 深度状态
|
||||
HWND window; ///< Win32窗口
|
||||
ComPtr<ID3D11Device> device; ///< 设备
|
||||
ComPtr<ID3D11DeviceContext> context; ///< 上下文
|
||||
ComPtr<IDXGISwapChain> swap_chain; ///< 交换链
|
||||
ComPtr<ID3D11RenderTargetView> rtv; ///< 渲染目标视图
|
||||
ComPtr<ID3D11Texture2D> back_buffer; ///< 后缓冲
|
||||
ComPtr<ID3D11Texture2D> depth_buffer; ///< 深度缓冲
|
||||
ComPtr<ID3D11DepthStencilView> dsv; ///< 深度模板视图
|
||||
ComPtr<ID3D11Texture2D> depth_staging; ///< 用于CPU读取的深度暂存纹理
|
||||
ComPtr<ID3D11VertexShader> vs; ///< 顶点着色器
|
||||
ComPtr<ID3D11PixelShader> ps; ///< 像素着色器
|
||||
ComPtr<ID3DBlob> vs_blob; ///< 顶点着色器字节码
|
||||
ComPtr<ID3DBlob> ps_blob; ///< 像素着色器字节码
|
||||
ComPtr<ID3D11InputLayout> input_layout; ///< 输入布局
|
||||
ComPtr<ID3D11Buffer> vertex_buffer; ///< 顶点缓冲
|
||||
ComPtr<ID3D11DepthStencilState> depth_state; ///< 深度状态
|
||||
ComPtr<ID3D11RasterizerState> rasterizer_state; ///< 光栅化状态
|
||||
std::vector<BYTE> depth_data; ///< 深度数据
|
||||
std::vector<BYTE> 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<IDXGIDevice> 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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#include "dll_loader.hpp"
|
||||
#include <basalt_char.hpp>
|
||||
#include <stdexcept>
|
||||
#include <filesystem>
|
||||
|
||||
@@ -9,16 +8,18 @@
|
||||
#include <unistd.h>
|
||||
#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<BSCHAR> filename) {
|
||||
DllLoader::DllLoader(DllKind kind, const BSStringView& filename) {
|
||||
// Build DLL full path
|
||||
auto dll_path = get_executable().parent_path();
|
||||
dll_path /= BSTEXT("plugin");
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace Basalt::Presenter {
|
||||
#endif
|
||||
|
||||
public:
|
||||
DllLoader(DllKind kind, const std::basic_string_view<BSCHAR> filename);
|
||||
DllLoader(DllKind kind, const Shared::Char::BSStringView& filename);
|
||||
~DllLoader();
|
||||
|
||||
private:
|
||||
|
||||
@@ -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::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));
|
||||
|
||||
while (true) {
|
||||
engine->Tick();
|
||||
if (engine->Tick()) break;
|
||||
}
|
||||
|
||||
engine->Shutdown();
|
||||
engine_dll.DestroyInstance(engine);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
#include <cwchar>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#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<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;
|
||||
}
|
||||
|
||||
void IEngine::Tick() {
|
||||
bool IEngine::Tick() {
|
||||
if (this->status != EngineStatus::Running) throw std::runtime_error("unexpected engine status");
|
||||
return false;
|
||||
}
|
||||
|
||||
void IEngine::Shutdown() {
|
||||
|
||||
@@ -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<BSCHAR> 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:
|
||||
|
||||
Reference in New Issue
Block a user