1
0
Files
BasaltMeter/BasaltPresenter/Plugins/Engine/DirectX11Engine/main.cpp
2026-01-04 23:11:58 +08:00

291 lines
11 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include <basalt_export.hpp>
#include <directx_util.hpp>
#include <engine.hpp>
#include <windows.h>
#include <d3d11.h>
#include <d3dcompiler.h>
#include <wrl/client.h>
#include <vector>
#include <iostream>
using Microsoft::WRL::ComPtr;
#define DXCHK(condition) \
if (FAILED(condition)) { \
throw std::runtime_error("bad DirectX calling"); \
}
// 立方体顶点(位置)
struct Vertex {
float x, y, z;
};
// 立方体顶点
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},
{1, 1, 1},
{-1, -1, 1},
{1, 1, 1},
{1, -1, 1},
// 左面
{-1, -1, -1},
{-1, -1, 1},
{-1, 1, 1},
{-1, -1, -1},
{-1, 1, 1},
{-1, 1, -1},
// 右面
{1, -1, -1},
{1, 1, -1},
{1, 1, 1},
{1, -1, -1},
{1, 1, 1},
{1, -1, 1},
// 顶面
{-1, 1, -1},
{1, 1, -1},
{1, 1, 1},
{-1, 1, -1},
{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"(
float4 main(float3 pos : POSITION) : SV_POSITION {
return float4(pos, 1.0f);
}
)";
// 简单像素着色器(返回固定颜色)
const char* g_PS = R"(
float4 main() : SV_TARGET {
return float4(0.2f, 0.4f, 0.8f, 1.0f);
}
)";
using ::Basalt::Shared::Engine::EngineConfig;
using ::Basalt::Shared::Engine::IEngine;
namespace DxUtil = ::Basalt::Shared::DirectX;
class DirectX11Engine : public IEngine {
public:
DirectX11Engine() : IEngine() {}
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; ///< 深度状态
std::vector<BYTE> depth_data; ///< 深度数据
public:
virtual void Startup(EngineConfig&& config) override {
IEngine::Startup(std::move(config));
// 初始化 COM
DXCHK(CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED));
// 创建设备和上下文
DXCHK(D3D11CreateDevice(nullptr,
D3D_DRIVER_TYPE_HARDWARE,
nullptr,
D3D11_CREATE_DEVICE_DEBUG,
nullptr,
0,
D3D11_SDK_VERSION,
&device,
nullptr,
&context));
// 创建交换链(窗口可选,这里仅用于渲染上下文)
DXGI_SWAP_CHAIN_DESC sd = {};
sd.BufferDesc.Width = this->config.width;
sd.BufferDesc.Height = this->config.height;
sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
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.Windowed = TRUE;
ComPtr<IDXGIDevice> dxgi_device;
DXCHK(device.As(&dxgi_device));
ComPtr<IDXGIAdapter> adapter;
DXCHK(dxgi_device->GetAdapter(&adapter));
ComPtr<IDXGIFactory> factory;
DXCHK(adapter->GetParent(IID_PPV_ARGS(&factory)));
DXCHK(factory->CreateSwapChain(device.Get(), &sd, &swap_chain));
// 创建渲染目标
DXCHK(swap_chain->GetBuffer(0, IID_PPV_ARGS(&back_buffer)));
DXCHK(device->CreateRenderTargetView(back_buffer.Get(), nullptr, &rtv));
// 创建深度缓冲D32_FLOAT
D3D11_TEXTURE2D_DESC depth_desc = {};
depth_desc.Width = this->config.width;
depth_desc.Height = this->config.height;
depth_desc.MipLevels = 1;
depth_desc.ArraySize = 1;
depth_desc.Format = DXGI_FORMAT_D32_FLOAT;
depth_desc.SampleDesc.Count = 1;
depth_desc.Usage = D3D11_USAGE_DEFAULT;
depth_desc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
DXCHK(device->CreateTexture2D(&depth_desc, nullptr, &depth_buffer));
DXCHK(device->CreateDepthStencilView(depth_buffer.Get(), nullptr, &dsv));
// 创建 staging texture 用于 CPU 读取深度R32_FLOAT
D3D11_TEXTURE2D_DESC staging_desc = depth_desc;
staging_desc.Format = DXGI_FORMAT_R32_FLOAT; // 注意DSV 用 D32_FLOATstaging 用 R32_FLOAT
staging_desc.BindFlags = 0;
staging_desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
staging_desc.Usage = D3D11_USAGE_STAGING;
DXCHK(device->CreateTexture2D(&staging_desc, nullptr, &depth_staging));
// 编译并创建着色器
DXCHK(D3DCompile(g_VS, static_cast<UINT>(strlen(g_VS)), nullptr, nullptr, nullptr, "main", "vs_4_0", 0, 0, &vs_blob, nullptr));
DXCHK(D3DCompile(g_PS, static_cast<UINT>(strlen(g_PS)), nullptr, nullptr, nullptr, "main", "ps_4_0", 0, 0, &ps_blob, nullptr));
DXCHK(device->CreateVertexShader(vs_blob->GetBufferPointer(), vs_blob->GetBufferSize(), nullptr, &vs));
DXCHK(device->CreatePixelShader(ps_blob->GetBufferPointer(), ps_blob->GetBufferSize(), nullptr, &ps));
// 输入布局
D3D11_INPUT_ELEMENT_DESC layout[] = {{"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0}};
DXCHK(device->CreateInputLayout(layout, 1, vs_blob->GetBufferPointer(), vs_blob->GetBufferSize(), &input_layout));
// 顶点缓冲
D3D11_BUFFER_DESC vb_desc = {};
vb_desc.ByteWidth = sizeof(CubeVertices);
vb_desc.Usage = D3D11_USAGE_DEFAULT;
vb_desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
D3D11_SUBRESOURCE_DATA vb_data = {CubeVertices};
DXCHK(device->CreateBuffer(&vb_desc, &vb_data, &vertex_buffer));
// 深度测试启用
D3D11_DEPTH_STENCIL_DESC ds_desc = {};
ds_desc.DepthEnable = TRUE;
ds_desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
ds_desc.DepthFunc = D3D11_COMPARISON_LESS;
DXCHK(device->CreateDepthStencilState(&ds_desc, &depth_state));
// 视口
D3D11_VIEWPORT vp;
ZeroMemory(&vp, sizeof(D3D11_VIEWPORT));
vp.TopLeftX = 0;
vp.TopLeftY = 0;
vp.Width = (float) this->config.width;
vp.Height = (float) this->config.height;
vp.MinDepth = 0.0f;
vp.MaxDepth = 1.0f;
context->RSSetViewports(1, &vp); // RSSetViewports doesn't return HRESULT, so no need to wrap
//// 打开命名管道(需另一进程已创建)
//constexpr const wchar_t* PipeName = L"\\\\.\\pipe\\54da494c-301a-47a9-9d67-4fbebaeda8cf";
//hPipe = CreateFileW(PipeName, GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, nullptr);
//if (hPipe == INVALID_HANDLE_VALUE) {
// std::cerr << "Failed to open named pipe. Ensure another process created it.\n";
// return;
//}
// 缩放深度数据数组到指定大小
depth_data.resize(this->config.width * this->config.height * sizeof(float));
// 设置管线
context->OMSetRenderTargets(1, rtv.GetAddressOf(), dsv.Get());
context->OMSetDepthStencilState(depth_state.Get(), 1);
context->VSSetShader(vs.Get(), nullptr, 0);
context->PSSetShader(ps.Get(), nullptr, 0);
context->IASetInputLayout(input_layout.Get());
UINT stride = sizeof(Vertex), offset = 0;
context->IASetVertexBuffers(0, 1, vertex_buffer.GetAddressOf(), &stride, &offset);
context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
//frameCount = 0;
}
virtual void Tick() override {
IEngine::Tick();
// 清屏
float clear_color[] = {0.8f, 0.1f, 0.1f, 1.0f};
context->ClearRenderTargetView(rtv.Get(), clear_color);
//context->ClearDepthStencilView(dsv.Get(), D3D11_CLEAR_DEPTH, 1.0f, 0);
//// 设置管线
//context->OMSetRenderTargets(1, rtv.GetAddressOf(), dsv.Get());
//context->OMSetDepthStencilState(depth_state.Get(), 1);
//context->VSSetShader(vs.Get(), nullptr, 0);
//context->PSSetShader(ps.Get(), nullptr, 0);
//context->IASetInputLayout(input_layout.Get());
//UINT stride = sizeof(Vertex), offset = 0;
//context->IASetVertexBuffers(0, 1, vertex_buffer.GetAddressOf(), &stride, &offset);
//context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
// 绘制立方体
context->Draw(sizeof(CubeVertices) / sizeof(Vertex), 0); // 自动计算顶点数
//// 复制深度缓冲到 staging texture
//context->CopyResource(depth_staging.Get(), depth_buffer.Get());
//// Map 获取数据
//D3D11_MAPPED_SUBRESOURCE mapped;
//DXCHK(context->Map(depth_staging.Get(), 0, D3D11_MAP_READ, 0, &mapped));
//memcpy(depth_data.data(), mapped.pData, this->config.width * this->config.height * sizeof(float));
//context->Unmap(depth_staging.Get(), 0);
//// 写入命名管道
//DWORD written;
//if (!WriteFile(hPipe, depth_data.data(), static_cast<DWORD>(this->config.width * this->config.height * sizeof(float)), &written, nullptr) || written != this->config.width * this->config.height * sizeof(float)) {
// std::cerr << "WriteFile failed or incomplete.\n";
//}
// 呈现(可选)
DXCHK(swap_chain->Present(0, 0));
//frameCount++;
}
virtual void Shutdown() override {
IEngine::Shutdown();
//if (hPipe != INVALID_HANDLE_VALUE) {
// CloseHandle(hPipe);
//}
CoUninitialize();
}
};
BS_EXPORT void* BSCreateInstance() {
return new DirectX11Engine();
}
BS_EXPORT void BSDestroyInstance(void* instance) {
delete reinterpret_cast<DirectX11Engine*>(instance);
}