2016-03-14 9 views
15

Ich habe in den letzten paar Wochen mit Vulkan gearbeitet und bin auf ein Problem gestoßen, das nur auf AMD-Karten passiert ist. Speziell die AMD 7970M. Ich habe mein Projekt auf GTX 700 und 900 Serie Karten ohne Problem ausgeführt. Ich habe sogar unter Windows ein Linux (Steam OS) mit Nvidia-Karten ohne Probleme laufen lassen. Das Problem tritt nur auf AMD-Karten und nur bei meinem Projekt auf; Alle Proben und Projekte von Sascha Willems laufen kein Problem.Vulkan versäumt, Tiefe zu löschen

Im Moment zeichne ich ein texturiertes Raptor Modell und spinne es an Ort und Stelle. Ich rendere das auf eine Textur und wende diese Textur dann auf ein Fullscreen-Dreieck an; grundlegendes Offscreen-Rendering. Die Tiefe scheint auf meiner 7970M jedoch nicht korrekt zu sein. Stattdessen bekomme ich diese seltsame Artefakte wie die Tiefe ist nicht richtig gelöscht wird:

Bad Raptor

Natürlich habe ich versucht, mit RenderDoc in diesem Graben und die Tiefe ist völlig falsch. Sowohl der Raptor und der das Vollbild Dreieck gezeichnet auf nur ein einziges Durcheinander:

Bad Depth

Bad Tri Depth

Ich habe versucht, meinen Code zu dem Offscreen Beispiel von Sascha Willems zu vergleichen und erscheinen mich fast do tun alles gleich. Ich dachte, dass mit der Art und Weise, wie ich meine Tiefe erstellt habe, vielleicht etwas nicht stimmen würde, aber im Vergleich zu all den Beispielen, die ich gesehen habe, scheint es in Ordnung zu sein.

Hier sind einige Debug-Ansichten von wo ich die Tiefe Bild erschaffe und Aussicht:

image info image view info

Hier ist die ganze Methode:

 bool VKRenderTarget::setupFramebuffer(VKRenderer* renderer) 
      { 
       VkDevice device = renderer->GetVKDevice(); 
       VkCommandBuffer setupCommand; 

       m_colorFormat = renderer->GetPreferredImageFormat(); 
       m_depthFormat = renderer->GetPreferredDepthFormat(); 

       renderer->CreateSetupCommandBuffer(); 

       setupCommand = renderer->GetSetupCommandBuffer(); 

       VkResult err; 

       //Color attachment 
       VkImageCreateInfo imageInfo = {}; 
       imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; 
       imageInfo.pNext = nullptr; 
       imageInfo.format = m_colorFormat; 
       imageInfo.imageType = VK_IMAGE_TYPE_2D; 
       imageInfo.extent.width = m_width; 
       imageInfo.extent.height = m_height; 
       imageInfo.mipLevels = 1; 
       imageInfo.arrayLayers = 1; 
       imageInfo.samples = VK_SAMPLE_COUNT_1_BIT; 
       imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL; 
       imageInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; 
       imageInfo.flags = 0; 

       VkMemoryAllocateInfo memAllocInfo = {}; 
       memAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; 

       VkMemoryRequirements memReqs; 

       err = vkCreateImage(device, &imageInfo, nullptr, &m_color.image); 
       assert(!err); 
       if (err != VK_SUCCESS) 
       { 
#ifdef _DEBUG 
        Core::DebugPrintF("VKRenderTarget::VPrepare(): Error creating color image!\n"); 
#endif 
        return false; 
       } 

       vkGetImageMemoryRequirements(device, m_color.image, &memReqs); 
       memAllocInfo.allocationSize = memReqs.size; 
       renderer->MemoryTypeFromProperties(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &memAllocInfo.memoryTypeIndex); 

       err = vkAllocateMemory(device, &memAllocInfo, nullptr, &m_color.memory); 
       assert(!err); 
       if (err != VK_SUCCESS) 
       { 
#ifdef _DEBUG 
        Core::DebugPrintF("VKRenderTarget::VPrepare(): Error allocating color image memory!\n"); 
#endif 
        return false; 
       } 

       err = vkBindImageMemory(device, m_color.image, m_color.memory, 0); 
       if (err != VK_SUCCESS) 
       { 
#ifdef _DEBUG 
        Core::DebugPrintF("VKRenderTarget::VPrepare(): Error binding color image memory!\n"); 
#endif 
        return false; 
       } 

       renderer->SetImageLayout(setupCommand, m_color.image, VK_IMAGE_ASPECT_COLOR_BIT, 
        VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); 

       VkImageViewCreateInfo viewInfo = {}; 
       viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; 
       viewInfo.pNext = nullptr; 
       viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; 
       viewInfo.format = m_colorFormat; 
       viewInfo.flags = 0; 
       viewInfo.subresourceRange = {}; 
       viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; 
       viewInfo.subresourceRange.baseMipLevel = 0; 
       viewInfo.subresourceRange.levelCount = 1; 
       viewInfo.subresourceRange.baseArrayLayer = 0; 
       viewInfo.subresourceRange.layerCount = 1; 
       viewInfo.image = m_color.image; 

       err = vkCreateImageView(device, &viewInfo, nullptr, &m_color.view); 
       if (err != VK_SUCCESS) 
       { 
#ifdef _DEBUG 
        Core::DebugPrintF("VKRenderTarget::VPrepare(): Error creating color image view!\n"); 
#endif 
        return false; 
       } 

       //We can reuse the same info structs to build the depth image 
       imageInfo.format = m_depthFormat; 
       imageInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; 

       err = vkCreateImage(device, &imageInfo, nullptr, &(m_depth.image)); 

       assert(!err); 
       if (err != VK_SUCCESS) 
       { 
#ifdef _DEBUG 
        Core::DebugPrintF("VKRenderTarget::VPrepare(): Error creating depth image!\n"); 
#endif 
        return false; 
       } 

       viewInfo.format = m_depthFormat; 
       viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; 

       vkGetImageMemoryRequirements(device, m_depth.image, &memReqs); 
       memAllocInfo.allocationSize = memReqs.size; 
       renderer->MemoryTypeFromProperties(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &memAllocInfo.memoryTypeIndex); 

       err = vkAllocateMemory(device, &memAllocInfo, nullptr, &m_depth.memory); 
       assert(!err); 
       if (err != VK_SUCCESS) 
       { 
#ifdef _DEBUG 
        Core::DebugPrintF("VKRenderTarget::VPrepare(): Error allocating depth image memory!\n"); 
#endif 
        return false; 
       } 

       err = vkBindImageMemory(device, m_depth.image, m_depth.memory, 0); 
       if (err != VK_SUCCESS) 
       { 
#ifdef _DEBUG 
        Core::DebugPrintF("VKRenderTarget::VPrepare(): Error binding depth image memory!\n"); 
#endif 
        return false; 
       } 

       renderer->SetImageLayout(setupCommand, m_depth.image, 
        VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT, 
        VK_IMAGE_LAYOUT_UNDEFINED, 
        VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); 

       viewInfo.image = m_depth.image; 

       err = vkCreateImageView(device, &viewInfo, nullptr, &m_depth.view); 
       if (err != VK_SUCCESS) 
       { 
#ifdef _DEBUG 
        Core::DebugPrintF("VKRenderTarget::VPrepare(): Error creating depth image view!\n"); 
#endif 
        return false; 
       } 

       renderer->FlushSetupCommandBuffer(); 

       //Finally create internal framebuffer 
       VkImageView attachments[2]; 
       attachments[0] = m_color.view; 
       attachments[1] = m_depth.view; 

       VkFramebufferCreateInfo framebufferInfo = {}; 
       framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; 
       framebufferInfo.pNext = nullptr; 
       framebufferInfo.flags = 0; 
       framebufferInfo.renderPass = *((VKRenderPass*)m_renderPass)->GetVkRenderPass(); 
       framebufferInfo.attachmentCount = 2; 
       framebufferInfo.pAttachments = attachments; 
       framebufferInfo.width = m_width; 
       framebufferInfo.height = m_height; 
       framebufferInfo.layers = 1; 

       err = vkCreateFramebuffer(device, &framebufferInfo, nullptr, &m_framebuffer); 
       if (err != VK_SUCCESS) 
       { 
#ifdef _DEBUG 
        Core::DebugPrintF("VKRenderTarget::VPrepare(): Error creating framebuffer!\n"); 
#endif 
        return false; 
       } 

       return true; 
      } 

Wenn jemand mehr Informationen über das will Code fühlen sich frei zu fragen, und ich werde es zur Verfügung stellen. Es gibt eine Menge Codezeilen für dieses Projekt, also möchte ich nicht, dass alle sich das alles ansehen müssen. Wenn Sie möchten, obwohl alle den Code finden Sie unter http://github.com/thirddegree/HatchitGraphics/tree/dev

Edit: Nach ein bisschen mehr herum stochern habe ich festgestellt, dass selbst die Farbe nicht wirklich klar ist. RenderDoc zeigt, dass jeder Frame nur den Ausschnitt des Raptors rendert und den Rest des Frames nicht löscht. Ist das ein Treiberproblem?

Bearbeiten: Einige weitere Informationen. Ich habe festgestellt, dass, wenn ich NOTHING zeichne, nur einen Render-Pass beginne und beende, ohne mein Vollbild-Dreieck zu zeichnen, der Bildschirm wird gelöscht. Wenn ich jedoch nur das Dreieck zeichne, ist die Tiefe falsch (auch wenn ich nichts vom Bildschirm blitze oder irgendeine Art von Textur anlege).

Edit: Genauer gesagt wird die Farbe löschen, aber die Tiefe nicht. Wenn ich nichts zeichne, bleibt die Tiefe schwarz; alle 0s. Warum das Fullscreen-Dreieck die seltsame Statik der Tiefe verursacht, bin ich nicht sicher.

Antwort

9

Das ist genau das, was mir passiert ist, als ich begann meine Vulkan Beispiele auf AMD-Hardware arbeiten zu erhalten:

enter image description here

Ihre GPUs verlassen sich stark auf korrekte Bildübergänge (die von zB NVIDIA ignoriert werden meistens) und ich denke, die Korruption, die Sie in Ihren Screenshots sehen, ist das Ergebnis einer fehlenden Prä-Präsens-Barriere.

Die Prä-Present-Barriere (siehe here) wandelt das Bildlayout Ihres Farbanhangs in ein Präsentationsformat um und übergibt es der Tauschkette.

Dies muss nach dem Rendern des Farbanhangs vorgenommen werden, um sicherzustellen, dass der Anhang abgeschlossen ist, bevor Sie ihn präsentieren.

Sie können ein Beispiel dafür in den draw routine meiner Beispiele sehen.

Beim Rendern des nächsten Frames müssen Sie das Bildformat des Farbanhangs umwandeln, damit Sie es erneut rendern können.

Um es zusammenzufassen:

  • Bevor VK_IMAGE_LAYOUT_PRESENT_SRC_KHR-VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL zu Ihrer Farbe Befestigung Übergang Ihr Bild zu machen (auch bekannt als "post present")

  • Sie Ihre

  • Transition-Rendering Ihr Farbanhangsbild von VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL zu VK_IMAGE_LAYOUT_PRESENT_SRC_KHR und präsentieren Sie das zur Umtauschkette

+0

Sollte dies sowohl für die Tiefe und Farbe Anhänge getan werden? – Honeybunch

+1

Die Farbbefestigung sollte ausreichend sein. Wenn Sie immer noch Korruption sehen, prüfen Sie auch bei den aktuellen Barrieren, ob Ihre Store- und Load-Ops für die Anhänge korrekt sind. –

+0

Entschuldigung für die späte Antwort zu diesem Thema. Ich bin mir sehr sicher, dass meine Lade- und Speicheroperationen korrekt sind. Ich bin nicht davon überzeugt, dass die Prä- und Post-Barrieren das Problem sind. Ich habe sie in meiner Engine sehr ähnlich implementiert, wie Sie sie in Ihren Beispielen eingerichtet haben. Es hatte keinerlei Auswirkungen auf das Bild. In der Tat, ich denke, ich habe gerade das Problem behoben, während ich dies geschrieben habe und ich habe vergessen, einen Bildübergangsbefehl einzureichen. – Honeybunch

5

Dank Sascha und einigen zusätzlichen Fehlern, die mit dem neuen 1.0.5 LunarG SDK auftauchten, ist es mir gelungen, das Problem zu beheben. https://github.com/thirddegree/HatchitGraphics/commit/515d0303f45a8e9c00f67a74c824530ea37b687a

Es war eine Kombination von ein paar Dinge: Die begehen mit den Befestigungs Änderungen (und ein paar andere Kleinigkeiten) sind hier zu finden

ich auf dem Framebuffer Befestigung der das Tiefenbild setzen benötigt swapchain zu VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT anstatt nur VK_IMAGE_ASPECT_DEPTH_BIT

Für so ziemlich Barriere jeden Bildspeichers ich die baseArrayLayer der subresourceRange specifiy vergessen zu. Dies verursachte bis Version 1.0.5 keinen Fehler.

Ein weiterer Fehler, der bis 1.0.5 nicht auftauchte, der Ihnen helfen könnte, einen ähnlichen Fehler zu verfolgen und meine Texturgenerierung zu beeinflussen, war, dass ich den Gerätespeicher für eine Textur zum Hostspeicher mappte, die ich von VK_IMAGE_LAYOUT_UNDEFINED überführen musste Senden Sie diesen Befehl an VK_IMAGE_LAYOUT_GENERAL, ordnen Sie den Speicher zu und übertragen Sie ihn dann von GENERAL auf VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL (vergessen Sie nicht, diesen Befehl ebenfalls zu senden). Auch dies ist nur für Texturen, die Sie probieren möchten, aber ich denke, die Moral hier ist "tatsächlich Ihre Bildübergänge übermitteln"