Closed jrprice closed 2 months ago
@jrprice thanks for the test.
@spencer-lunarg I checked this test before the writeonly change and after that, and the error existed in both cases with this difference:
Before writeonly change the access to the descriptor was determined as write (writeonly was true) and the error was WRITE_AFTER_WRITE
.
After writeonly change the descriptor access is determined as read which results in WRITE_AFTER_READ
.
Unfortunately current code does not have "no access" option, it assumes the resource is used and tries to classify it either as read or write. @spencer-lunarg Do you think it's possible to use IsReadFrom()
in addition to IsWrittenTo
to determine there are no accesses and in that case to skip hazard detection?
@jrprice thanks for getting a very minimal case
This is the SPIR-V
The OpImageQuerySize
is NOT an image read, but we there is still the OpLoad
and I currently mark that as a read access
so IsReadFrom() == true
but IsImageReadFrom() == false
here
note %image = OpVariable %12 UniformConstant
is layout(set = 0, binding = 0, rgba8) writeonly uniform image2D image;
changing the shader (to avoid dead code elimination)
#version 450
layout(set = 0, binding = 0, rgba8) writeonly uniform image2D image;
layout(set = 0, binding = 1) buffer SSBO { uvec2 size; } data;
void main(){
data.size = imageSize(image);
}
and running through Intel MESA, the final shader looks like
decl_var image INTERP_MODE_NONE restrict readonly writeonly r8g8b8a8_unorm image2D image (~0, 0, 0)
decl_var ssbo INTERP_MODE_NONE restrict writeonly SSBO data (~0, 0, 1)
decl_function main (0 params)
impl main {
con block b0: // preds:
con 32 %0 = load_const (0x00000000)
con 32 %1 = load_const (0xdeaddead = -6264320714451451904.000000 = -559030611 = 3735936685)
con 32 %2 = load_const (0x00000002 = 0.000000)
con 32 %3 = @resource_intel (%1 (0xdeaddead), %2 (0x2), %0 (0x0), %0 (0x0)) (desc_set=0, binding=0, resource_intel=0, resource_block_intel=-1)
con 32x2 %4 = @image_size (%3, %0 (0x0)) (image_dim=2D, image_array=false, format=r8g8b8a8_unorm, access=restrict|readonly|writeonly, range_base=0)
con 32 %5 = load_const (0x00000003 = 0.000000)
con 32 %6 = @resource_intel (%1 (0xdeaddead), %5 (0x3), %0 (0x0), %0 (0x0)) (desc_set=0, binding=1, resource_intel=0, resource_block_intel=-1)
@store_ssbo (%4, %6, %0 (0x0)) (wrmask=xy, access=writeonly, align_mul=1073741824, align_offset=0)
// succs: b1
block b1:
}
I can't find any documentation on resource_intel
but I am assuming this is an access
final update - got confirmation that
resource_intel reads the descriptor, not the image data
so for sync val that care about the data, this is should not be marked as a read, but for things like detecting if the descriptor was statically used this needs to marked as read
It looks like VVL treats
OpLoad
of an image handle as an access to the underlying texture storage, which is leading to false positives (e.g.SYNC-HAZARD-WRITE-AFTER-READ
).For example, a shader that only queries the dimensions of an image does not actually perform any accesses to that image. The Vulkan spec says:
I created this unit test for
sync_val_positive.cpp
which I believe captures the issue:The test fails with the following error:
The error indicates that the usage includes
SYNC_COMPUTE_SHADER_SHADER_STORAGE_READ
, despite the fact that no accesses are performed by the shader. I believe the issue is specifically tied to theOpLoad
instruction which loads the image handle, as I'm seeing these false positives with shaders that only do that.