2017-09-22 1 views
0

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

enter image description here

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, &region, 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.

enter image description here

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.

Antwort

4

Ich bin nicht wirklich sicher, ob es das Problem ist, aber wenn ich Ihren Code verstehe, möchten Sie image in filename setzen. Sie möchten also von diesem Bild lesen. Sie haben jedoch gesagt, dass das alte Layout für dieses Bild (nicht das Staging) ein UNDEFINED-Layout ist. Die Implementierung kann frei davon ausgehen, dass Sie sich nicht um Daten kümmern, die darin gespeichert sind. Verwenden Sie stattdessen das echte Layout (ich denke, es ist COLOR_ATTACHMENT oder so ähnlich).

Darüber hinaus verwenden Sie ein Staging-Image und einen Staging-Puffer. Ich verstehe nicht wirklich, warum machst du so etwas? Warum nicht einfach vkCmdCopyImageToBuffer Funktion mit image bis staging_buffer verwenden?

BTW, mit Vulkan ist es nicht, weil ein Code auf einigen GPUs funktioniert, dass dieser Code korrekt ist.

Auch ich denke, Sie müssen eine Speicherbarriere nach Ihrer Übertragung in den Puffer verwenden, die HOST_STAGE und HOST_READ impliziert. In der Beschreibung ist es schreiben:

einen Zaun Melde- und wartet auf dem Host garantiert nicht, dass die Ergebnisse der Speicherzugriffe auf den Host, als Zugriffsbereich einer Speicher Abhängigkeit von einem Zaun definiert sichtbar ist beinhaltet nur den Gerätezugriff. Um dies zu gewährleisten, muss eine Speicherbarriere oder eine andere Speicherabhängigkeit verwendet werden. Weitere Informationen finden Sie in der Beschreibung der Hostzugriffstypen.

+0

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. –

+1

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;) –

+0

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. –

0

Dieser Teil des Codes scheint seltsam:

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); 

Das bedeutet im Wesentlichen, dass Ihr Quellbild nach der Sperre keine Daten hat. UNDEFINED-Wert, der als Quelllayout verwendet wird, garantiert nicht, dass der Inhalt eines Bildes erhalten bleibt.

+1

["Sie" gegen "Sie" als höfliche Form des Schreibens] (https://english.stackexchange.com/q/30185/25305) –

+0

@ NicolBolas Was ist los mit "Sie" als höfliche Form des Schreibens? ;-) – Ekzuzy

+2

Weil, wie der Link zeigt, den ich dir gezeigt habe, Englisch nicht so funktioniert. –