Closed ghost closed 5 years ago
The problem is: you can fetch, sample and store any pixels from an attachment image in shaders within a subpass however you want, which should trigger pull of other framebuffer regions on tilers, as I understand?
Can you tell Vulkan explicitly that you won't need other framebuffer regions except the current one?
I guess you can simply say: how to force everything within a subpass to be framebuffer-local?
It is defining the scope of availability of data from one subpass to the next, so if both subpasses have the same number of samples, then the VK_DEPENDENCY_BY_REGION_BIT being set is saying that only a single pixel, or single sample, needs to be considered to be available.
If the first synchronization scope includes operations on pixels/fragments with N samples and the second synchronization scope includes operations on pixels/fragments with M samples, where N does not equal M, then a framebuffer region containing all samples at a given (x, y, layer) coordinate in the first synchronization scope corresponds to a region containing all samples at the same coordinate in the second synchronization scope. In other words, it is a pixel granularity dependency. If N equals M, then a framebuffer region containing a single (x, y, layer, sample) coordinate in the first synchronization scope corresponds to a region containing the same sample at the same coordinate in the second synchronization scope. In other words, it is a sample granularity dependency.
On a tile based implementation you'll have access to the framebuffer region from some form of close/internal storage, but your shader shouldn't try to access any other sample/pixel than in the framebuffer region as it cannot rely on the data being available, you'll get undefined behaviour if you were to do this (you might not even get the correct 'stale data').
The size of the framebuffer region used by the actual HW might be larger than a single pixel/sample, so sometimes the data might be available, but it is unknown to the application so no assumptions can be made other than you have access to pixel (x, y, layer) or sample (x, y, layer, sample).
Note
Since fragment invocations are not specified to run in any particular groupings, the size of a framebuffer region is implementation-dependent, not known to the application, and must be assumed to be no larger than specified above.
@CaffeinePwrdAl thank you so much for this detailed answer!
So it basically means you always have access to a single pixel only within any render pass?
Can any VK_IMAGEUSAGE* flags like VK_IMAGE_USAGE_SAMPLED_BIT
or VK_IMAGE_USAGE_STORAGE_BIT
break this single pixel promise?
Can you pass an image as a descriptor to a shader within a subpass that uses the same image as an attachment? If yes, will fetches/samples/stores in vertex or fragment stage through that descriptor break this single pixel promise and trigger pull of other framebuffer regions or those descriptor fetches/samples/stores will use other (or no) caches and won't invalidate the current framebuffer region?
By specifying a BY_REGION dependency you're giving the implementation an explicit guarantee of the application's behaviour, not a hint - with the bit set your shaders can only expect to have access to a single pixel (N != M) or sample (N == M) of that resource.
If the application steps outside that guarantee, behaviour will be undefined, an implementation won't be expecting it or spend 'cost' on checking and handle things 'just in case'.
Though it will vary depending on the IHV's particular implementation, I'd also suggest not thinking of it as just being a 'pull' of a framebuffer region, but that the framebuffer region might just not get 'pushed' anywhere until the end of the renderpass has been processed for that tile, so the data for the region is still available in a more favourable location in the GPU.
I'll have to check what Vulkan would expect if you specify a BY_REGION dependency and bind an image resource as both an input attachment and a sampled/storage image at the same time, particularly if the resource contents are the result of a colour attachment write in the same renderpass - I have an expectation in my head, but I can't seem to find the relevant spec so I'll check more closely and get back to you.
Can you pass an image as a descriptor to a shader within a subpass that uses the same image as an attachment?
Not unless that descriptor is an input attachment. While an image is being used as an attachment in a render pass instance, you may not use that image for anything other than attachment uses. At all.
This is stated explicitly in the Valid Usage section of the drawing functions:
Image subresources used as attachments in the current render pass must not be accessed in any way other than as an attachment by this command.
And for input attachments, you can only read from the pixel for that specific fragment; you're not allowed to read from anything else in that image. The SubpassData
instruction is required by Vulkan to use a UV offset of 0.
So your initial statement of "you can fetch, sample and store any pixels from an attachment image in shaders within a subpass however you want" is incorrect.
@NicolBolas awesome, thank you for pointing that out!
@CaffeinePwrdAl @NicolBolas thanks to both of you, I think this covers everything. :)
@procedural
FYI: questions like this are probably best handled on the Khronos forums first.
How can one promise to Vulkan that you won't look at any other pixels other than the current one?
I know there is a VK_DEPENDENCY_BY_REGION_BIT flag, but it's a guarantee for memory barriers, not shader level fetches, samples and stores.