[Mesa-dev] [PATCH] glsl: Fix program interface queries relating to interface blocks.

Kenneth Graunke kenneth at whitecape.org
Mon Dec 19 22:13:18 UTC 2016


On Monday, December 19, 2016 1:36:00 PM PST Ian Romanick wrote:
> On 12/16/2016 09:35 PM, Kenneth Graunke wrote:
> > This fixes 555 dEQP tests (using the nougat-cts-dev branch), Piglit's
> > arb_program_interface_query/arb_program_interface_query-resource-query,
> > and GL45-CTS.program_interface_query.separate-programs-{tess-control,
> > tess-eval,geometry}.  Only one dEQP program interface failure remains.
> > 
> > I would have liked to split this up into several distinct changes, but
> > I wasn't sure how to do that given thet tangled nature of these issues.
> > 
> > So, the issues:
> > 
> >    * We need to treat interface blocks declared as an array of instances
> >      as a single block - removing the outer array.  The resource list
> >      entry's name should not include the array length.  Properties such
> >      as GL_ARRAY_SIZE should refer to the variable inside the block, not
> >      the interface block's array properties.
> > 
> >    * We need to do this prefixing even for structure variables.
> > 
> >    * We need to do this for built-ins (such as gl_PerVertex.gl_Position).
> > 
> >    * After interface array unwrapping, any variable which is an array
> >      should have [0] appended.  It doesn't matter if it's a TCS/TES/GS
> >      input or TCS output - that looked like an attempt to unwrap for
> >      per-vertex variables, but that didn't consider per-patch variables,
> >      and as far as I can tell there's nothing to justify this.
> > 
> > Several Mesa developers have suggested that Issue 16 contradicts the
> > main specification, but I believe that it doesn't - the main spec just
> > isn't terribly clear.  The main ARB_program_interface query spec says:
> > 
> >   "* For an active interface block not declared as an array of block
> >      instances, a single entry will be generated, using the block name from
> >      the shader source.
> > 
> >    * For an active interface block declared as an array of instances,
> >      separate entries will be generated for each active instance.  The name
> >      of the instance is formed by concatenating the block name, the "["
> >      character, an integer identifying the instance number, and the "]"
> >      character."
> > 
> > Issue 16 says that built-ins should be named "gl_PerVertex.gl_Position",
> > but several people suggested the second bullet above means that it
> > should be named "gl_PerVertex[array length].gl_Position".
> > 
> > There are two important things to note.  Those bullet points say
> > "an active interface block", while the others say "variable" or "active
> > shader storage block member".  They also don't mention applying the
> > rules recursively (unlike the other bullets).  Both suggest that
> > these rules apply to blocks themselves, not members of blocks.
> > 
> > In fact, for GL_UNIFORM_BLOCK queries, we do have "block[0]",
> > "block[1]", ... resource list entries - so those rules are real,
> > and actually used.  So if they don't apply to block members, then how
> > should members be named?  Unfortunately, I don't see any rules outside
> > of issue 16 - where the rationale is very unclear.  I hope to clarify
> > the spec in the future.
> 
> Based on my understanding, something like
> 
> out Vertex {
>     vec4 p;
>     vec4 c[3];
> } vertex[2];
> 
> in a vertex shader should produce
> 
>     Vertex[0].p
>     Vertex[0].c[0] (with GL_ARRAY_SIZE = 3)
>     Vertex[1].p
>     Vertex[1].c[0] (with GL_ARRAY_SIZE = 3)
> 
> This is definitely what we would produce for a uniform block.
> 
> What I've never understood is why that isn't done for gl_PerVertex stage
> boundaries where gl_PerVertex is explicitly arrayed.

My expectation is that the above code would produce:

Block entries:

    Vertex[0]
    Vertex[1]

Variable/member entries:

    Vertex.p
    Vertex.c[0] (with GL_ARRAY_SIZE = 3)

We would produce similar results for uniform blocks after my patch.

I don't think anything about the rules is gl_PerVertex specific.

> I think this patch is good for now.  I like that it brings all the
> strange edge-case handling into one place.
> 
> Reviewed-by: Ian Romanick <ian.d.romanick at intel.com>

I've attached some notes I took while looking at dEQP program interface
query tests - it has the shader code and expected results for a lot of
test cases.  I didn't write down the uniform ones, but they follow the
same pattern (as shown above).

For what it's worth, the OpenGL wiki's Program Introspection page(*),
under "Interface block member naming" gives an example matching my above
reply.  It says:

    uniform BlockName3
    {
      int mem;
    } instanceName3[4];

    This definition will create a single member named "BlockName3.min".
    The reason this array of four blocks only counts as having one
    variable is because each of the four blocks uses the same internal
    definition. There is nothing that could be queried from
    BlockName3[1] that could not be queried from BlockName3[0].

(*) https://www.khronos.org/opengl/wiki/Program_Introspection

I think that's a decent explanation of why this is reasonable.  Because
the block entries have per-element entries (Block[0], Block[1], etc. 
you can query whether a block is referenced (i.e. a UBO binding is used).

But for fields...things like names, locations, and so on would be the
same regardless of whether it's Block[0].field or Block[1].field.  So
they collapsed the field entries to "Block.field".

--Ken
-------------- next part --------------
╻┏┓╻┏━┓╺┳╸┏━┓┏┓╻┏━╸┏━╸╺┳┓   ╻┏┓╻╺┳╸┏━╸┏━┓┏━╸┏━┓┏━╸┏━╸┏━┓
┃┃┗┫┗━┓ ┃ ┣━┫┃┗┫┃  ┣╸  ┃┃   ┃┃┗┫ ┃ ┣╸ ┣┳┛┣╸ ┣━┫┃  ┣╸ ┗━┓
╹╹ ╹┗━┛ ╹ ╹ ╹╹ ╹┗━╸┗━╸╺┻┛   ╹╹ ╹ ╹ ┗━╸╹┗╸╹  ╹ ╹┗━╸┗━╸┗━┛

((
    Interface is an instanced array?  Unwrap it.
))


program_input.resource_list.interface_blocks.in.named_block.var

	in TargetInterface {
		highp vec4 target;
	} targetInstance;

    => TargetInterface.target

    OK.

program_input.resource_list.interface_blocks.in.named_block_explicit_location.var

	layout(location=3) in TargetInterface {
		highp vec4 target;
	} targetInstance;

    => TargetInterface.target

    OK.

program_input.resource_list.interface_blocks.in.named_block.var_array

	in TargetInterface {
		highp vec4 target[3];
	} targetInstance;

    => TargetInterface.target[0]

    OK.

program_input.resource_list.interface_blocks.in.named_block_explicit_location.var_array

	layout(location=3) in TargetInterface {
		highp vec4 target[3];
	} targetInstance;

    => TargetInterface.target[0]

    OK.

program_input.resource_list.interface_blocks.in.block_array.var
program_input.location.interface_blocks.in.block_array.var

    (FS)

    in TargetInterface {
        highp vec4 target;
    } targetInstance[3];

    => TargetInterface.target

    OK.

program_input.resource_list.interface_blocks.in.block_array.var_array

    (FS)

	in TargetInterface {
		highp vec4 target[3];
	} targetInstance[2];

    => TargetInterface.target[0]

    OK.

program_input.resource_list.interface_blocks.patch_in.named_block.var

	patch in TargetInterface {
		highp vec4 target;
	} targetInstance;

    => TargetInterface.target

    OK.

program_input.resource_list.interface_blocks.patch_in.named_block_explicit_location.var

	layout(location=3) patch in TargetInterface {
		highp vec4 target;
	} targetInstance;

    => TargetInterface.target

    OK.

program_input.resource_list.interface_blocks.patch_in.named_block.var_array

	patch in TargetInterface {
		highp vec4 target[3];
	} targetInstance;

    => TargetInterface.target[0]

    OK.

program_input.resource_list.interface_blocks.patch_in.named_block_explicit_location.var_array

	layout(location=3) patch in TargetInterface {
		highp vec4 target[3];
	} targetInstance;

    => TargetInterface.target[0]

    OK.

program_input.resource_list.interface_blocks.patch_in.block_array.var

	patch in TargetInterface {
		highp vec4 target;
	} targetInstance[3];

    => TargetInterface.target

    OK.

program_input.resource_list.interface_blocks.patch_in.block_array.var_array

    patch in TargetInterface {
		highp vec4 target[3];
	} targetInstance[2];

    => TargetInterface.target[0]

    OK.

program_output.resource_list.interface_blocks.out.named_block.var
program_output.resource_list.interface_blocks.out.named_block.var_array
program_output.resource_list.interface_blocks.out.named_block_explicit_location.var
program_output.resource_list.interface_blocks.out.named_block_explicit_location.var_array
program_output.resource_list.interface_blocks.out.block_array.var
program_output.resource_list.interface_blocks.out.block_array.var_array
program_output.resource_list.interface_blocks.patch_out.named_block.var
program_output.resource_list.interface_blocks.patch_out.named_block.var_array
program_output.resource_list.interface_blocks.patch_out.named_block_explicit_location.var
program_output.resource_list.interface_blocks.patch_out.named_block_explicit_location.var_array
program_output.resource_list.interface_blocks.patch_out.block_array.var_array

╻ ╻┏┓╻┏┓╻┏━┓┏┳┓┏━╸╺┳┓   ╻┏┓╻╺┳╸┏━╸┏━┓┏━╸┏━┓┏━╸┏━╸┏━┓
┃ ┃┃┗┫┃┗┫┣━┫┃┃┃┣╸  ┃┃   ┃┃┗┫ ┃ ┣╸ ┣┳┛┣╸ ┣━┫┃  ┣╸ ┗━┓
┗━┛╹ ╹╹ ╹╹ ╹╹ ╹┗━╸╺┻┛   ╹╹ ╹ ╹ ┗━╸╹┗╸╹  ╹ ╹┗━╸┗━╸┗━┛

program_input.resource_list.interface_blocks.in.unnamed_block.var

	in TargetInterface {
		highp vec4 target;
	};

    => target

program_input.resource_list.interface_blocks.in.unnamed_block.var_array

	in TargetInterface {
		highp vec4 target[3];
	};

    => target[0]

program_input.resource_list.interface_blocks.patch_in.unnamed_block.var

	patch in TargetInterface {
		highp vec4 target;
	};

    => target

program_input.resource_list.interface_blocks.patch_in.unnamed_block.var_array

	patch in TargetInterface {
		highp vec4 target[3];
	};

    => target[0]

program_output.resource_list.interface_blocks.out.unnamed_block.var
program_output.resource_list.interface_blocks.out.unnamed_block.var_array
program_output.resource_list.interface_blocks.patch_out.unnamed_block.var
program_output.resource_list.interface_blocks.patch_out.unnamed_block.var_array
program_output.resource_list.interface_blocks.patch_out.block_array.var

┏━┓╻┏┳┓┏━┓╻  ┏━╸   ╻ ╻┏━┓┏━┓╻┏━┓┏┓ ╻  ┏━╸┏━┓
┗━┓┃┃┃┃┣━┛┃  ┣╸    ┃┏┛┣━┫┣┳┛┃┣━┫┣┻┓┃  ┣╸ ┗━┓
┗━┛╹╹ ╹╹  ┗━╸┗━╸   ┗┛ ╹ ╹╹┗╸╹╹ ╹┗━┛┗━╸┗━╸┗━┛

((
	Use the name of the variable.  If an array, append "[0]".
))

program_input.resource_list.vertex_fragment.var
program_input.resource_list.separable_fragment.var

    in highp vec4 target;               =>          target

program_input.resource_list.separable_fragment.var_array

	in highp vec4 target[3];            =>          target[0]

program_input.resource_list.separable_tess_ctrl.var
program_input.resource_list.separable_tess_eval.var
program_input.resource_list.separable_geometry.var

    in highp vec4 target[];             =>          target[0]

program_input.resource_list.separable_tess_eval.patch_var

    patch in highp vec4 target;         =>          target

program_input.resource_list.separable_tess_eval.patch_var_array

    patch in highp vec4 target[3];      =>          target[0]

program_output.resource_list.vertex_fragment.var
program_output.resource_list.separable_vertex.var
program_output.resource_list.separable_fragment.var

    out highp vec4 target;              =>          target

program_output.resource_list.vertex_fragment.var_array
program_output.resource_list.separable_vertex.var_array
program_output.resource_list.separable_fragment.var_array

    out highp vec4 target[3];           =>          target[0]

program_output.resource_list.separable_tess_ctrl.var
program_output.resource_list.separable_tess_ctrl.patch_var
program_output.resource_list.separable_tess_ctrl.patch_var_array

    => gl_TessLevelOuter[0] and gl_TessLevelInner[0]

┏━┓╺┳╸┏━┓╻ ╻┏━╸╺┳╸┏━┓
┗━┓ ┃ ┣┳┛┃ ┃┃   ┃ ┗━┓
┗━┛ ╹ ╹┗╸┗━┛┗━╸ ╹ ┗━┛

((
	[<interface>.]<struct-name>.<recurse>
))

program_input.resource_list.separable_fragment.var_struct
program_input.resource_list.separable_tess_eval.patch_var_struct
program_input.resource_list.interface_blocks.in.named_block.var_struct
program_input.resource_list.interface_blocks.in.named_block_explicit_location.var_struct
program_input.resource_list.interface_blocks.in.unnamed_block.var_struct
program_input.resource_list.interface_blocks.in.block_array.var_struct
program_input.resource_list.interface_blocks.patch_in.named_block.var_struct
program_input.resource_list.interface_blocks.patch_in.named_block_explicit_location.var_struct
program_input.resource_list.interface_blocks.patch_in.unnamed_block.var_struct
program_input.resource_list.interface_blocks.patch_in.block_array.var_struct
program_output.resource_list.separable_vertex.var_struct
program_output.resource_list.separable_tess_ctrl.patch_var_struct
program_output.resource_list.separable_tess_eval.var_struct
program_output.resource_list.separable_geometry.var_struct
program_output.resource_list.interface_blocks.out.named_block.var_struct
program_output.resource_list.interface_blocks.out.named_block_explicit_location.var_struct
program_output.resource_list.interface_blocks.out.unnamed_block.var_struct
program_output.resource_list.interface_blocks.out.block_array.var_struct
program_output.resource_list.interface_blocks.patch_out.named_block.var_struct
program_output.resource_list.interface_blocks.patch_out.named_block_explicit_location.var_struct
program_output.resource_list.interface_blocks.patch_out.unnamed_block.var_struct
program_output.resource_list.interface_blocks.patch_out.block_array.var_struct

program_input.resource_list.interface_blocks.in.block_array.var_struct
program_input.array_size.interface_blocks.in.block_array.var_struct

    (FS)

	struct StructType0 {
		highp vec4 target;
	};

	in TargetInterface {
		StructType0 target;
	} targetInstance[3];

    => TargetInterface.target.target


program_input.resource_list.interface_blocks.patch_in.block_array.var_struct
program_input.array_size.interface_blocks.patch_in.block_array.var_struct

	struct StructType0 {
		highp vec4 target;
	};

	patch in TargetInterface {
		StructType0 target;
	} targetInstance[3];

    => TargetInterface.target.target

program_input.resource_list.separable_fragment.var_struct

	struct StructType0 {
		highp vec4 target;
	};

	in StructType0 target;

    => target.target
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: This is a digitally signed message part.
URL: <https://lists.freedesktop.org/archives/mesa-dev/attachments/20161219/ef7e15c6/attachment-0001.sig>


More information about the mesa-dev mailing list