Estou desenvolvendo um aplicativo Vulkan em um laptop com gráficos integrados (apenas um VkQueue) e na inicialização preciso executar um shader de fragmento muito caro, cuja saída é lida mais tarde como uma textura. O problema é que o SO (acredito eu) às vezes o mata se demorar muito, causando VK_ERROR_DEVICE_LOST.
Para contornar isso, eu dividi o trabalho de renderização subdividindo as chamadas de desenho com diferentes tesouras/áreas de renderização, cada uma com seu próprio buffer de comando e VkSubmitInfo, framebuffer compartilhado. Isso corrigiu os erros de perda do dispositivo, no entanto, há ruído/lixo em todas as tesouras, exceto na última. Não é completamente aleatório: pode-se ver que os desenhos foram feitos, mas parece que o driver acredita que a memória está disponível para uso após a renderização de uma tesoura ser feita.
Preciso dizer ao driver "não toque neste pedaço de memória", e presumi que esse era o objetivo da área de renderização do framebuffer.
Se eu definir o initialLayout do anexo como READ_ONLY_OPTIMAL (o mesmo que finalLayout) em vez de UNDEFINED, tudo funciona corretamente, mas é claro que recebo o erro de validação de que a imagem foi encontrada com o layout errado. Tentar fazer a transição da imagem para o layout correto quebra a renderização novamente.
Portanto, presumo que estou configurando a barreira do pipeline incorretamente:
VkImageMemoryBarrier barrier = {
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.image = image,
.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
.newLayout = VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.subresourceRange.levelCount = 1,
.subresourceRange.layerCount = 1,
};
}
vkCmdPipelineBarrier(cmd[i],
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
0, // dependencyFlags
0, NULL, 0, NULL, 1, &barrier);
O que estou fazendo errado?
SOLUÇÃO:
renderpass = {.initialLayout=COLOR_ATTACHMENT, .finalLayout=.initialLayout}
if batch == 0
vkCmdPipelineBarrier(TOP_OF_PIPE, COLOR_ATTACHMENT_OUTPUT,
barrier={.oldLayout=UNDEFINED, .newLayout=COLOR_ATTACHMENT})
renderpass begin, ..., renderpass end
if batch == last
vkCmdPipelineBarrier(COLOR_ATTACHMENT_OUTPUT, COLOR_ATTACHMENT_OUTPUT,
barrier={.oldLayout=COLOR_ATTACHMENT, .newLayout=READ_ONLY})
Layout undefined é .. undefined .. ele diz à implementação que os dados em
image
podem ser descartados porque não há como interpretar o conteúdo. Você só pode usar isso quando for sobrescrever todos os dados emimage
, e no seu caso isso só é verdade para a primeira passagem de renderização. Para as últimas, você precisa preservar os dados e eu os manteria emCOLOR_ATTACHMENT_OPTIMAL
Parece a escolha errada para um anexo de passagem de renderização, dado que você está escrevendo para ele. Esperaria usar
COLOR_ATTACHMENT_OPTIMAL
para anexos.