fix: 修复截图保存功能和CreateCommittedResource参数问题
- 修复SaveScreenshot函数中D3D12_RESOURCE_DESC的初始化 - 添加完整的SampleDesc和Layout字段 - 修复从PRESENT状态正确转换到COPY_SOURCE进行读取 - 启用D3D12 Debug Layer以获取更好的调试信息 - 添加日志输出到文件以便捕获调试信息
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
#include "XCEngine/RHI/D3D12/D3D12Device.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef _DEBUG
|
||||
#include <dxgidebug.h>
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <stdarg.h>
|
||||
#include <algorithm>
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
@@ -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];
|
||||
Log("[DEBUG] SaveScreenshot: renderTarget = %p\n", renderTarget);
|
||||
|
||||
D3D12_RESOURCE_DESC desc = renderTarget->GetDesc();
|
||||
// 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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user