Синхронизация между вызовами в Вулкане - PullRequest
1 голос
/ 02 июля 2019

Насколько я понимаю, если у меня есть drawcall, который каким-то образом использует результаты любого предыдущего drawcall или пишет в ту же цель рендеринга (framebuffer), то мне нужно убедиться, что более поздний drawcall видит эффекты памяти всех предыдущих розыгрышей.

Но как насчет того, что когда я рендерил сцену с кучей объектов, каждый такой объект представляет собой один вызов вызова, и все эти вызовы записи записываются в один и тот же кадровый буфер.

Нужно ли выдавать барьер памяти после каждого вызова?

Например, в примере pbrbasic Саша Виллема есть этот код (немного упрощенный), и я не вижу там никаких конвейерных барьеров:

            VK_CHECK_RESULT(vkBeginCommandBuffer(drawCmdBuffers[i], &cmdBufInfo));

            vkCmdBeginRenderPass(drawCmdBuffers[i], &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE);

            VkViewport viewport = vks::initializers::viewport((float)width, (float)height, 0.0f, 1.0f);
            vkCmdSetViewport(drawCmdBuffers[i], 0, 1, &viewport);

            VkRect2D scissor = vks::initializers::rect2D(width, height, 0, 0);
            vkCmdSetScissor(drawCmdBuffers[i], 0, 1, &scissor);

            VkDeviceSize offsets[1] = { 0 };

            vkCmdBindPipeline(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
            vkCmdBindDescriptorSets(drawCmdBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet, 0, NULL);
            vkCmdBindVertexBuffers(drawCmdBuffers[i], VERTEX_BUFFER_BIND_ID, 1, &models.objects[models.objectIndex].vertices.buffer, offsets);
            vkCmdBindIndexBuffer(drawCmdBuffers[i], models.objects[models.objectIndex].indices.buffer, 0, VK_INDEX_TYPE_UINT32);

            Material mat = materials[materialIndex];

            for (uint32_t y = 0; y < GRID_DIM; y++) {
                for (uint32_t x = 0; x < GRID_DIM; x++) {
                    glm::vec3 pos = glm::vec3(float(x - (GRID_DIM / 2.0f)) * 2.5f, 0.0f, float(y - (GRID_DIM / 2.0f)) * 2.5f);
                    vkCmdPushConstants(drawCmdBuffers[i], pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(glm::vec3), &pos);
                    mat.params.metallic = glm::clamp((float)x / (float)(GRID_DIM - 1), 0.1f, 1.0f);
                    mat.params.roughness = glm::clamp((float)y / (float)(GRID_DIM - 1), 0.05f, 1.0f);
                    vkCmdPushConstants(drawCmdBuffers[i], pipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, sizeof(glm::vec3), sizeof(Material::PushBlock), &mat);
                    vkCmdDrawIndexed(drawCmdBuffers[i], models.objects[models.objectIndex].indexCount, 1, 0, 0, 0);
                }
            }

            drawUI(drawCmdBuffers[i]);

            vkCmdEndRenderPass(drawCmdBuffers[i]);

            VK_CHECK_RESULT(vkEndCommandBuffer(drawCmdBuffers[i]));

Существуют ли какие-либо гарантии того, что логические вызовы после логических вызовов будут видеть перед ними эффекты памяти, сделанные логическими вызовами?

Итак, вопрос в том, когда мне нужно синхронизировать между собой различные вызовы?

1 Ответ

2 голосов
/ 02 июля 2019

использует результаты любого предыдущего вызова или записи в одну и ту же цель рендеринга

Это , а не одно и то же.Побочные эффекты операции рендеринга (вещи, которые вы изменяете через загрузку / сохранение изображений или SSBO) и вещи, записанные в кадровый буфер, имеют очень разные потребности в отношении синхронизации.

Операции с фиксированной функцией, которые приводят кзапись значения в кадровый буфер (тест ножниц, проверка глубины, смешивание и т. д.) регулируется порядком растеризации : они должны происходить атомарно и в этом конкретном порядке, внутри данного примитива и для конкретного образцапотенциально записывается в буфер кадра.И выполнение таких операций также должно учитывать порядок примитивов : порядок примитивов, генерируемых командами рисования, но также и порядок примитивов в команде рисования.

Таким образом, что касается рендеринга, вызовы отрисовки будут учитывать результаты предыдущих вызовов отрисовки в пределах одного и того же подпроцесса (между подпроцессами действуют явные зависимости подпрохода).Вам не нужно делать ничего особенного, чтобы смешивать работу.Если у вас есть два перекрывающих друг друга треугольника, причем один происходит за другим по примитивному порядку, то при смешивании второго тиража будут использованы результаты первого тиража.Это просто работает.

Любая другая запись вашего шейдера требует явной синхронизации.

...