D3D12: Fix Quad test screenshot and update texture
- Fix SetGraphicsRootDescriptorTable call order (SetRootSignature before SetPipelineState) - Rename texture earth_d.jpg -> earth.png - Fix vertex order for TriangleStrip quad rendering - Add integration test README - Add debug logging to D3D12Screenshot - Remove obsolete run.bat
This commit is contained in:
@@ -4,6 +4,7 @@
|
|||||||
#include "RHI/D3D12/D3D12Texture.h"
|
#include "RHI/D3D12/D3D12Texture.h"
|
||||||
#include "Debug/Logger.h"
|
#include "Debug/Logger.h"
|
||||||
#include <d3d12.h>
|
#include <d3d12.h>
|
||||||
|
#include <dxgi.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
namespace XCEngine {
|
namespace XCEngine {
|
||||||
@@ -65,6 +66,13 @@ bool D3D12Screenshot::CopyToReadbackAndSave(ID3D12Device* device,
|
|||||||
ID3D12CommandAllocator* cmdAlloc = nullptr;
|
ID3D12CommandAllocator* cmdAlloc = nullptr;
|
||||||
HRESULT hr = device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&cmdAlloc));
|
HRESULT hr = device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&cmdAlloc));
|
||||||
if (FAILED(hr)) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,6 +101,7 @@ bool D3D12Screenshot::CopyToReadbackAndSave(ID3D12Device* device,
|
|||||||
IID_PPV_ARGS(&readbackBuffer));
|
IID_PPV_ARGS(&readbackBuffer));
|
||||||
|
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
|
XCEngine::Debug::Logger::Get().Error(XCEngine::Debug::LogCategory::Rendering, "Screenshot: CreateCommittedResource failed");
|
||||||
cmdAlloc->Release();
|
cmdAlloc->Release();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -100,6 +109,7 @@ bool D3D12Screenshot::CopyToReadbackAndSave(ID3D12Device* device,
|
|||||||
ID3D12GraphicsCommandList* cmdList = nullptr;
|
ID3D12GraphicsCommandList* cmdList = nullptr;
|
||||||
hr = device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, cmdAlloc, nullptr, IID_PPV_ARGS(&cmdList));
|
hr = device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, cmdAlloc, nullptr, IID_PPV_ARGS(&cmdList));
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
|
XCEngine::Debug::Logger::Get().Error(XCEngine::Debug::LogCategory::Rendering, "Screenshot: CreateCommandList failed");
|
||||||
cmdAlloc->Release();
|
cmdAlloc->Release();
|
||||||
readbackBuffer->Release();
|
readbackBuffer->Release();
|
||||||
return false;
|
return false;
|
||||||
@@ -140,11 +150,21 @@ bool D3D12Screenshot::CopyToReadbackAndSave(ID3D12Device* device,
|
|||||||
cmdList->Close();
|
cmdList->Close();
|
||||||
ID3D12CommandList* ppCmdLists[] = { cmdList };
|
ID3D12CommandList* ppCmdLists[] = { cmdList };
|
||||||
commandQueue->ExecuteCommandLists(1, ppCmdLists);
|
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);
|
HANDLE fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
|
||||||
ID3D12Fence* fence = nullptr;
|
ID3D12Fence* fence = nullptr;
|
||||||
hr = device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&fence));
|
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;
|
UINT64 fenceValue = 1;
|
||||||
commandQueue->Signal(fence, fenceValue);
|
commandQueue->Signal(fence, fenceValue);
|
||||||
if (fence->GetCompletedValue() < fenceValue) {
|
if (fence->GetCompletedValue() < fenceValue) {
|
||||||
|
|||||||
@@ -8,4 +8,5 @@ enable_testing()
|
|||||||
|
|
||||||
add_subdirectory(minimal)
|
add_subdirectory(minimal)
|
||||||
add_subdirectory(triangle)
|
add_subdirectory(triangle)
|
||||||
|
add_subdirectory(quad)
|
||||||
add_subdirectory(render_model)
|
add_subdirectory(render_model)
|
||||||
|
|||||||
36
tests/RHI/D3D12/integration/README.md
Normal file
36
tests/RHI/D3D12/integration/README.md
Normal file
@@ -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)
|
||||||
|
**内容**: 模型渲染 (待实现)
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 189 KiB After Width: | Height: | Size: 189 KiB |
@@ -95,8 +95,6 @@ bool LoadTexture(const char* filename, D3D12Texture& texture, D3D12ShaderResourc
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Log("[INFO] Loaded texture %s: %dx%d", filename, width, height);
|
|
||||||
|
|
||||||
allocator.Reset();
|
allocator.Reset();
|
||||||
commandList->Reset(allocator.GetCommandAllocator(), nullptr);
|
commandList->Reset(allocator.GetCommandAllocator(), nullptr);
|
||||||
|
|
||||||
@@ -112,9 +110,8 @@ bool LoadTexture(const char* filename, D3D12Texture& texture, D3D12ShaderResourc
|
|||||||
queue.WaitForIdle();
|
queue.WaitForIdle();
|
||||||
|
|
||||||
texture.SetName(filename);
|
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);
|
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = D3D12ShaderResourceView::CreateDesc(Format::R8G8B8A8_UNorm, D3D12_SRV_DIMENSION_TEXTURE2D);
|
||||||
srv.InitializeAt(device, texture.GetResource(), srvHeap.GetCPUDescriptorHandleForHeapStart(), &srvDesc);
|
srv.InitializeAt(device, texture.GetResource(), srvHeap.GetCPUDescriptorHandleForHeapStart(), &srvDesc);
|
||||||
|
|
||||||
@@ -263,8 +260,8 @@ bool InitD3D12() {
|
|||||||
Vertex vertices[] = {
|
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, 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 }, { 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, 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)) {
|
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.SetStride(sizeof(Vertex));
|
||||||
gVertexBuffer.SetBufferType(BufferType::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");
|
Log("[ERROR] Failed to load texture");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -384,23 +381,21 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
|||||||
|
|
||||||
BeginRender();
|
BeginRender();
|
||||||
|
|
||||||
|
gCommandList.SetRootSignature(gRootSignature.GetRootSignature());
|
||||||
|
gCommandList.SetPipelineState(gPipelineState.GetPipelineState());
|
||||||
|
|
||||||
ID3D12DescriptorHeap* heaps[] = { gSRVHeap.GetDescriptorHeap() };
|
ID3D12DescriptorHeap* heaps[] = { gSRVHeap.GetDescriptorHeap() };
|
||||||
gCommandList.SetDescriptorHeaps(1, heaps);
|
gCommandList.SetDescriptorHeaps(1, heaps);
|
||||||
gCommandList.SetGraphicsRootDescriptorTable(0, gSRVHeap.GetGPUDescriptorHandleForHeapStart());
|
gCommandList.SetGraphicsRootDescriptorTable(0, gSRVHeap.GetGPUDescriptorHandleForHeapStart());
|
||||||
|
gCommandList.SetPrimitiveTopology(PrimitiveTopology::TriangleStrip);
|
||||||
gCommandList.SetPipelineState(gPipelineState.GetPipelineState());
|
|
||||||
gCommandList.SetRootSignature(gRootSignature.GetRootSignature());
|
|
||||||
gCommandList.SetPrimitiveTopology(PrimitiveTopology::TriangleList);
|
|
||||||
gCommandList.SetVertexBuffer(0, gVertexBuffer.GetResource(), 0, gVertexBuffer.GetStride());
|
gCommandList.SetVertexBuffer(0, gVertexBuffer.GetResource(), 0, gVertexBuffer.GetStride());
|
||||||
gCommandList.Draw(4, 1, 0, 0);
|
gCommandList.Draw(4, 1, 0, 0);
|
||||||
|
|
||||||
frameCount++;
|
frameCount++;
|
||||||
|
|
||||||
if (frameCount >= targetFrameCount) {
|
if (frameCount >= targetFrameCount) {
|
||||||
Log("[INFO] Reached target frame count %d - taking screenshot!", targetFrameCount);
|
|
||||||
ExecuteCommandList();
|
ExecuteCommandList();
|
||||||
WaitForGPU();
|
WaitForGPU();
|
||||||
Log("[INFO] GPU idle, taking screenshot...");
|
|
||||||
|
|
||||||
bool screenshotResult = D3D12Screenshot::Capture(
|
bool screenshotResult = D3D12Screenshot::Capture(
|
||||||
gDevice,
|
gDevice,
|
||||||
|
|||||||
@@ -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
|
|
||||||
Reference in New Issue
Block a user