Validate surface using shader code and write BMP file for each frame
This commit is contained in:
@@ -177,6 +177,91 @@ void D3D12Manager::WaitForGPU()
|
||||
}
|
||||
}
|
||||
|
||||
void D3D12Manager::ExecuteCommandListAndWait()
|
||||
{
|
||||
// Close command list
|
||||
m_command_list->Close();
|
||||
|
||||
// Execute command list
|
||||
ID3D12CommandList* cmdLists[] = { m_command_list };
|
||||
m_command_queue->ExecuteCommandLists(1, cmdLists);
|
||||
|
||||
// Wait for GPU to finish
|
||||
WaitForGPU();
|
||||
|
||||
// Reset command list for next use
|
||||
m_command_allocator->Reset();
|
||||
m_command_list->Reset(m_command_allocator, nullptr);
|
||||
}
|
||||
|
||||
bool D3D12Manager::SaveTextureToBMP(ID3D12Resource* texture, uint32_t width, uint32_t height, const char* filename)
|
||||
{
|
||||
if (!texture || !filename) {
|
||||
printf("[D3D12Manager] Invalid parameters for SaveTextureToBMP\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Readback texture to CPU
|
||||
uint8_t* rgba_data = ReadbackTexture(texture, width, height);
|
||||
if (!rgba_data) {
|
||||
printf("[D3D12Manager] Failed to readback texture\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// BMP file header (14 bytes)
|
||||
uint32_t file_size = 54 + (width * height * 4);
|
||||
uint8_t bmp_header[54] = {
|
||||
'B', 'M', // Signature
|
||||
(uint8_t)(file_size), (uint8_t)(file_size >> 8), (uint8_t)(file_size >> 16), (uint8_t)(file_size >> 24), // File size
|
||||
0, 0, 0, 0, // Reserved
|
||||
54, 0, 0, 0, // Data offset
|
||||
40, 0, 0, 0, // Info header size
|
||||
(uint8_t)(width), (uint8_t)(width >> 8), (uint8_t)(width >> 16), (uint8_t)(width >> 24), // Width
|
||||
(uint8_t)(height), (uint8_t)(height >> 8), (uint8_t)(height >> 16), (uint8_t)(height >> 24), // Height
|
||||
1, 0, // Planes
|
||||
32, 0, // Bits per pixel (32-bit RGBA)
|
||||
0, 0, 0, 0, // Compression (none)
|
||||
(uint8_t)(width * height * 4), (uint8_t)((width * height * 4) >> 8),
|
||||
(uint8_t)((width * height * 4) >> 16), (uint8_t)((width * height * 4) >> 24), // Image size
|
||||
0, 0, 0, 0, // X pixels per meter
|
||||
0, 0, 0, 0, // Y pixels per meter
|
||||
0, 0, 0, 0, // Colors used
|
||||
0, 0, 0, 0 // Important colors
|
||||
};
|
||||
|
||||
// Open file
|
||||
FILE* file = nullptr;
|
||||
fopen_s(&file, filename, "wb");
|
||||
if (!file) {
|
||||
printf("[D3D12Manager] Failed to open file: %s\n", filename);
|
||||
delete[] rgba_data;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Write BMP header
|
||||
fwrite(bmp_header, 1, 54, file);
|
||||
|
||||
// Convert RGBA to BGRA for BMP and flip vertically
|
||||
for (int y = height - 1; y >= 0; y--) {
|
||||
for (uint32_t x = 0; x < width; x++) {
|
||||
uint32_t src_idx = (y * width + x) * 4;
|
||||
uint8_t bgra[4] = {
|
||||
rgba_data[src_idx + 2], // B
|
||||
rgba_data[src_idx + 1], // G
|
||||
rgba_data[src_idx + 0], // R
|
||||
rgba_data[src_idx + 3] // A
|
||||
};
|
||||
fwrite(bgra, 1, 4, file);
|
||||
}
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
delete[] rgba_data;
|
||||
|
||||
printf("[D3D12Manager] Saved texture to: %s\n", filename);
|
||||
return true;
|
||||
}
|
||||
|
||||
ID3D12Resource* D3D12Manager::CreateNV12Texture(uint32_t width, uint32_t height)
|
||||
{
|
||||
D3D12_RESOURCE_DESC desc = {};
|
||||
@@ -252,13 +337,13 @@ uint8_t* D3D12Manager::ReadbackTexture(ID3D12Resource* texture, uint32_t width,
|
||||
// Get texture description
|
||||
D3D12_RESOURCE_DESC desc = texture->GetDesc();
|
||||
|
||||
// Calculate layout for both Y and UV planes
|
||||
D3D12_PLACED_SUBRESOURCE_FOOTPRINT layouts[2];
|
||||
UINT num_rows[2] = { 0 };
|
||||
UINT64 row_sizes[2] = { 0 };
|
||||
// RGBA format has only 1 subresource
|
||||
D3D12_PLACED_SUBRESOURCE_FOOTPRINT layout;
|
||||
UINT num_rows = 0;
|
||||
UINT64 row_size = 0;
|
||||
UINT64 total_bytes = 0;
|
||||
|
||||
m_device->GetCopyableFootprints(&desc, 0, 2, 0, layouts, num_rows, row_sizes, &total_bytes);
|
||||
m_device->GetCopyableFootprints(&desc, 0, 1, 0, &layout, &num_rows, &row_size, &total_bytes);
|
||||
|
||||
// Create readback buffer
|
||||
D3D12_HEAP_PROPERTIES readback_heap_props = {};
|
||||
@@ -301,31 +386,18 @@ uint8_t* D3D12Manager::ReadbackTexture(ID3D12Resource* texture, uint32_t width,
|
||||
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
|
||||
m_command_list->ResourceBarrier(1, &barrier);
|
||||
|
||||
// Copy Y plane (subresource 0)
|
||||
D3D12_TEXTURE_COPY_LOCATION src_y = {};
|
||||
src_y.pResource = texture;
|
||||
src_y.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
|
||||
src_y.SubresourceIndex = 0;
|
||||
// Copy RGBA texture (single subresource)
|
||||
D3D12_TEXTURE_COPY_LOCATION src = {};
|
||||
src.pResource = texture;
|
||||
src.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
|
||||
src.SubresourceIndex = 0;
|
||||
|
||||
D3D12_TEXTURE_COPY_LOCATION dst_y = {};
|
||||
dst_y.pResource = readback_buffer;
|
||||
dst_y.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
|
||||
dst_y.PlacedFootprint = layouts[0];
|
||||
D3D12_TEXTURE_COPY_LOCATION dst = {};
|
||||
dst.pResource = readback_buffer;
|
||||
dst.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
|
||||
dst.PlacedFootprint = layout;
|
||||
|
||||
m_command_list->CopyTextureRegion(&dst_y, 0, 0, 0, &src_y, nullptr);
|
||||
|
||||
// Copy UV plane (subresource 1)
|
||||
D3D12_TEXTURE_COPY_LOCATION src_uv = {};
|
||||
src_uv.pResource = texture;
|
||||
src_uv.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
|
||||
src_uv.SubresourceIndex = 1;
|
||||
|
||||
D3D12_TEXTURE_COPY_LOCATION dst_uv = {};
|
||||
dst_uv.pResource = readback_buffer;
|
||||
dst_uv.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;
|
||||
dst_uv.PlacedFootprint = layouts[1];
|
||||
|
||||
m_command_list->CopyTextureRegion(&dst_uv, 0, 0, 0, &src_uv, nullptr);
|
||||
m_command_list->CopyTextureRegion(&dst, 0, 0, 0, &src, nullptr);
|
||||
|
||||
// Transition texture back to COMMON
|
||||
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_SOURCE;
|
||||
@@ -350,28 +422,20 @@ uint8_t* D3D12Manager::ReadbackTexture(ID3D12Resource* texture, uint32_t width,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Allocate CPU buffer (NV12 format: Y plane + UV plane)
|
||||
uint32_t y_size = width * height;
|
||||
uint32_t uv_size = width * (height / 2);
|
||||
uint8_t* cpu_buffer = new uint8_t[y_size + uv_size];
|
||||
// Allocate CPU buffer for RGBA data
|
||||
uint8_t* rgba_data = new uint8_t[width * height * 4];
|
||||
|
||||
// Copy Y plane
|
||||
uint8_t* src_y_data = static_cast<uint8_t*>(mapped_data) + layouts[0].Offset;
|
||||
uint8_t* dst_y_data = cpu_buffer;
|
||||
for (UINT row = 0; row < height; ++row) {
|
||||
memcpy(dst_y_data + row * width, src_y_data + row * layouts[0].Footprint.RowPitch, width);
|
||||
}
|
||||
|
||||
// Copy UV plane
|
||||
uint8_t* src_uv_data = static_cast<uint8_t*>(mapped_data) + layouts[1].Offset;
|
||||
uint8_t* dst_uv_data = cpu_buffer + y_size;
|
||||
for (UINT row = 0; row < height / 2; ++row) {
|
||||
memcpy(dst_uv_data + row * width, src_uv_data + row * layouts[1].Footprint.RowPitch, width);
|
||||
// Copy RGBA data (considering row pitch alignment)
|
||||
uint8_t* src_ptr = static_cast<uint8_t*>(mapped_data);
|
||||
for (uint32_t y = 0; y < height; y++) {
|
||||
memcpy(rgba_data + y * width * 4,
|
||||
src_ptr + y * layout.Footprint.RowPitch,
|
||||
width * 4);
|
||||
}
|
||||
|
||||
// Unmap and release readback buffer
|
||||
readback_buffer->Unmap(0, nullptr);
|
||||
readback_buffer->Release();
|
||||
|
||||
return cpu_buffer;
|
||||
return rgba_data;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user