About render pass compatibility in Vulkan - vulkan

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.

Related

Is there way to force SPIR-V assembly function to accept both Private and Function storage class arrays?

I am in the process of writing a binary processing module for SPIR-V shaders to fix alignment issues with float4x3[6] matrices because of driver bugs. Right now i have:
injected necessary appropriate OpTypes and OpTypePointers.
processed the binary to change constant buffer members from float4x3[6] to vec4[18]
injected function properly unpacking vec4[18] into float4x3[6] accepting vec4[18] as a pointer to Uniform array 18.
created Private storage qualifier matrix unpack targets as OpVariables.(Private in SPIR-V just means invocation-level global...).
injected preambles about composite extraction and construction to call my new function. (since from what im seeing we need to copy arguments from constant buffers to functions always, so thats what I do).
called the function from entrypoint, for every float4x3[6] member to have ready unpacked matrices when main() starts.
changed OpAccessChain operations that referenced given members in constant buffers and swapped them with access chains referencing my new Private targets.
But now i ran into trouble. It looks like a function in SPIR-V can either accept Private or Function storage qualifier pointers. Not both. Is there any way i can tell SPIR-V "Yeah, you can dump both of those storage classes here as arguments"?
Or do i need to rework my solution to utilize Function storage class matrix targets, and inject them and calls to unpack them every single time they are used in a new function? This seems much less elegant since there might be way more unpack operations then. And much less hassle-free, since i would have to scan every OpFunction block separately and inject OpVariables with Function storage into every block that uses the matrices.
My problem is, after all this machinery is done my targets are living as OpTypePointer of Private Storage Duration. Therefore i cannot use them in ANY SPIR-V function generated from HLSL, since they take OpTypePointers of Function duration. My unpack function is sole exception to this since i injected it directly in SPIR-V asm, byte by byte and was able to precisely tune OpFunctionParameters in header.
This is a matter of calling conventions. Or rather, the lack of calling conventions in SPIR-V.
Higher-level languages like GLSL and HLSL have calling conventions. They explain what it means for a function to take an input parameter and how that relates to the argument being given to it.
SPIR-V doesn't have calling conventions in that sense. Or more to the point, you have to construct the calling conventions you want using SPIR-V.
Parameters in HLSL are conceptually always passed by copy. If the parameter is an input parameter, then the copy is initialized with the given argument. If the parameter is an output parameter, the data from the function is copied into the argument after calling the function.
The HLSL compiler must implement this in SPIR-V. So if a function takes a struct input parameter, that function's input parameter must be new storage from any existing object. When a caller tries to call this function, it must create storage for that parameter. That storage will use the Function storage qualifier, so the parameter also uses that qualifier.
SPIR-V requires that pointer types specify the storage qualifier of the objects they point to. This is important, as how the compiler goes about generating the GPU assembly which accesses the object can be different (perhaps drastically). As such, a function cannot accept a pointer that points to different storage classes; the function has to pick one.
So if your SPIR-V adjustment system sees a function call whose source data comes from something you need to adjust, then you have two options:
Create a new function which is a copy of the old one, except that it takes a Private pointer.
Follow the calling convention by creating Function-local storage and copying from your Private data into it prior to calling the function (and copying back out if it is an output parameter). There's probably code to do that sitting there already, so you probably only need to change where it copies from/to.

implicit subpass dependency and barriers

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.

Using same VkPipeline with more than one VkRenderPass

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.

How to synchronize vkCmdCopyBufferToImage()?

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.

How the EXPORTING method parameters passed by value?

I'm wondering about the definition of a call-by-value EXPORTING argument of an ABAP method call.
The SAP Help Portal states that EXPORTING parameters can be defined call-by-value (and call by reference). It does not give a precise definition of how this parameter type is handled. Instead, it states
For precise details of the relevant ABAP statements, refer to the
corresponding keyword documentation in the ABAP Editor.
Now, the ABAP Keyword Documentation of the SAP editor does not mention pass-by-value for EXPORTING. (It does mention pass-by-value for IMPORTING and CHANGING).
I can guess the meaning of pass-by-value EXPORTING. But I want to read the definition. From FORM/PERFORM, I know that details can be subtle. Could you point me to an official description of this case?
I'm not sure in what way the details can be subtle even when using FORMs - but anyway, it's in the documentation:
There are two ways in which parameters can be passed: pass by
reference and pass by value. Pass by value is selected in the Function
Builder by selecting pass by value, and in the above syntax, differs
from pass by reference by the specification of VALUE( ).
In pass by reference, the formal parameter points directly to the actual parameter, so that changes to the formal parameters have an
immediate effect on the actual parameter.
In pass by value, when the function module is called, the formal parameter is created as a copy of the actual parameter (in IMPORTING
and CHANGING parameters), or initial (in EXPORTING parameters) in
the stack. In CHANGING and EXPORTING parameters, the formal
parameter is copied to the actual parameter when returning from the
function module.