KhronosGroup / SPIRV-Reflect

SPIRV-Reflect is a lightweight library that provides a C/C++ reflection API for SPIR-V shader bytecode in Vulkan applications.
Apache License 2.0
672 stars 147 forks source link

Reflecting capabilities used by a shader more finely #222

Open mbechard opened 1 year ago

mbechard commented 1 year ago

If I'm given an arbitrary shader and I want to see if it runs on the local hardware, I can use reflection to see if any capabilities are being requested that the hardware doesn't support. However this isn't quite fine grained enough in many cases. For example if SpvCapabilityAtomicFloat32AddEXT is declared, I can see if VK_EXT_shader_atomic_floatis supported as a first check. However the hardware may support atomic float operations on some data types and not others, as per the entries in VkPhysicalDeviceShaderAtomicFloatFeaturesEXT. For example on macOS shaderImageFloat32AtomicAdd is not currently supported.

Is there any path forward where we can see what kinds of operations are applied to data, such as flags on a reflected image descriptor saying it was used for an atomic float operation?

spencer-lunarg commented 1 year ago
#version 450
#extension GL_EXT_shader_explicit_arithmetic_types_int64 : enable
#extension GL_EXT_shader_image_int64 : enable
layout(set = 0, binding = 0) buffer ssbo { uint64_t y; };
layout(set = 0, binding = 1, r64ui) uniform u64image2D z;
void main() {
    y = imageAtomicAdd(z, ivec2(1, 1), y);
}

will currently show

accessed: 1

but I can see how having a "type of access" flag to list if it was atomic could be helpful

Seems like something I could take a crack at

mbechard commented 12 months ago

That would be amazing. A related request is this: https://github.com/KhronosGroup/SPIRV-Reflect/issues/99 where it would be useful to know if the resource is used via a read and/or a write operation. This would allow more finely controlling the VkAccessFlags used on the resource before it's used.

spencer-lunarg commented 11 months ago

@mbechard I have an implementation of this in https://github.com/KhronosGroup/SPIRV-Reflect/pull/224 (which I still need to invest more time before I feel comfortable merging it)

I would love feedback on it if you think it works as expected for your use case

mbechard commented 11 months ago

Thanks! This looks great. Seems to work with a simple test case. Offhand I would expect the READ/WRITE flags to also be set when ATOMIC is set though. It allows for logic that is just looking if a resource is read or written to handle those flags regardless of if the operation happens to be atomic or not

spencer-lunarg commented 11 months ago

I would expect the READ/WRITE flags to also be set when ATOMIC is set though

I wasn't 100% if it made sense to have it do that or not... I think you are right and would be easier to just have to check for READ then READ or ATOMIC

chaoticbob commented 9 months ago

I finally had some time to look at #224 .

I wanted to get a better understanding of what the purpose of the READ/WRITE flags are?

If the the READ/WRITE flag is to indicate if a descriptor binding is READ_ONLY or READ_WRITE, then having SPV_REFLECT_RESOURCE_FLAG_UAV set on SpvReflectDescriptorBinding::resource_type will indicate that it's READ_WRITE - otherwise is is READ_ONLY.

spencer-lunarg commented 9 months ago

something else worth noting from my PR, something like

 %ac = OpAccessChain %ptr %index
 %14 = OpArrayLength %uint %ac 1

I am not sure if this is actually a "read" (seems it isn't from the spec) but currently this is marked as "accessed"

edit: this is a bug, OpArrayLength is an access (https://gitlab.khronos.org/vulkan/vulkan/-/issues/3682)

mbechard commented 5 months ago

@chaoticbob The purpose is to determine how a resource is actually used in the shader, rather than just using how it's declared. There may be code that writes to a READ_WRITE resource, however due to optimization it ends up getting removed in one compilation, thus the resource is only actually READ, and code that is using reflection to determine synchronization can optimize based on that more refined knowledge.