From 28ce604b7f2b08b967b6a27051ecab04adaed575 Mon Sep 17 00:00:00 2001 From: Paul Berry Date: Wed, 8 Jan 2014 11:59:28 -0800 Subject: [PATCH] mesa/cs: Handle compute shader local size during linking. Reviewed-by: Jordan Justen --- src/glsl/linker.cpp | 64 +++++++++++++++++++++++++++++++++++++++ src/mesa/main/mtypes.h | 17 +++++++++++ src/mesa/main/shaderapi.c | 7 +++++ 3 files changed, 88 insertions(+) diff --git a/src/glsl/linker.cpp b/src/glsl/linker.cpp index 32825ba41cc..6a07e4ab0d1 100644 --- a/src/glsl/linker.cpp +++ b/src/glsl/linker.cpp @@ -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); diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h index 36d98eeef87..8d81aa1592c 100644 --- a/src/mesa/main/mtypes.h +++ b/src/mesa/main/mtypes.h @@ -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; diff --git a/src/mesa/main/shaderapi.c b/src/mesa/main/shaderapi.c index 987c48aff34..571e13ca9b9 100644 --- a/src/mesa/main/shaderapi.c +++ b/src/mesa/main/shaderapi.c @@ -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; } -- 2.30.2