Ich bin in der Lage, Sachen von R32G32B32A32 Bild für Screenshot zu dumpen. Ich möchte auch ein Pixel aus dem R32G32_SFLOAT-Bild auslesen. Aber das Ergebnis sieht komisch aus.Wie zu lesen R32G32_SFLOAT Bild von GPU in Vulkan
unter Dump-Code meines Arbeitsbild ist (kein Validierungsfehler)
void DumpImageToFile(VkTool::VulkanDevice &device, VkQueue graphics_queue, VkTool::Wrapper::CommandBuffers &command_buffer, VkImage image, uint32_t width, uint32_t height, const char *filename)
{
auto image_create_info = VkTool::Initializer::GenerateImageCreateInfo(VK_IMAGE_TYPE_2D, VK_FORMAT_R8G8B8A8_UNORM, {width, height, 1},
VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, VK_SAMPLE_COUNT_1_BIT);
VkTool::Wrapper::Image staging_image(device, image_create_info, VK_MEMORY_HEAP_DEVICE_LOCAL_BIT);
auto buffer_create_info = VkTool::Initializer::GenerateBufferCreateInfo(width * height * 4, VK_BUFFER_USAGE_TRANSFER_DST_BIT);
VkTool::Wrapper::Buffer staging_buffer(device, buffer_create_info, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
// Copy texture to buffer
command_buffer.Begin();
auto image_memory_barrier = VkTool::Initializer::GenerateImageMemoryBarrier(VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
{ VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }, staging_image.Get());
device.vkCmdPipelineBarrier(command_buffer.Get(), VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0
, 0, nullptr, 0, nullptr, 1, &image_memory_barrier);
image_memory_barrier = VkTool::Initializer::GenerateImageMemoryBarrier(VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
{ VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }, image);
device.vkCmdPipelineBarrier(command_buffer.Get(), VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0
, 0, nullptr, 0, nullptr, 1, &image_memory_barrier);
// Copy!!
VkImageBlit region = {};
region.srcSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
region.srcOffsets[0] = { 0, 0, 0 };
region.srcOffsets[1] = { static_cast<int32_t>(width), static_cast<int32_t>(height), 1};
region.dstSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
region.dstOffsets[0] = { 0, 0, 0 };
region.dstOffsets[1] = { static_cast<int32_t>(width), static_cast<int32_t>(height), 1 };
device.vkCmdBlitImage(command_buffer.Get(), image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, staging_image.Get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion, VK_FILTER_LINEAR);
image_memory_barrier = VkTool::Initializer::GenerateImageMemoryBarrier(VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
{ VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }, image);
device.vkCmdPipelineBarrier(command_buffer.Get(), VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0
, 0, nullptr, 0, nullptr, 1, &image_memory_barrier);
image_memory_barrier = VkTool::Initializer::GenerateImageMemoryBarrier(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
{ VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }, staging_image.Get());
device.vkCmdPipelineBarrier(command_buffer.Get(), VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0
, 0, nullptr, 0, nullptr, 1, &image_memory_barrier);
auto buffer_image_copy = VkTool::Initializer::GenerateBufferImageCopy({ VK_IMAGE_ASPECT_COLOR_BIT , 0, 0, 1 }, { width, height, 1 });
device.vkCmdCopyImageToBuffer(command_buffer.Get(), staging_image.Get(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, staging_buffer.Get(), 1, &buffer_image_copy);
command_buffer.End();
std::vector<VkCommandBuffer> raw_command_buffers = command_buffer.GetAll();
auto submit_info = VkTool::Initializer::GenerateSubmitInfo(raw_command_buffers);
VkTool::Wrapper::Fence fence(device);
device.vkQueueSubmit(graphics_queue, 1, &submit_info, fence.Get());
fence.Wait();
fence.Destroy();
const uint8_t *mapped_address = reinterpret_cast<const uint8_t *>(staging_buffer.MapMemory());
lodepng::encode(filename, mapped_address, width, height);
staging_buffer.UnmapMemory();
staging_image.Destroy();
staging_buffer.Destroy();
}
Sorry für die hässliche selbstgemachte Wrapper, gab es keine offizielle Wrapper. Im Grunde erstellt es ein Zwischenspeicherungsbild und einen Zwischenspeicher. erste Kopie vom Quellbild zum Staging-Image mit vkCmdBlitImage. Verwenden Sie dann vkCmdCopyImageToBuffer und ordnen Sie den Puffer dem Host-Speicher zu. Diese Methode funktioniert auf mehreren GPUs und muss sich nicht um das Padding kümmern. (Ich denke, korrigiere mich, wenn ich falsch liege).
Allerdings habe ich kein Glück, diese Methode zu verwenden, um R32G32_SFLOAT zu lesen. Zuerst dachte ich, es sei wegen der Endiannität, bis ich das ganze Bild ausplatzte.
Das Bild oben ist ich R32G32_SFLOAT zu R8G8B8A8_UNORM direkt konvertieren, ich weiß, es macht keinen Sinn. Aber ohne das Format zu ändern, gibt es immer noch eine Menge "Löcher" im Bild und Werte sind tödlich falsch.
Könnten Sie bitte Ihre letzte Aussage kommentieren? Ich kann nicht sehen, wie ein gut geschriebener und korrekt synchronisierter Code, der auf einigen verfügbaren Funktionen basiert, auf einem GPU-Treiberpaar funktionieren kann, das die Feature-Liste unterstützt und nicht auf einem anderen GPU-Treiberpaar arbeitet, das die gleichen Features unterstützt. –
Es gibt ein Missverständnis. Ich meinte, dass manche GPUs mehr Synchronisation oder einen korrekten Layout-Übergang benötigen als andere Grafikprozessoren. Zum Beispiel müssen Sie bei NVIDIA wahrscheinlich nicht alles perfekt synchronisieren, damit es funktioniert. AMD-Karten erfordern vom Entwickler mehr Aufwand. Allerdings habe ich nicht gesagt, dass der Code korrekt ist. Wie ich gerade gesagt habe, könnte ein falscher Code bei NVIDIA funktionieren, aber nicht bei AMD, und das gilt auch für das OP. Sein Code funktioniert auf einigen GPUs, aber nicht auf jedem;) –
Der Grund, warum ich Staging-Images verwende, ist, dass ich gerne sehen würde, was passieren würde, wenn ich vkCmdBlitImage für ein anderes Format von src und dst image verwende. Yap Es ist Farbbefestigung. "undefined" zu schreiben bedeutet, dass mir das Format und die Synchronisation in diesem Moment egal sind. Und ich wünsche, dass diese Funktion für nicht-Farbe-Attachment-Bild verwendet werden kann. –