diff --git a/engine/src/RHI/D3D12/D3D12Screenshot.cpp b/engine/src/RHI/D3D12/D3D12Screenshot.cpp index d52ac4e1..6adfae68 100644 --- a/engine/src/RHI/D3D12/D3D12Screenshot.cpp +++ b/engine/src/RHI/D3D12/D3D12Screenshot.cpp @@ -4,6 +4,7 @@ #include "RHI/D3D12/D3D12Texture.h" #include "Debug/Logger.h" #include +#include #include namespace XCEngine { @@ -65,6 +66,13 @@ bool D3D12Screenshot::CopyToReadbackAndSave(ID3D12Device* device, ID3D12CommandAllocator* cmdAlloc = nullptr; HRESULT hr = device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&cmdAlloc)); if (FAILED(hr)) { + XCEngine::Debug::Logger::Get().Error(XCEngine::Debug::LogCategory::Rendering, "Screenshot: CreateCommandAllocator failed"); + if (hr == DXGI_ERROR_DEVICE_REMOVED) { + HRESULT removedReason = device->GetDeviceRemovedReason(); + char reasonMsg[256]; + sprintf_s(reasonMsg, sizeof(reasonMsg), "Screenshot: Device removed reason: 0x%X", removedReason); + XCEngine::Debug::Logger::Get().Error(XCEngine::Debug::LogCategory::Rendering, reasonMsg); + } return false; } @@ -93,6 +101,7 @@ bool D3D12Screenshot::CopyToReadbackAndSave(ID3D12Device* device, IID_PPV_ARGS(&readbackBuffer)); if (FAILED(hr)) { + XCEngine::Debug::Logger::Get().Error(XCEngine::Debug::LogCategory::Rendering, "Screenshot: CreateCommittedResource failed"); cmdAlloc->Release(); return false; } @@ -100,6 +109,7 @@ bool D3D12Screenshot::CopyToReadbackAndSave(ID3D12Device* device, ID3D12GraphicsCommandList* cmdList = nullptr; hr = device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, cmdAlloc, nullptr, IID_PPV_ARGS(&cmdList)); if (FAILED(hr)) { + XCEngine::Debug::Logger::Get().Error(XCEngine::Debug::LogCategory::Rendering, "Screenshot: CreateCommandList failed"); cmdAlloc->Release(); readbackBuffer->Release(); return false; @@ -140,11 +150,21 @@ bool D3D12Screenshot::CopyToReadbackAndSave(ID3D12Device* device, cmdList->Close(); ID3D12CommandList* ppCmdLists[] = { cmdList }; commandQueue->ExecuteCommandLists(1, ppCmdLists); + XCEngine::Debug::Logger::Get().Info(XCEngine::Debug::LogCategory::Rendering, "Screenshot: ExecuteCommandLists done, waiting for fence..."); HANDLE fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr); ID3D12Fence* fence = nullptr; hr = device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&fence)); - if (SUCCEEDED(hr)) { + if (FAILED(hr)) { + XCEngine::Debug::Logger::Get().Error(XCEngine::Debug::LogCategory::Rendering, "Screenshot: CreateFence failed"); + cmdList->Release(); + cmdAlloc->Release(); + readbackBuffer->Release(); + CloseHandle(fenceEvent); + return false; + } + XCEngine::Debug::Logger::Get().Info(XCEngine::Debug::LogCategory::Rendering, "Screenshot: Fence created, waiting..."); + { UINT64 fenceValue = 1; commandQueue->Signal(fence, fenceValue); if (fence->GetCompletedValue() < fenceValue) { diff --git a/tests/RHI/D3D12/integration/CMakeLists.txt b/tests/RHI/D3D12/integration/CMakeLists.txt index 4817c280..9f89d72a 100644 --- a/tests/RHI/D3D12/integration/CMakeLists.txt +++ b/tests/RHI/D3D12/integration/CMakeLists.txt @@ -8,4 +8,5 @@ enable_testing() add_subdirectory(minimal) add_subdirectory(triangle) +add_subdirectory(quad) add_subdirectory(render_model) diff --git a/tests/RHI/D3D12/integration/README.md b/tests/RHI/D3D12/integration/README.md new file mode 100644 index 00000000..58b2ec5b --- /dev/null +++ b/tests/RHI/D3D12/integration/README.md @@ -0,0 +1,36 @@ +# D3D12 Integration Tests + +## minimal +**后端**: D3D12Device, DXGIFactory, CommandQueue, CommandList, SwapChain +**内容**: 最小 D3D12 初始化流程,创建窗口和交换链,无渲染输出 + +--- + +## triangle +**后端**: D3D12Device, DXGIFactory, CommandQueue, CommandList, SwapChain, Buffer, Shader, RootSignature, PipelineState, RenderTargetView, DepthStencilView, Screenshot +**内容**: +- 基础三角形渲染 +- 顶点 buffer 上传 +- HLSL shader 编译 (vs_5_1, ps_5_1) +- Root signature + PSO 创建 +- RenderTarget 切换 (Present ↔ RenderTarget) +- 截图功能验证 + +--- + +## quad +**后端**: triangle 的全部 + Texture, DescriptorHeap, ShaderResourceView +**内容**: +- 四边形纹理采样渲染 +- Texture 加载与初始化 (stb_image) +- DescriptorHeap (CBV_SRV_UAV) + SRV 创建 +- 静态采样器配置 +- Root signature descriptor table +- SetDescriptorHeaps + SetGraphicsRootDescriptorTable +- 截图功能验证 + +--- + +## render_model +**后端**: (TODO) +**内容**: 模型渲染 (待实现) diff --git a/tests/RHI/D3D12/integration/quad/GT.ppm b/tests/RHI/D3D12/integration/quad/GT.ppm index 6fd275e4..a8920605 100644 Binary files a/tests/RHI/D3D12/integration/quad/GT.ppm and b/tests/RHI/D3D12/integration/quad/GT.ppm differ diff --git a/tests/RHI/D3D12/integration/quad/Res/Image/earth_d.jpg b/tests/RHI/D3D12/integration/quad/Res/Image/earth.png similarity index 100% rename from tests/RHI/D3D12/integration/quad/Res/Image/earth_d.jpg rename to tests/RHI/D3D12/integration/quad/Res/Image/earth.png diff --git a/tests/RHI/D3D12/integration/quad/main.cpp b/tests/RHI/D3D12/integration/quad/main.cpp index 0852042f..45add888 100644 --- a/tests/RHI/D3D12/integration/quad/main.cpp +++ b/tests/RHI/D3D12/integration/quad/main.cpp @@ -95,8 +95,6 @@ bool LoadTexture(const char* filename, D3D12Texture& texture, D3D12ShaderResourc return false; } - Log("[INFO] Loaded texture %s: %dx%d", filename, width, height); - allocator.Reset(); commandList->Reset(allocator.GetCommandAllocator(), nullptr); @@ -112,9 +110,8 @@ bool LoadTexture(const char* filename, D3D12Texture& texture, D3D12ShaderResourc queue.WaitForIdle(); texture.SetName(filename); - stbi_image_free(pixels); - srvHeap.Initialize(device, DescriptorHeapType::CBV_SRV_UAV, 1); + srvHeap.Initialize(device, DescriptorHeapType::CBV_SRV_UAV, 1, true); D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = D3D12ShaderResourceView::CreateDesc(Format::R8G8B8A8_UNorm, D3D12_SRV_DIMENSION_TEXTURE2D); srv.InitializeAt(device, texture.GetResource(), srvHeap.GetCPUDescriptorHandleForHeapStart(), &srvDesc); @@ -263,8 +260,8 @@ bool InitD3D12() { Vertex vertices[] = { { { -0.5f, -0.5f, 0.0f, 1.0f }, { 0.0f, 1.0f, 0.0f, 0.0f } }, { { -0.5f, 0.5f, 0.0f, 1.0f }, { 0.0f, 0.0f, 0.0f, 0.0f } }, - { { 0.5f, 0.5f, 0.0f, 1.0f }, { 1.0f, 0.0f, 0.0f, 0.0f } }, { { 0.5f, -0.5f, 0.0f, 1.0f }, { 1.0f, 1.0f, 0.0f, 0.0f } }, + { { 0.5f, 0.5f, 0.0f, 1.0f }, { 1.0f, 0.0f, 0.0f, 0.0f } }, }; if (!gVertexBuffer.InitializeWithData(device, gCommandList.GetCommandList(), vertices, sizeof(vertices), D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER)) { @@ -274,7 +271,7 @@ bool InitD3D12() { gVertexBuffer.SetStride(sizeof(Vertex)); gVertexBuffer.SetBufferType(BufferType::Vertex); - if (!LoadTexture("Res/Image/earth_d.jpg", gDiffuseTexture, gDiffuseSRV, device, gSRVHeap, gCommandList.GetCommandList(), gCommandAllocator, gCommandQueue)) { + if (!LoadTexture("Res/Image/earth.png", gDiffuseTexture, gDiffuseSRV, device, gSRVHeap, gCommandList.GetCommandList(), gCommandAllocator, gCommandQueue)) { Log("[ERROR] Failed to load texture"); return false; } @@ -384,24 +381,22 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine BeginRender(); + gCommandList.SetRootSignature(gRootSignature.GetRootSignature()); + gCommandList.SetPipelineState(gPipelineState.GetPipelineState()); + ID3D12DescriptorHeap* heaps[] = { gSRVHeap.GetDescriptorHeap() }; gCommandList.SetDescriptorHeaps(1, heaps); gCommandList.SetGraphicsRootDescriptorTable(0, gSRVHeap.GetGPUDescriptorHandleForHeapStart()); - - gCommandList.SetPipelineState(gPipelineState.GetPipelineState()); - gCommandList.SetRootSignature(gRootSignature.GetRootSignature()); - gCommandList.SetPrimitiveTopology(PrimitiveTopology::TriangleList); + gCommandList.SetPrimitiveTopology(PrimitiveTopology::TriangleStrip); gCommandList.SetVertexBuffer(0, gVertexBuffer.GetResource(), 0, gVertexBuffer.GetStride()); gCommandList.Draw(4, 1, 0, 0); frameCount++; if (frameCount >= targetFrameCount) { - Log("[INFO] Reached target frame count %d - taking screenshot!", targetFrameCount); ExecuteCommandList(); WaitForGPU(); - Log("[INFO] GPU idle, taking screenshot..."); - + bool screenshotResult = D3D12Screenshot::Capture( gDevice, gCommandQueue, diff --git a/tests/RHI/D3D12/integration/run.bat b/tests/RHI/D3D12/integration/run.bat deleted file mode 100644 index 700d7364..00000000 --- a/tests/RHI/D3D12/integration/run.bat +++ /dev/null @@ -1,7 +0,0 @@ -@echo off -cd /d "%~dp0..\..\..\..\build\tests\RHI\D3D12\integration\Debug" -if exist "D3D12_engine_log.txt" del "D3D12_engine_log.txt" -if exist "screenshot.ppm" del "screenshot.ppm" -D3D12.exe -python "%~dp0compare_ppm.py" "screenshot.ppm" "GT.ppm" 5 -pause \ No newline at end of file