diff --git a/engine/src/RHI/D3D12Device.cpp b/engine/src/RHI/D3D12Device.cpp index 31babad2..d0b18b7a 100644 --- a/engine/src/RHI/D3D12Device.cpp +++ b/engine/src/RHI/D3D12Device.cpp @@ -1,4 +1,5 @@ #include "XCEngine/RHI/D3D12/D3D12Device.h" +#include #ifdef _DEBUG #include @@ -75,8 +76,7 @@ void D3D12Device::Shutdown() { bool D3D12Device::CreateDXGIFactory(bool enableDebugLayer) { UINT dxgiFactoryFlags = 0; -#ifdef _DEBUG - if (enableDebugLayer) { + { ID3D12Debug* debugController = nullptr; if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&debugController)))) { debugController->EnableDebugLayer(); @@ -84,14 +84,19 @@ bool D3D12Device::CreateDXGIFactory(bool enableDebugLayer) { debugController->Release(); } } -#endif HRESULT hr = CreateDXGIFactory2(dxgiFactoryFlags, IID_PPV_ARGS(&m_factory)); return SUCCEEDED(hr); } bool D3D12Device::CreateDevice(IDXGIAdapter1* adapter) { + OutputDebugStringA("[DEBUG] CreateDevice: start\n"); HRESULT hr = D3D12CreateDevice(adapter, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&m_device)); + if (FAILED(hr)) { + char buf[256]; + sprintf(buf, "[DEBUG] CreateDevice: D3D12CreateDevice failed! hr=%08X\n", hr); + OutputDebugStringA(buf); + } return SUCCEEDED(hr); } diff --git a/tests/D3D12/main.cpp b/tests/D3D12/main.cpp index 9a1bc69d..ed8dc227 100644 --- a/tests/D3D12/main.cpp +++ b/tests/D3D12/main.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -25,6 +26,22 @@ using namespace XCEngine::RHI; #pragma comment(lib,"d3dcompiler.lib") #pragma comment(lib,"winmm.lib") +static FILE* gLogFile = nullptr; + +void Log(const char* format, ...) { + va_list args; + va_start(args, format); + vprintf(format, args); + va_end(args); + + if (gLogFile) { + va_start(args, format); + vfprintf(gLogFile, format, args); + va_end(args); + fflush(gLogFile); + } +} + //================================================================================= // D3D12 核心全局对象 (最小渲染所需) //================================================================================= @@ -285,7 +302,7 @@ void CreateShaderFromFile( if (FAILED(hResult)) { char szLog[1024] = { 0 }; strcpy_s(szLog, (char*)errorBuffer->GetBufferPointer()); - printf("CreateShaderFromFile error : [%s][%s]:[%s]\n", inMainFunctionName, inTarget, szLog); + Log("CreateShaderFromFile error : [%s][%s]:[%s]\n", inMainFunctionName, inTarget, szLog); errorBuffer->Release(); return; } @@ -726,31 +743,48 @@ void SwapD3D12Buffers() { // 使用 Readback 方式读取渲染目标并保存为 PPM 格式 //================================================================================= bool SaveScreenshot(const char* filename, int width, int height) { - ID3D12Device* device = gDevice.GetDevice(); - ID3D12CommandQueue* queue = gCommandQueue.GetCommandQueue(); - int currentRTIndex = gSwapChain->GetCurrentBackBufferIndex(); - + Log("[DEBUG] SaveScreenshot: start\n"); + + XCEngine::RHI::D3D12Device& deviceWrapper = gDevice; + ID3D12Device* device = deviceWrapper.GetDevice(); + Log("[DEBUG] SaveScreenshot: device = %p\n", device); + + IDXGISwapChain3* swapChain = gSwapChain; + + // Wait for previous frame to finish + Log("[DEBUG] SaveScreenshot: waiting for GPU\n"); + WaitForCompletionOfCommandList(); + + // Get current back buffer index + int currentRTIndex = swapChain->GetCurrentBackBufferIndex(); + Log("[DEBUG] SaveScreenshot: currentRTIndex = %d\n", currentRTIndex); + + // Use existing render target ID3D12Resource* renderTarget = gColorRTs[currentRTIndex]; - - D3D12_RESOURCE_DESC desc = renderTarget->GetDesc(); + Log("[DEBUG] SaveScreenshot: renderTarget = %p\n", renderTarget); + + // Need to transition from PRESENT to COPY_SOURCE for reading + HRESULT hr = S_OK; + ID3D12CommandAllocator* cmdAlloc = nullptr; + hr = device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&cmdAlloc)); D3D12_HEAP_PROPERTIES heapProps = {}; heapProps.Type = D3D12_HEAP_TYPE_READBACK; - heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_WRITE_BACK; - heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_L0; - D3D12_RESOURCE_DESC readbackDesc = {}; readbackDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; - readbackDesc.Width = width * height * 4; + readbackDesc.Alignment = 0; + readbackDesc.Width = (UINT64)width * height * 4; readbackDesc.Height = 1; readbackDesc.DepthOrArraySize = 1; readbackDesc.MipLevels = 1; readbackDesc.Format = DXGI_FORMAT_UNKNOWN; + readbackDesc.SampleDesc.Count = 1; + readbackDesc.SampleDesc.Quality = 0; readbackDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; readbackDesc.Flags = D3D12_RESOURCE_FLAG_NONE; ID3D12Resource* readbackBuffer = nullptr; - HRESULT hr = device->CreateCommittedResource( + hr = device->CreateCommittedResource( &heapProps, D3D12_HEAP_FLAG_NONE, &readbackDesc, @@ -759,17 +793,31 @@ bool SaveScreenshot(const char* filename, int width, int height) { IID_PPV_ARGS(&readbackBuffer)); if (FAILED(hr)) { + Log("[DEBUG] SaveScreenshot: CreateCommittedResource failed! hr=%08X\n", hr); + return false; + } + Log("[DEBUG] SaveScreenshot: created readback buffer\n"); + + hr = device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&cmdAlloc)); + if (FAILED(hr)) { + Log("[DEBUG] SaveScreenshot: CreateCommandAllocator failed! hr=%08X\n", hr); + readbackBuffer->Release(); return false; } - ID3D12CommandAllocator* cmdAlloc = nullptr; - device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&cmdAlloc)); - ID3D12GraphicsCommandList* cmdList = nullptr; - 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)) { + Log("[DEBUG] SaveScreenshot: CreateCommandList failed! hr=%08X\n", hr); + cmdAlloc->Release(); + readbackBuffer->Release(); + return false; + } + Log("[DEBUG] SaveScreenshot: copying resource\n"); D3D12_RESOURCE_BARRIER barrier = {}; barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; + barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE; barrier.Transition.pResource = renderTarget; barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT; barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_SOURCE; @@ -784,28 +832,45 @@ bool SaveScreenshot(const char* filename, int width, int height) { cmdList->Close(); ID3D12CommandList* ppCmdLists[] = { cmdList }; + ID3D12CommandQueue* queue = gCommandQueue.GetCommandQueue(); queue->ExecuteCommandLists(1, ppCmdLists); - gFence.Initialize(device, 0); - gFence.Signal(1); - gFence.Wait(1); + Log("[DEBUG] SaveScreenshot: waiting for GPU copy\n"); + gFenceValue += 1; + queue->Signal(gFence.GetFence(), gFenceValue); + gFence.Wait(gFenceValue); - D3D12_RANGE readRange = { 0, width * height * 4 }; + Log("[DEBUG] SaveScreenshot: mapping memory\n"); + D3D12_RANGE readRange = { 0, 0 }; unsigned char* mappedData = nullptr; - readbackBuffer->Map(0, &readRange, (void**)&mappedData); - - FILE* fp = fopen(filename, "wb"); - if (!fp) { - readbackBuffer->Release(); + hr = readbackBuffer->Map(0, &readRange, (void**)&mappedData); + if (FAILED(hr)) { + Log("[DEBUG] SaveScreenshot: Map failed! hr=%08X\n", hr); cmdList->Release(); cmdAlloc->Release(); + readbackBuffer->Release(); + return false; + } + + D3D12_RESOURCE_DESC desc = readbackBuffer->GetDesc(); + UINT rowPitch = width * 4; + Log("[DEBUG] SaveScreenshot: rowPitch = %u\n", rowPitch); + + Log("[DEBUG] SaveScreenshot: writing file\n"); + FILE* fp = fopen(filename, "wb"); + if (!fp) { + Log("[DEBUG] SaveScreenshot: fopen failed!\n"); + readbackBuffer->Unmap(0, nullptr); + cmdList->Release(); + cmdAlloc->Release(); + readbackBuffer->Release(); return false; } fprintf(fp, "P6\n%d %d\n255\n", width, height); for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { - int idx = (y * width + x) * 4; + int idx = y * rowPitch + x * 4; unsigned char r = mappedData[idx + 2]; unsigned char g = mappedData[idx + 1]; unsigned char b = mappedData[idx + 0]; @@ -819,10 +884,11 @@ bool SaveScreenshot(const char* filename, int width, int height) { D3D12_RANGE writeRange = { 0, 0 }; readbackBuffer->Unmap(0, &writeRange); - readbackBuffer->Release(); cmdList->Release(); cmdAlloc->Release(); + readbackBuffer->Release(); + Log("[DEBUG] SaveScreenshot: done!\n"); return true; } @@ -855,6 +921,12 @@ LRESULT CALLBACK WindowProc(HWND inHWND, UINT inMSG, WPARAM inWParam, LPARAM inL // 程序入口点 //================================================================================= int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int inShowCmd) { + fopen_s(&gLogFile, "D3D12_log.txt", "w"); + + AllocConsole(); + freopen("CONOUT$", "w", stdout); + Log("[DEBUG] D3D12 Test Application Started\n"); + WNDCLASSEX wndClassEx; wndClassEx.cbSize = sizeof(WNDCLASSEX); wndClassEx.style = CS_HREDRAW | CS_VREDRAW; @@ -989,9 +1061,14 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine TranslateMessage(&msg); DispatchMessage(&msg); } else { - frameCount++; + frameCount++; if (frameCount == 2) { - SaveScreenshot("screenshot.png", 1280, 720); + Log("[DEBUG] Saving screenshot at frame %d...\n", frameCount); + if (SaveScreenshot("screenshot.ppm", 1280, 720)) { + Log("[DEBUG] Screenshot saved to screenshot.ppm\n"); + } else { + Log("[DEBUG] Failed to save screenshot!\n"); + } } WaitForCompletionOfCommandList(); DWORD current_time = timeGetTime(); @@ -1018,5 +1095,8 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine SwapD3D12Buffers(); } } + if (gLogFile) { + fclose(gLogFile); + } return 0; }