0
votes

I have two types of vertices, each with it's own vertex and fragment shaders:

Vertex Type "A" => vertex shader "A" => fragment shader "A"
Vertex Type "B" => vertex shader "B" => fragment shader "B"

I need to keep vertices and shaders separate because they are fundamentally different.

I understand that I need two graphicsPipelines, because I have 4 stages (two vert, two frag) but they are not applied sequentially. With a single pipeline I can do this:

VkPipelineShaderStageCreateInfo shaderStages[] = {
    vertShaderStageCreateInfo,
    fragShaderStageCreateInfo
};

graphicsPipelineCreateInfo.pStages = shaderStages;

This is pretty obvious what it means. But I have 4 shader modules (shaders) and therefore 4 "stages", and on one pipeline I can only define one "stage sequence", like so:

Stage sequence: Stage 1 => Stage 2 => Stage 3 => Stage 4

This would be multipass rendering (I guess!).

But I need two separate stage sequences:

Stage sequence A: Stage 1 (vertex type A) => Stage 2 (vertex type A)
Stage sequence B: Stage 1 (vertex type B) => Stage 2 (vertex type B)

So that's why I need two pipelines, one for each "vertex type/shader set" (A and B).

QUESTION: Is this correct or am I misunderstanding pipelines?

Now, with the two pipelines (and pipelinLayouts) I have to record command buffers. In the single-pipeline approach I bind pipeline, pipelineLayout, descriptors and vertices:

void recordCommands(
    VkPipeline& graphicsPipeline,
    VkPipelineLayout& pipelineLayout,
    VkBuffer& vertexBuffer)
{
    vkCmdBeginRenderPass(...);

        vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline);
        vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet, 0, nullptr);
        vkCmdBindVertexBuffers(commandBuffer, 0, 1, vertexBuffers, offsets);
        vkCmdDraw(...);

    vkCmdEndRenderPass(...);
}

Can I draw two pipelines in one drawcall, like this?

BEGIN RENDER PASS
  BIND PIPELINE A, DESCRIPTORS, VERTEX_BUFFER A
  DRAW A
  BIND PIPELINE B, DESCRIPTORS, VERTEX_BUFFER B
  DRAW B
END RENDER PASS

Is this even possible? Or do I have to register two RENDER PASSES in the same command buffer (would this be multipass rendering)?

Or worse, do I have to register two command buffers and then do two VkSubmitInfo() one after the other? And by doing so, will I have to wait for the first command buffer to end ('VkQueueWaitIdle' or use semaphores), before I can submit the second command buffer? Or can I submit both command buffers immediately (it is called "queue" after all)?

1

1 Answers

2
votes

I honestly don't understand how you imagine pipelines work. They are just state, and are changed via binding, and you can only have one pipeline bound at a time. I don't think one pipeline can have multiple vertex shaders at once - you just have two pipelines bind one first, draw with it, then bind second and draw. One pipeline defining how the vertices and other data are processed, from the begining to pixel(end). And I don't remember anything that would stop you from changing pipelines within a single renderpass (besides cost, maybe - changing state has an overhead, although driver should be able to optimise a bit - how vulkan works helps). Also, if one pipeline depends on data produced by other(or one modifies data that is used by other, any order), you will need a barrier between them.

Multipass rendering is when you have multiple render passes, I think they are used if you want to use result of first pass as a texture in a second pass. There are also subpasses, which let you use result of first subpass in a second, with the restriction that you can only use data from same pixel. They are probably more efficient than separate passes...

Also, compute pipelines can't be used in render passes.