From 549178de352324a3c79d5577bd10543060477819 Mon Sep 17 00:00:00 2001 From: ssdfasd <2156608475@qq.com> Date: Sun, 15 Mar 2026 13:54:58 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8DD3D12=E6=88=AA?= =?UTF-8?q?=E5=9B=BE=E5=8A=9F=E8=83=BD=20-=20=E4=BD=BF=E7=94=A8=E6=AD=A3?= =?UTF-8?q?=E7=A1=AE=E7=9A=84buffer=E5=B0=BA=E5=AF=B8=E5=92=8Crow=20pitch?= =?UTF-8?q?=E8=8E=B7=E5=8F=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/D3D12/main.cpp | 115 ++++++++++++++++++++++++++++++------------- 1 file changed, 81 insertions(+), 34 deletions(-) diff --git a/tests/D3D12/main.cpp b/tests/D3D12/main.cpp index ed8dc227..be44acc8 100644 --- a/tests/D3D12/main.cpp +++ b/tests/D3D12/main.cpp @@ -680,8 +680,13 @@ ID3D12GraphicsCommandList* GetCommandList() { } void WaitForCompletionOfCommandList() { - if (gFence.GetCompletedValue() < gFenceValue) { - gFence.Wait(gFenceValue); + UINT64 completed = gFence.GetCompletedValue(); + UINT64 current = gFenceValue; + Log("[DEBUG] WaitForCompletion: completed=%llu, waiting for=%llu\n", completed, current); + if (completed < current) { + Log("[DEBUG] WaitForCompletion: waiting...\n"); + gFence.Wait(current); + Log("[DEBUG] WaitForCompletion: done\n"); } } @@ -755,25 +760,39 @@ bool SaveScreenshot(const char* filename, int width, int height) { Log("[DEBUG] SaveScreenshot: waiting for GPU\n"); WaitForCompletionOfCommandList(); - // Get current back buffer index - int currentRTIndex = swapChain->GetCurrentBackBufferIndex(); - Log("[DEBUG] SaveScreenshot: currentRTIndex = %d\n", currentRTIndex); + // Don't call Present() - capture directly from RENDER_TARGET state + int captureRTIndex = gCurrentRTIndex; + Log("[DEBUG] SaveScreenshot: gCurrentRTIndex = %d\n", gCurrentRTIndex); // Use existing render target - ID3D12Resource* renderTarget = gColorRTs[currentRTIndex]; + ID3D12Resource* renderTarget = gColorRTs[captureRTIndex]; Log("[DEBUG] SaveScreenshot: renderTarget = %p\n", renderTarget); - - // Need to transition from PRESENT to COPY_SOURCE for reading + + D3D12_RESOURCE_DESC rtDesc = renderTarget->GetDesc(); + Log("[DEBUG] SaveScreenshot: rtDesc.Width=%llu, Height=%u, Format=%d\n", rtDesc.Width, rtDesc.Height, rtDesc.Format); + + // Create readback buffer - size must include row pitch padding + D3D12_PLACED_SUBRESOURCE_FOOTPRINT layout = {}; + UINT64 totalSize = 0; + device->GetCopyableFootprints(&rtDesc, 0, 1, 0, &layout, nullptr, nullptr, &totalSize); + UINT rowPitch = layout.Footprint.RowPitch; + Log("[DEBUG] SaveScreenshot: GPU rowPitch = %u, totalSize = %llu\n", rowPitch, totalSize); + + // Create buffer with proper size HRESULT hr = S_OK; ID3D12CommandAllocator* cmdAlloc = nullptr; hr = device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&cmdAlloc)); + if (FAILED(hr)) { + Log("[DEBUG] SaveScreenshot: CreateCommandAllocator failed! hr=%08X\n", hr); + return false; + } D3D12_HEAP_PROPERTIES heapProps = {}; heapProps.Type = D3D12_HEAP_TYPE_READBACK; D3D12_RESOURCE_DESC readbackDesc = {}; readbackDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; readbackDesc.Alignment = 0; - readbackDesc.Width = (UINT64)width * height * 4; + readbackDesc.Width = totalSize; readbackDesc.Height = 1; readbackDesc.DepthOrArraySize = 1; readbackDesc.MipLevels = 1; @@ -794,17 +813,11 @@ bool SaveScreenshot(const char* filename, int width, int height) { if (FAILED(hr)) { Log("[DEBUG] SaveScreenshot: CreateCommittedResource failed! hr=%08X\n", hr); + cmdAlloc->Release(); 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; - } - ID3D12GraphicsCommandList* cmdList = nullptr; hr = device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, cmdAlloc, nullptr, IID_PPV_ARGS(&cmdList)); if (FAILED(hr)) { @@ -819,15 +832,33 @@ bool SaveScreenshot(const char* filename, int width, int height) { 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.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET; barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_SOURCE; barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; cmdList->ResourceBarrier(1, &barrier); - cmdList->CopyResource(readbackBuffer, renderTarget); + // Use CopyTextureRegion to copy from texture to buffer + D3D12_TEXTURE_COPY_LOCATION srcLoc = {}; + srcLoc.pResource = renderTarget; + srcLoc.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; + srcLoc.SubresourceIndex = 0; + + D3D12_TEXTURE_COPY_LOCATION dstLoc = {}; + dstLoc.pResource = readbackBuffer; + dstLoc.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; + dstLoc.PlacedFootprint = layout; + + D3D12_BOX srcBox = {}; + srcBox.left = 0; + srcBox.top = 0; + srcBox.front = 0; + srcBox.right = (UINT)rtDesc.Width; + srcBox.bottom = rtDesc.Height; + srcBox.back = 1; + cmdList->CopyTextureRegion(&dstLoc, 0, 0, 0, &srcLoc, &srcBox); barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_SOURCE; - barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT; + barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET; cmdList->ResourceBarrier(1, &barrier); cmdList->Close(); @@ -852,10 +883,15 @@ bool SaveScreenshot(const char* filename, int width, int height) { return false; } - D3D12_RESOURCE_DESC desc = readbackBuffer->GetDesc(); - UINT rowPitch = width * 4; Log("[DEBUG] SaveScreenshot: rowPitch = %u\n", rowPitch); + // Debug: check some pixel values + int centerIdx = (height / 2) * rowPitch + (width / 2) * 4; + Log("[DEBUG] SaveScreenshot: center pixel RGBA = %02X %02X %02X %02X\n", + mappedData[centerIdx], mappedData[centerIdx+1], mappedData[centerIdx+2], mappedData[centerIdx+3]); + Log("[DEBUG] SaveScreenshot: first pixel RGBA = %02X %02X %02X %02X\n", + mappedData[0], mappedData[1], mappedData[2], mappedData[3]); + Log("[DEBUG] SaveScreenshot: writing file\n"); FILE* fp = fopen(filename, "wb"); if (!fp) { @@ -871,9 +907,9 @@ bool SaveScreenshot(const char* filename, int width, int height) { for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { int idx = y * rowPitch + x * 4; - unsigned char r = mappedData[idx + 2]; - unsigned char g = mappedData[idx + 1]; - unsigned char b = mappedData[idx + 0]; + unsigned char r = mappedData[idx + 0]; // R8G8B8A8: R is at offset 0 + unsigned char g = mappedData[idx + 1]; // G is at offset 1 + unsigned char b = mappedData[idx + 2]; // B is at offset 2 fwrite(&r, 1, 1, fp); fwrite(&g, 1, 1, fp); fwrite(&b, 1, 1, fp); @@ -1018,6 +1054,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine int imageWidth, imageHeight, imageChannel; stbi_uc* pixels = stbi_load("Res/Image/earth_d.jpg", &imageWidth, &imageHeight, &imageChannel, 4); + Log("[DEBUG] Texture loaded: width=%d, height=%d, channels=%d, pixels=%p\n", imageWidth, imageHeight, imageChannel, pixels); ID3D12Resource* texture = CreateTexture2D(commandList, pixels, imageWidth * imageHeight * imageChannel, imageWidth, imageHeight, DXGI_FORMAT_R8G8B8A8_UNORM); delete[] pixels; @@ -1062,14 +1099,6 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine DispatchMessage(&msg); } else { frameCount++; - if (frameCount == 2) { - 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(); DWORD frameTime = current_time - last_time; @@ -1090,9 +1119,27 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine commandList->SetGraphicsRootShaderResourceView(3, sb->GetGPUVirtualAddress()); commandList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); staticMeshComponent.Render(commandList); - EndRenderToSwapChain(commandList); + + // On screenshot frame, don't transition to PRESENT - keep RENDER_TARGET for screenshot + if (frameCount != 120) { + EndRenderToSwapChain(commandList); + } EndCommandList(); - SwapD3D12Buffers(); + + // On screenshot frame, don't Present - we'll screenshot before next frame + if (frameCount != 120) { + SwapD3D12Buffers(); + } + + // Screenshot after rendering is done + if (frameCount == 120) { + 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"); + } + } } } if (gLogFile) {