2016-03-14 16 views
15

Ho lavorato con Vulkan per le ultime due settimane e ho incontrato un problema che si è verificato solo sulle schede AMD. In particolare l'AMD 7970M. Ho eseguito il mio progetto sulle schede GTX 700 e 900 senza alcun problema. Ho persino eseguito Windows e Linux (Steam OS) con schede Nvidia senza intoppi. Il problema si presenta solo sulle schede AMD e solo con il mio progetto; tutti i campioni e i progetti da Sascha Willems non eseguono alcun problema.Vulkan non riesce a cancellare la profondità

In questo momento sto disegnando un modello di Raptor con texture e girandolo sul posto. Lo renderò a una texture e quindi applicherei quella texture a un triangolo a schermo intero; rendering offscreen di base. Tuttavia, la profondità non sembra essere corretta correttamente sul mio 7970M. Invece ho questa artifacting strano come la profondità non viene cancellata correttamente:

Bad Raptor

Naturalmente ho provato a scavare in questo con RenderDoc e la profondità è totalmente sbagliato. Sia il Raptor e il Triangolo a tutto schermo la sua disegnato su sono solo un pasticcio:

Bad Depth

Bad Tri Depth

ho provato a confronto il mio codice all'esempio Offscreen da Sascha Willems e appaio fatevi fare quasi tutto allo stesso modo. Ho pensato che forse qualcosa sarebbe stato sbagliato nel modo in cui ho creato la mia profondità, ma mi sembra soddisfacente rispetto a tutti gli esempi che ho visto.

Ecco alcuni punti di vista di debug di cui sto creando l'immagine di profondità e la vista:

image info image view info

Ecco l'intero metodo:

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

se qualcuno vuole maggiori informazioni sul codice non esitate a chiedere e lo fornirò. Ci sono molte linee di codice per questo progetto, quindi non voglio che tutti debbano attraversare tutto. Se vuoi che tutto il codice possa essere trovato su http://github.com/thirddegree/HatchitGraphics/tree/dev

Modifica: Dopo un po 'di più, ho scoperto che anche il colore non si cancella bene. RenderDoc mostra che ogni frame esegue solo il ritaglio del raptor e non cancella il resto del frame. È un problema con il guidatore?

Modifica: altre informazioni. Ho scoperto che se disegno NULLA, inizio e termina un passaggio di rendering senza nemmeno disegnare il mio triangolo a schermo intero, lo schermo si cancellerà. Comunque, se disegno solo il triangolo, la profondità è sbagliata (anche se non spacco nulla da fuori schermo o non applico alcun tipo di texture).

Modifica: più specificatamente il colore si cancellerà ma la profondità no. Se non disegno nulla, la profondità rimarrà nera; tutti gli 0 Perché il triangolo a schermo intero causa la strana staticità della profondità non sono sicuro.

risposta

9

Questo è esattamente quello che è successo a me quando ho cominciato ad avere i miei esempi Vulkan lavorano su AMD hardware:

enter image description here

loro GPU si basano molto sulle transizioni di immagine corretti (che sono per lo più ignorati da esempio NVIDIA) e penso che la corruzione che vedi nei tuoi screenshot sia il risultato di una barriera pre-presente mancante.

La barriera pre-presente (vedere here) trasforma il layout dell'immagine dell'allegato colorato in un formato di presentazione per il passaggio presentandolo alla catena di scambio.

Questo deve essere eseguito dopo aver completato il rendering all'allegato colore per assicurarsi che l'allegato sia completato prima di presentarlo.

Potete vedere un esempio di questo nel draw routine dei miei esempi.

Nel rendering del fotogramma successivo è necessario trasformare di nuovo il formato dell'immagine dell'allegato di colore per poter eseguire nuovamente il rendering su di esso.

Per riassumere:

  • Prima di pronunciare per la transizione attaccamento colore l'immagine VK_IMAGE_LAYOUT_PRESENT_SRC_KHR-VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL (alias "presente post")

  • fare la vostra rendendo

  • Transizione l'immagine allegata al colore da VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL a VK_IMAGE_LAYOUT_PRESENT_SRC_KHR e presente alla catena di scambio

+0

Questo dovrebbe essere fatto per gli allegati di profondità e colore? – Honeybunch

+1

L'allegato a colori dovrebbe essere sufficiente. Se vedi ancora la corruzione, anche con le barriere presenti controlla anche se il tuo negozio e le operazioni di carico per gli allegati sono corretti. –

+0

Ci scusiamo per la risposta tardiva su questo. Sono sicuro che le mie operazioni di caricamento e di archiviazione sono corrette. Non sono convinto che le barriere pre e post presenti siano il problema. Li ho implementati nel mio motore in modo molto simile a come li hai impostati nei tuoi esempi e non ha avuto alcun effetto sull'immagine. In effetti penso di aver corretto il problema mentre scrivevo questo e ho dimenticato di inviare un comando di transizione dell'immagine. – Honeybunch

5

Grazie a Sascha e alcuni errori extra che sono comparsi con il nuovo 1.0.0 LunarG SDK sono riuscito a risolvere il problema. Il commit con i cambiamenti di fissaggio (e un paio di altre piccole cose) può essere trovato qui: https://github.com/thirddegree/HatchitGraphics/commit/515d0303f45a8e9c00f67a74c824530ea37b687a

E 'stata una combinazione di un paio di cose:

avevo bisogno di impostare l'immagine della profondità sulla attaccamento framebuffer del swapchain a VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT piuttosto che solo VK_IMAGE_ASPECT_DEPTH_BIT

per praticamente ogni barriera di memoria immagine che ho dimenticato di specifiy la baseArrayLayer del subresourceRange. Questo non ha prodotto un errore fino alla versione 1.0.5.

Un altro errore che non è stato visualizzato fino alla 1.0.5 che potrebbe aiutare a tenere traccia di un errore simile e ha influito sulla generazione della trama è che prima di mappare la memoria del dispositivo per una trama sulla memoria host avevo bisogno di passarla da VK_IMAGE_LAYOUT_UNDEFINED a VK_IMAGE_LAYOUT_GENERAL, inviare tale comando, mappare la memoria e quindi passare da GENERALE a VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL (non dimenticare di inviare anche questo comando). Ancora una volta questo è solo per le trame che vuoi campionare, ma immagino che la morale qui sia "effettivamente invia le transizioni dell'immagine"

Problemi correlati