lovr icon indicating copy to clipboard operation
lovr copied to clipboard

Shader:getVariables

Open bjornbytes opened this issue 11 months ago • 1 comments

Requested in chat. Use case is reflecting shader variables for an inspector/debug UI.

Thought about exposing separate getBuffers, getTextures, getSamplers, etc. methods, but this seems too messy, and you have to name them like getBufferNames to make it clear they don't return resources, just the resource names. It's more clean to just have getVariables and let the user filter them, or maybe accept some filter params eventually.

LÖVE has a corresponding feature request with some discussion: https://github.com/love2d/love/issues/2137

Current API idea is Shader:getVariables to match the existing Shader:hasVariable. Other names would be possible. getUniforms doesn't make sense because this will also expose "resources" like buffers/textures. getInputs could be good, but I feel it is slightly less clear than "variable".

The return value would be a table where the key is a variable name and the value is the type of variable. One big question is whether it returns the type of a uniform, like this:

{
  radius = 'float',
  direction = 'vec3',
  transforms = 'buffer'
}

This seems good, but we support structs/arrays too. Should we return complicated format tables like this?

{
  lights = {
    name = 'lights',
    stride = 32,
    length = 8,
    offset = 0,
    type = {
      { name = 'pos', type = 'f32x3', offset = 0 },
      { name = 'type', type = 'u32', offset = 12 },
      { name = 'color', type = 'f32x4', offset = 16 }
    }
  },
  sky = 'texture',
  transforms = 'buffer'
}

This doesn't feel right, it feels like the method is returning too much information. I lean towards just returning the basic "variable type" and leaving further metadata to other methods. So the keys are variable names and the values are a new VariableType enum, like this:

{
  lights = 'uniform',
  sky = 'texture',
  transforms = 'buffer'
}

We could expand Shader:getBufferFormat to support uniforms too, so that you can get the full format. This makes the name confusing though since now it works with both uniforms and buffers. It could be renamed to Shader:getDataFormat, Shader:getVariableFormat, etc., or we could just leave it as-is without too much trouble.

bjornbytes avatar Feb 06 '25 21:02 bjornbytes

Tried implementing this. The main challenge is that we don't actually know variable names for anything in the C code, we just know their hashes. So we'll have to do the thing where we measure how many bytes we need for all the uniform/resource names, allocate extra space in the names array, save a name pointer for everything, and copy them out of the spirv.

Since we only need these names for :getVariables, it might actually make more sense to just store separate resourceNames and uniformNames arrays? We don't want/need to add the name to ShaderResource or DataField.

bjornbytes avatar Feb 06 '25 21:02 bjornbytes