问题
As far as I understand, if I have a drawcall that in some way uses the results of any previous drawcall or writes to the same render target (framebuffer), then I need to make sure that the later drawcall sees the memory effects of all previous drawcalls.
But what about, when I am rendering a scene with a bunch of objects, each such object is one drawcall and all these drawcalls write to the same framebuffer.
Do I need to issue a memory barrier after every drawcall ?
For example Sascha Willem's pbrbasic example has this code (a bit simplified) and I do not see any pipelines barriers there:
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]));
Are there any guarantees that drawcalls logically following after will see the memory effects of drawcalls logically before them ?
So the question is, when do I need to synchronize between different drawcalls ?
回答1:
uses the results of any previous drawcall or writes to the same render target
Those are not the same thing. The side-effects of a rendering operation (stuff you modify via image load/store or SSBOs) and stuff written to the framebuffer have very different needs as far as synchronization is concerned.
The fixed function operations that lead to the writing of a value to the framebuffer (scissor test, depth test, blending, etc) are governed by rasterization order: they must happen atomically and in that particular order, within a given primitive and for a particular sample potentially being written to the frame buffer. And the execution of such operations must also respect primitive order: the order of primitives generated by drawing commands, but also the order of primitives within a drawing command.
So as far as rendering is concerned, draw calls will respect the results of previous draw calls, within the same subpass (between subpasses is governed by explicit subpass dependencies). You don't need to do anything special to make blending work. If you have two overlapping triangles, with one happening after the other by primitive order, the second draw's blending will use the results of the first draw. It just works.
Any other writing by your shader requires explicit synchronization.
来源:https://stackoverflow.com/questions/56849788/synchronization-between-drawcalls-in-vulkan