vkCmdSetViewport problems

Is it possible to change the viewport on the fly inside a single render pass?
I’m getting weird results - graphics from the second viewport duplicated in the first viewport.
The graphics pipeline is correctly setup for dynamic viewports/scissors.

fpAcquireNextImageKHR(…)
vkResetCommandBuffer(…)
vkBeginCommandBuffer(…)
vkCmdBeginRenderPass(…)

for each sim {
vkCmdSetViewport(…)
vkCmdSetScissor(…)
vkUpdateDescriptorSets(…)
vkCmdBindPipeline(…)
vkCmdBindDescriptorSets(…)
vkCmdBindVertexBuffers(…)
vkCmdDrawIndexed(…)
}

vkCmdEndRenderPass(…)
vkCmdPipelineBarrier(…)
vkQueueWaitIdle(…)
vkQueueSubmit(…)

Is the above scenario valid? If so then there is some obscure bug in my code.

I don’t think it is prohibited.

Per the spec vkCmdSetViewport can be both inside or outside renderpass scope. The vkCmdDraw* commands seem to be the places that read the dynamic states.

On the other hand vkCmdSet* should preferably be called after the vkCmdBindPipeline.

Driver bug is also always a possibility.

I am not the original poster.

Can you explain what situations you are aware of where vkCmdSet* should be called after the vkCmdBindPipeline? I just wonder which Vulkan setups might misbehave and how?

It’s not clear what you mean.

The vkCmdSetViewport function is relevant only when rendering with a pipeline that has VK_DYNAMIC_STATE_VIEWPORT set on it. Otherwise, the state is ignored.

And like most other state, it is undefined at the beginning of command buffers, at the start/end of renderpasses and at every subpass transition.

Thanks, Alfonse!

I was specifically asking about the difference between methodA:

void methodA() {
  vkCmdBeginRenderPass(...);
  vkCmdSetViewport(...);
  vkCmdBindPipeline(...);
  vkCmdDraw(...);
}

and methodB:

void methodB() {
  vkCmdBeginRenderPass(...);
  vkCmdBindPipeline(...);
  vkCmdSetViewport(...);
  vkCmdDraw(...);
}

Your explanation makes sense: the order of vkCmdBindPipeline and vkCmdSetViewport does not matter.

It does matter that vkCmdSetViewport is called after vkCmdBeginRenderPass.

@dhubbard The VU says the currently bound pipeline must have that state set as dynamic.
That assumes there must be bound pipeline at all. It may be spec bug/omision.
And it requires the previous pipeline has that state also set as dynamic (even if that dynamic state is meant for the next bound pipeline).

I said it is preferrable though. vkCmdBindPipeline before vkCmdSetViewport is more obvious.
Besides it is not exactly clear to me what should happen if e.g. the previous pipeline has less viewports then the next one (for which the state is intended by the OP).

Ah, ok, I was wrong. Thanks, krOoze. It does matter to call vkCmdBindPipeline before vkCmdSetViewport.

Ok thanks everyone. I’m going to have to refactor the code to ensure vkCmdSetViewport executes after vkCmdBindPipeline. Will post results.