mesa/cs: Handle compute shader local size during linking.

Reviewed-by: Jordan Justen <jordan.l.justen@intel.com>
This commit is contained in:
Paul Berry 2014-01-08 11:59:28 -08:00
parent 0fa74e848f
commit 28ce604b7f
3 changed files with 88 additions and 0 deletions

View file

@ -1287,6 +1287,69 @@ link_gs_inout_layout_qualifiers(struct gl_shader_program *prog,
prog->Geom.VerticesOut = linked_shader->Geom.VerticesOut;
}
/**
* Perform cross-validation of compute shader local_size_{x,y,z} layout
* qualifiers for the attached compute shaders, and propagate them to the
* linked CS and linked shader program.
*/
static void
link_cs_input_layout_qualifiers(struct gl_shader_program *prog,
struct gl_shader *linked_shader,
struct gl_shader **shader_list,
unsigned num_shaders)
{
for (int i = 0; i < 3; i++)
linked_shader->Comp.LocalSize[i] = 0;
/* This function is called for all shader stages, but it only has an effect
* for compute shaders.
*/
if (linked_shader->Stage != MESA_SHADER_COMPUTE)
return;
/* From the ARB_compute_shader spec, in the section describing local size
* declarations:
*
* If multiple compute shaders attached to a single program object
* declare local work-group size, the declarations must be identical;
* otherwise a link-time error results. Furthermore, if a program
* object contains any compute shaders, at least one must contain an
* input layout qualifier specifying the local work sizes of the
* program, or a link-time error will occur.
*/
for (unsigned sh = 0; sh < num_shaders; sh++) {
struct gl_shader *shader = shader_list[sh];
if (shader->Comp.LocalSize[0] != 0) {
if (linked_shader->Comp.LocalSize[0] != 0) {
for (int i = 0; i < 3; i++) {
if (linked_shader->Comp.LocalSize[i] !=
shader->Comp.LocalSize[i]) {
linker_error(prog, "compute shader defined with conflicting "
"local sizes\n");
return;
}
}
}
for (int i = 0; i < 3; i++)
linked_shader->Comp.LocalSize[i] = shader->Comp.LocalSize[i];
}
}
/* Just do the intrastage -> interstage propagation right now,
* since we already know we're in the right type of shader program
* for doing it.
*/
if (linked_shader->Comp.LocalSize[0] == 0) {
linker_error(prog, "compute shader didn't declare local size\n");
return;
}
for (int i = 0; i < 3; i++)
prog->Comp.LocalSize[i] = linked_shader->Comp.LocalSize[i];
}
/**
* Combine a group of shaders for a single stage to generate a linked shader
*
@ -1391,6 +1454,7 @@ link_intrastage_shaders(void *mem_ctx,
ralloc_steal(linked, linked->UniformBlocks);
link_gs_inout_layout_qualifiers(prog, linked, shader_list, num_shaders);
link_cs_input_layout_qualifiers(prog, linked, shader_list, num_shaders);
populate_symbol_table(linked);

View file

@ -2185,6 +2185,11 @@ struct gl_fragment_program
struct gl_compute_program
{
struct gl_program Base; /**< base class */
/**
* Size specified using local_size_{x,y,z}.
*/
unsigned LocalSize[3];
};
@ -2646,6 +2651,18 @@ struct gl_shader_program
0 if not present. */
} Vert;
/**
* Compute shader state - copied into gl_compute_program by
* _mesa_copy_linked_program_data().
*/
struct {
/**
* If this shader contains a compute stage, size specified using
* local_size_{x,y,z}. Otherwise undefined.
*/
unsigned LocalSize[3];
} Comp;
/* post-link info: */
unsigned NumUserUniformStorage;
struct gl_uniform_storage *UniformStorage;

View file

@ -1846,6 +1846,13 @@ _mesa_copy_linked_program_data(gl_shader_stage type,
dst_gp->UsesEndPrimitive = src->Geom.UsesEndPrimitive;
}
break;
case MESA_SHADER_COMPUTE: {
struct gl_compute_program *dst_cp = (struct gl_compute_program *) dst;
int i;
for (i = 0; i < 3; i++)
dst_cp->LocalSize[i] = src->Comp.LocalSize[i];
}
break;
default:
break;
}