I need to render an image and copy it back to host. I issue the vkCmdCopyImageToBuffer() from the render pass result to a host readable buffer right after the vkCmdEndRenderPass(), it seems to work, but I am worried the copy starts before the rendering is finished (or the image is transitioned).
Do I need to perform some kind of synchronization, or it is implicitly guaranteed the image will be transitioned to the needed VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, which happens at the end of the render pass, before the copy is initiated? In the specs, where is this sequence defined?
The layout of an image after the execution of a renderpass is explicitly specified by you, when you constructed that renderpass. This is specified by VkAttachmentDescription::finalLayout for the attached image.
As for synchronization, that again is specified by you at renderpass creation time. Subpasses can have external dependencies, where they depend on something that happens before the renderpass, or where they cause something after the renderpass to depend on them.
That being said, if you do not specify a subpass dependency for which the destination subpass is VK_SUBPASS_EXTERNAL, then an implicit dependency is created (one of the few times Vulkan does synchronization implicitly). This implicit dependency synchronizes color, depth, and input attachments from any command with the bottom of the pipe. However, because it does not specify any destination access forms in its mask, this is not useful and you should provide an explicit external dependency.
Also, using bottom of the pipe as the destination stage is pretty much never useful.
Related
I'm studying Vulkan RenderPasses, for hobby.
I have the following descriptions for members of VkSubpassDependency struct.
The verbiage is a combination of language from sources(books, spec, internet), and
my own word-smithing. The descriptions might be wrong because of my messing with them.
// .srcSubpass:
// The subpass index from which "producing" operations should be finished before the second set of "consuming" operations executes.
// If there are no dependencies on previous subpasses(eg: first subpass), use VK_SUBPASS_EXTERNAL.
// .srcStageMask:
// A bitmask of the pipeline stages which produce the data read by the "consuming" commands.
// .srcAccessMask:
// The types of memory operations that occurred during the "producing" commands.
// ----------
// .dstSubpass:
// The index of the first subpass whose operations depend the output of this subpass; or VK_SUBPASS_EXTERNAL, if
// there are no destination subpasses dependencies.
// .dstStageMask:
// A bitmask of the pipeline stages which depend on the data generated by the "producing" commands.
// .dstAccessMask:
// The types of memory operations that will be performed in "consuming" commands.
I have some questions
Lets say that a RenderPass has 3 subpasses -- S1, S2, S3 -- which are "logically" executed in sequence, but which may be executed out of order by the GPU.
srcSubpass:
1.1. Is it possible for there to be a scenario in which S3 does not depend on either S1 nor S2? Or do subsequent subpasses always depend on some previous pass?
1.2. If 1.1 is true, then srcSubpass would be VK_SUBPASS_EXTERNAL, correct?
1.3. Or, does VK_SUBPASS_EXTERNAL only ever apply to S1?
2. dstSubpass:
2.1. Is this simply always the index of the next logical subpass (ie: S1->S2)? Or is it possible for it to be S1->S3?
2.2. Similar to question 1.1, is it possible for S3 not to depend on S2, and thus this value would be VK_SUBPASS_EXTERNAL for S2?
3. srcStageMask:
3.1. Is it the case that the earlier the pipeline stage is, the less the dependency between the 2 sets of operations would be?
That is, a srcStageMask of VK_PIPELINE_STAGE_VERTEX_INPUT_BIT would have a smaller dependency time than VK_PIPELINE_STAGE_VERTEX_SHADER_BIT.
3.2. If 3.1 is true, then this means that the ideal pipeline stage would be VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, correct?
4. dstStageMask:
4.1. For a smaller dependency time between 2 sets of operations, the farther down the pipeline, the better?
4.2. If 4.1 is true, then VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT would be the ideal stage, for minimum dependency. Yeah?
Thanks
1.1 Anything that is not impossible\invalid is by definition possible. Might make sense to render to two independent color attachments using the same vertex buffer. Might save on binning, which need only be done once.
1.2 Not necessarily. For example a subpass might have no color attachments and instead output via Storage Images. Therefore it needs no VK_SUBPASS_EXTERNAL dependecy, explict nor implicit.
1.3 No it applies to whichever subpass uses given attachment first, as that one executes the LoadOp for that attachment.
2.1 Yes, it is a dependency DAG, so it might have S1→S3, S2→S3 (and no S1→S2).
2.2 It might be VK_SUBPASS_EXTERNAL. Note you can have more dependencies; one can be VK_SUBPASS_EXTERNAL and other may have another subpass. One attachment in S2 might be finished and have early StoreOp here, and therefore VK_SUBPASS_EXTERNAL would be appropriate for it.
3.1 Yes, the more logically-earlier stage is used in srcStageMask, the restriction imposed by such dependency is lesser or equal.
3.2 Yes, that would be a no-op dependency. Coincidentally this is how the implicit subpass dependency is specified.
4.1 Yea, same logic. The more logically-later stage is used in `dstStageMask, the restriction imposed by such dependency is lesser or equal.
4.2 That is the no-op dependency. And coincidentally this is how the implicit subpass dependency is specified.
I must copy a color attachment into a buffer. Do I need an image memory barrier between the end of the render pass and the copy operation, to ensure visibility to the transfer?
The render pass has a single subpass with a single attachment. The VkAttachmentDescription.finalLayout differs from the VkAttachmentReference.layout, so an implicit subpass dependency with dstSubpass = VK_SUBPASS_EXTERNAL does indeed exists.
My confusion arises from the description of such implicit external dependency: it has a dstAccessMask = 0 and dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT. Since the transfer stage happens before the end of pipe pseudostage, does it mean I need to specify a barrier? Or does the implicit dependency only affect operations in the render pass, so I need a barrier anyway? As a side question, what is the meaning of 0 as a source or destination access mask?
Validation layers do not report any issue either with or without a barrier, and the output is as expected, but I am not sure it is correct though.
Yes, you need a dependency between _______ and _______ in Vulkan.
Implicit dependency exists in the spec only for formal reasons. Without it you would not know when the layout transition happens when used e.g. with a Semaphore. But in practice the implicit dependency is no-op. Its dst half does not cover anything.
The meaning of 0 in access mask is "no access". E.g. VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT stage does not read nor write anything, so the access flag accompanying it should be 0.
I read the portion relevant to "Render Pass Compatibility" in Vulkan specification. I'm not sure if my understanding is right.
Record some commands inside a render pass, which exists the invocation of VkFrameBuffer and VkPipeline. VkFrameBuffer or VkPipeline is strongly related to VkRenderPass. They must only be used with that render pass object, or one compatible with it. Can I reuse VkFrameBuffer or VkPipeline in a compatible render pass? Tell me more about this topic, please.
Not sure what do with your question except answer "yes".
VkRenderPassBeginInfo VU:
renderPass must be compatible with the renderPass member of the VkFramebufferCreateInfo structure specified when creating framebuffer.
e.g. vkCmdDraw VU:
The current render pass must be compatible with the renderPass member of the VkGraphicsPipelineCreateInfo structure specified when creating the VkPipeline bound to VK_PIPELINE_BIND_POINT_GRAPHICS.
I.e. the VkFramebuffer resp. VkPipeline has to be used with render pass that is "only" compatible, not necessarily the same object handle.
VkGraphicsPipelineCreateInfo expects assignment of a VkRenderPass to .renderPass property. I don't really understand why a pipeline must be coupled with render pass. I mean, VkGraphicsPipelineCreateInfo doesn't directly "talks" to render pass related content, like FBOs and their attachments. I may want to use same pipeline with more than one render pass, like in case where I want to render same set of objects in different scenes, so do I have to create another one with exactly the same setup?
Just to add that creating VkPipeline with .renderPass = nullptr fails with validation error:
vkCreateGraphicsPipelines: required parameter
pCreateInfos[0].renderPass specified as VK_NULL_HANDLE.Invalid
VkRenderPass Object 0x0. The Vulkan spec states: renderPass must be a
valid VkRenderPass handle
(https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-VkGraphicsPipelineCreateInfo-renderPass-parameter)
I mean VkGraphicsPipelineCreateInfo doesn't directly "talks" to render pass related content, like FBOs and their attachments.
Of course it does. What do you think a fragment shader is doing when it writes into a render pass' attachments?
Do I have to create another one with exactly the same setup?
No. As per the specification:
"renderPass is a handle to a render pass object describing the environment in which the pipeline will be used; the pipeline must only be used with an instance of any render pass compatible with the one provided. See Render Pass Compatibility for more information".
... so a pipeline can be used with any render pass that is compatible with the one used to create it.
I am curious about when the class side initialize messages are sent in Smalltalk (Pharo and Squeak particularly). Is there any specified order? Is it at least safe to assume all other classes packaged with it have already been loaded and compiled, or does the system eagerly initialize (send initialize before even finishing loading and compiling the other classes)?
The class-side initialize is never sent by the system. During development you do it manually (which is why many of these methods have a "self initialize" comment.
When exporting code of a class into a changeset, the exporter puts a send of initialize at the very end, so it gets executed when the class is loaded into another system.
This behavior is mimicked by Monticello. When loading a class for the first time, or when the code of the initialize method was changed, it is executed. That is because conceptually MC builds a changeset on-the-fly containing the difference of what is in the image already and what the package to be loaded contains. If that diff includes a class-side initialize method, it will be executed when loading that package version.
As you asked about loading and compiling, I'm assuming you mean when loading code...
When loading a package or changeset, class-side #initialize methods are called after all code is installed (1). While you can not count on a specific order, you can assume that all classes and methods from that package are loaded.
As Bert pointed out, if you were not loading but implementing class-side #initialize, you'd have to send the message yourself.
One way to know for sure, is to test it yourself. Smalltalk systems make this kind of thing a little more approachable than many other systems. Just define a your own MyTestClass, and then implement your own class side (that's important) initialize message so that you can discover for yourself when it fires, how often it fires, etc.
initialize
Transcript show: 'i have been INITIALIZED!!! Muwahahahah!!!'
Make sure it works by opening a Transcript and running
MyTestClass initialize
from a Workspace. Now you can play with filing it out and back in, Monticello loading, whatever and when it runs.