This reduces confusion since gl_shader::Type is sometimes GL_SHADER_PROGRAM_MESA but is more frequently GL_SHADER_{VERTEX,GEOMETRY,FRAGMENT}. It also has the advantage that when switching on gl_shader::Stage, the compiler will alert if one of the possible enum types is unhandled. Finally, many functions in src/glsl (especially those dealing with linking) already use gl_shader_stage to represent pipeline stages; storing a gl_shader_stage in the gl_shader object avoids the need for a conversion. --- src/glsl/glsl_parser_extras.cpp | 4 +-- src/glsl/glsl_parser_extras.h | 15 +++++----- src/glsl/link_interface_blocks.cpp | 2 +- src/glsl/link_varyings.cpp | 22 +++++++-------- src/glsl/linker.cpp | 16 +++++------ src/glsl/lower_packed_varyings.cpp | 2 +- src/glsl/main.cpp | 1 + src/glsl/opt_dead_builtin_varyings.cpp | 4 +-- src/glsl/standalone_scaffolding.cpp | 1 + src/glsl/test_optpass.cpp | 1 + src/glsl/tests/builtin_variable_test.cpp | 1 + src/mesa/drivers/dri/i965/brw_shader.cpp | 6 ++-- src/mesa/drivers/dri/i965/brw_wm_surface_state.c | 2 +- src/mesa/main/mtypes.h | 35 ++++++++++++------------ src/mesa/main/shaderapi.c | 8 +++--- src/mesa/main/shaderobj.c | 1 + src/mesa/program/ir_to_mesa.cpp | 17 ++++++------ src/mesa/program/prog_print.c | 15 ++++++---- src/mesa/state_tracker/st_glsl_to_tgsi.cpp | 1 + 19 files changed, 83 insertions(+), 71 deletions(-)
diff --git a/src/glsl/glsl_parser_extras.cpp b/src/glsl/glsl_parser_extras.cpp index 492f2ac..bdd8bf4 100644 --- a/src/glsl/glsl_parser_extras.cpp +++ b/src/glsl/glsl_parser_extras.cpp @@ -1448,7 +1448,7 @@ static void set_shader_inout_layout(struct gl_shader *shader, struct _mesa_glsl_parse_state *state) { - if (shader->Type != GL_GEOMETRY_SHADER) { + if (shader->Stage != MESA_SHADER_GEOMETRY) { /* Should have been prevented by the parser. */ assert(!state->gs_input_prim_type_specified); assert(!state->out_qualifier->flags.i); @@ -1516,7 +1516,7 @@ _mesa_glsl_compile_shader(struct gl_context *ctx, struct gl_shader *shader, if (!state->error && !shader->ir->is_empty()) { struct gl_shader_compiler_options *options = - &ctx->ShaderCompilerOptions[_mesa_shader_enum_to_shader_stage(shader->Type)]; + &ctx->ShaderCompilerOptions[shader->Stage]; /* Do some optimization at compile time to reduce shader IR size * and reduce later work if the same shader is linked multiple times diff --git a/src/glsl/glsl_parser_extras.h b/src/glsl/glsl_parser_extras.h index ecf832f..a9c5117 100644 --- a/src/glsl/glsl_parser_extras.h +++ b/src/glsl/glsl_parser_extras.h @@ -423,14 +423,6 @@ extern bool _mesa_glsl_process_extension(const char *name, YYLTYPE *name_locp, YYLTYPE *behavior_locp, _mesa_glsl_parse_state *state); -/** - * Get the textual name of the specified shader target (which is a - * gl_shader_stage). - */ -extern const char * -_mesa_shader_stage_to_string(unsigned target); - - #endif /* __cplusplus */ @@ -441,6 +433,13 @@ _mesa_shader_stage_to_string(unsigned target); extern "C" { #endif +/** + * Get the textual name of the specified shader target (which is a + * gl_shader_stage). + */ +extern const char * +_mesa_shader_stage_to_string(unsigned target); + extern const char * _mesa_progshader_enum_to_string(GLenum type); diff --git a/src/glsl/link_interface_blocks.cpp b/src/glsl/link_interface_blocks.cpp index 4769636..52552cc 100644 --- a/src/glsl/link_interface_blocks.cpp +++ b/src/glsl/link_interface_blocks.cpp @@ -313,7 +313,7 @@ validate_interstage_inout_blocks(struct gl_shader_program *prog, const gl_shader *consumer) { interface_block_definitions definitions; - const bool extra_array_level = consumer->Type == GL_GEOMETRY_SHADER; + const bool extra_array_level = consumer->Stage == MESA_SHADER_GEOMETRY; /* Add input interfaces from the consumer to the symbol table. */ foreach_list(node, consumer->ir) { diff --git a/src/glsl/link_varyings.cpp b/src/glsl/link_varyings.cpp index ab40d45..da97e9f 100644 --- a/src/glsl/link_varyings.cpp +++ b/src/glsl/link_varyings.cpp @@ -1072,7 +1072,7 @@ assign_varying_locations(struct gl_context *ctx, const unsigned producer_base = VARYING_SLOT_VAR0; const unsigned consumer_base = VARYING_SLOT_VAR0; varying_matches matches(ctx->Const.DisableVaryingPacking, - consumer && consumer->Type == GL_FRAGMENT_SHADER); + consumer && consumer->Stage == MESA_SHADER_FRAGMENT); hash_table *tfeedback_candidates = hash_table_ctor(0, hash_table_string_hash, hash_table_string_compare); hash_table *consumer_inputs @@ -1217,9 +1217,9 @@ assign_varying_locations(struct gl_context *ctx, linker_error(prog, "%s shader varying %s not written " "by %s shader\n.", - _mesa_progshader_enum_to_string(consumer->Type), + _mesa_shader_stage_to_string(consumer->Stage), var->name, - _mesa_progshader_enum_to_string(producer->Type)); + _mesa_shader_stage_to_string(producer->Stage)); } /* An 'in' variable is only really a shader input if its @@ -1250,14 +1250,14 @@ check_against_output_limit(struct gl_context *ctx, } unsigned max_output_components; - switch (producer->Type) { - case GL_VERTEX_SHADER: + switch (producer->Stage) { + case MESA_SHADER_VERTEX: max_output_components = ctx->Const.VertexProgram.MaxOutputComponents; break; - case GL_GEOMETRY_SHADER: + case MESA_SHADER_GEOMETRY: max_output_components = ctx->Const.GeometryProgram.MaxOutputComponents; break; - case GL_FRAGMENT_SHADER: + case MESA_SHADER_FRAGMENT: default: assert(!"Should not get here."); return false; @@ -1299,14 +1299,14 @@ check_against_input_limit(struct gl_context *ctx, } unsigned max_input_components; - switch (consumer->Type) { - case GL_GEOMETRY_SHADER: + switch (consumer->Stage) { + case MESA_SHADER_GEOMETRY: max_input_components = ctx->Const.GeometryProgram.MaxInputComponents; break; - case GL_FRAGMENT_SHADER: + case MESA_SHADER_FRAGMENT: max_input_components = ctx->Const.FragmentProgram.MaxInputComponents; break; - case GL_VERTEX_SHADER: + case MESA_SHADER_VERTEX: default: assert(!"Should not get here."); return false; diff --git a/src/glsl/linker.cpp b/src/glsl/linker.cpp index 428a044..91a7220 100644 --- a/src/glsl/linker.cpp +++ b/src/glsl/linker.cpp @@ -438,7 +438,7 @@ analyze_clip_usage(struct gl_shader_program *prog, if (clip_vertex.variable_found() && clip_distance.variable_found()) { linker_error(prog, "%s shader writes to both `gl_ClipVertex' " "and `gl_ClipDistance'\n", - _mesa_progshader_enum_to_string(shader->Type)); + _mesa_shader_stage_to_string(shader->Stage)); return; } *UsesClipDistance = clip_distance.variable_found(); @@ -1209,7 +1209,7 @@ link_gs_inout_layout_qualifiers(struct gl_shader_program *prog, /* No in/out qualifiers defined for anything but GLSL 1.50+ * geometry shaders so far. */ - if (linked_shader->Type != GL_GEOMETRY_SHADER || prog->Version < 150) + if (linked_shader->Stage != MESA_SHADER_GEOMETRY || prog->Version < 150) return; /* From the GLSL 1.50 spec, page 46: @@ -1376,7 +1376,7 @@ link_intrastage_shaders(void *mem_ctx, if (main == NULL) { linker_error(prog, "%s shader lacks `main'\n", - _mesa_progshader_enum_to_string(shader_list[0]->Type)); + _mesa_shader_stage_to_string(shader_list[0]->Stage)); return NULL; } @@ -1450,7 +1450,7 @@ link_intrastage_shaders(void *mem_ctx, validate_ir_tree(linked->ir); /* Set the size of geometry shader input arrays */ - if (linked->Type == GL_GEOMETRY_SHADER) { + if (linked->Stage == MESA_SHADER_GEOMETRY) { unsigned num_vertices = vertices_per_prim(prog->Geom.InputType); geom_array_resize_visitor input_resize_visitor(num_vertices, prog); foreach_iter(exec_list_iterator, iter, *linked->ir) { @@ -2049,16 +2049,16 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog) goto done; } - switch (prog->Shaders[i]->Type) { - case GL_VERTEX_SHADER: + switch (prog->Shaders[i]->Stage) { + case MESA_SHADER_VERTEX: vert_shader_list[num_vert_shaders] = prog->Shaders[i]; num_vert_shaders++; break; - case GL_FRAGMENT_SHADER: + case MESA_SHADER_FRAGMENT: frag_shader_list[num_frag_shaders] = prog->Shaders[i]; num_frag_shaders++; break; - case GL_GEOMETRY_SHADER: + case MESA_SHADER_GEOMETRY: geom_shader_list[num_geom_shaders] = prog->Shaders[i]; num_geom_shaders++; break; diff --git a/src/glsl/lower_packed_varyings.cpp b/src/glsl/lower_packed_varyings.cpp index 9edef5d..c23d180 100644 --- a/src/glsl/lower_packed_varyings.cpp +++ b/src/glsl/lower_packed_varyings.cpp @@ -669,7 +669,7 @@ lower_packed_varyings(void *mem_ctx, unsigned location_base, gs_input_vertices, &new_instructions); visitor.run(instructions); if (mode == ir_var_shader_out) { - if (shader->Type == GL_GEOMETRY_SHADER) { + if (shader->Stage == MESA_SHADER_GEOMETRY) { /* For geometry shaders, outputs need to be lowered before each call * to EmitVertex() */ diff --git a/src/glsl/main.cpp b/src/glsl/main.cpp index 2f59848..3260c44 100644 --- a/src/glsl/main.cpp +++ b/src/glsl/main.cpp @@ -362,6 +362,7 @@ main(int argc, char **argv) shader->Type = GL_FRAGMENT_SHADER; else usage_fail(argv[0]); + shader->Stage = _mesa_shader_enum_to_shader_stage(shader->Type); shader->Source = load_text_file(whole_program, argv[optind]); if (shader->Source == NULL) { diff --git a/src/glsl/opt_dead_builtin_varyings.cpp b/src/glsl/opt_dead_builtin_varyings.cpp index a939a2b..c2a306e 100644 --- a/src/glsl/opt_dead_builtin_varyings.cpp +++ b/src/glsl/opt_dead_builtin_varyings.cpp @@ -512,7 +512,7 @@ do_dead_builtin_varyings(struct gl_context *ctx, tfeedback_decl *tfeedback_decls) { /* Lower the gl_FragData array to separate variables. */ - if (consumer && consumer->Type == GL_FRAGMENT_SHADER) { + if (consumer && consumer->Stage == MESA_SHADER_FRAGMENT) { lower_fragdata_array(consumer->ir); } @@ -574,7 +574,7 @@ do_dead_builtin_varyings(struct gl_context *ctx, * This doesn't prevent elimination of the gl_TexCoord elements which * are not read by the fragment shader. We want to eliminate those anyway. */ - if (consumer->Type == GL_FRAGMENT_SHADER) { + if (consumer->Stage == MESA_SHADER_FRAGMENT) { producer_info.texcoord_usage = (1 << MAX_TEXTURE_COORD_UNITS) - 1; } diff --git a/src/glsl/standalone_scaffolding.cpp b/src/glsl/standalone_scaffolding.cpp index 73dfe5c..6a71745 100644 --- a/src/glsl/standalone_scaffolding.cpp +++ b/src/glsl/standalone_scaffolding.cpp @@ -76,6 +76,7 @@ _mesa_new_shader(struct gl_context *ctx, GLuint name, GLenum type) shader = rzalloc(NULL, struct gl_shader); if (shader) { shader->Type = type; + shader->Stage = _mesa_shader_enum_to_shader_stage(type); shader->Name = name; shader->RefCount = 1; } diff --git a/src/glsl/test_optpass.cpp b/src/glsl/test_optpass.cpp index 01f6f95..bdb1e8f 100644 --- a/src/glsl/test_optpass.cpp +++ b/src/glsl/test_optpass.cpp @@ -204,6 +204,7 @@ int test_optpass(int argc, char **argv) struct gl_shader *shader = rzalloc(NULL, struct gl_shader); shader->Type = shader_type; + shader->Stage = _mesa_shader_enum_to_shader_stage(shader_type); string input = read_stdin_to_eof(); diff --git a/src/glsl/tests/builtin_variable_test.cpp b/src/glsl/tests/builtin_variable_test.cpp index 63949ee..9b4a097 100644 --- a/src/glsl/tests/builtin_variable_test.cpp +++ b/src/glsl/tests/builtin_variable_test.cpp @@ -65,6 +65,7 @@ common_builtin::SetUp() this->shader = rzalloc(this->mem_ctx, gl_shader); this->shader->Type = this->shader_type; + this->shader->Stage = _mesa_shader_enum_to_shader_stage(this->shader_type); this->state = new(mem_ctx) _mesa_glsl_parse_state(&this->ctx, this->shader->Type, diff --git a/src/mesa/drivers/dri/i965/brw_shader.cpp b/src/mesa/drivers/dri/i965/brw_shader.cpp index a40df6d..33197eb 100644 --- a/src/mesa/drivers/dri/i965/brw_shader.cpp +++ b/src/mesa/drivers/dri/i965/brw_shader.cpp @@ -40,6 +40,7 @@ brw_new_shader(struct gl_context *ctx, GLuint name, GLuint type) shader = rzalloc(NULL, struct brw_shader); if (shader) { shader->base.Type = type; + shader->base.Stage = _mesa_shader_enum_to_shader_stage(type); shader->base.Name = name; _mesa_init_shader(ctx, &shader->base); } @@ -261,7 +262,8 @@ brw_link_shader(struct gl_context *ctx, struct gl_shader_program *shProg) if (ctx->Shader.Flags & GLSL_DUMP) { printf("\n"); printf("GLSL IR for linked %s program %d:\n", - _mesa_progshader_enum_to_string(shader->base.Type), shProg->Name); + _mesa_shader_stage_to_string(shader->base.Stage), + shProg->Name); _mesa_print_ir(shader->base.ir, NULL); printf("\n"); } @@ -274,7 +276,7 @@ brw_link_shader(struct gl_context *ctx, struct gl_shader_program *shProg) continue; printf("GLSL %s shader %d source for linked program %d:\n", - _mesa_progshader_enum_to_string(sh->Type), + _mesa_shader_stage_to_string(sh->Stage), i, shProg->Name); printf("%s", sh->Source); diff --git a/src/mesa/drivers/dri/i965/brw_wm_surface_state.c b/src/mesa/drivers/dri/i965/brw_wm_surface_state.c index 5236eda..acb1a40 100644 --- a/src/mesa/drivers/dri/i965/brw_wm_surface_state.c +++ b/src/mesa/drivers/dri/i965/brw_wm_surface_state.c @@ -842,7 +842,7 @@ brw_upload_ubo_surfaces(struct brw_context *brw, brw_create_constant_surface(brw, bo, binding->Offset, bo->size - binding->Offset, &surf_offsets[i], - shader->Type == GL_FRAGMENT_SHADER); + shader->Stage == MESA_SHADER_FRAGMENT); } if (shader->NumUniformBlocks) diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h index 9e2083c..37e0592 100644 --- a/src/mesa/main/mtypes.h +++ b/src/mesa/main/mtypes.h @@ -393,6 +393,23 @@ typedef enum /** + * Shader stages. Note that these will become 5 with tessellation. + * + * The order must match how shaders are ordered in the pipeline. + * The GLSL linker assumes that if i<j, then the j-th shader is + * executed later than the i-th shader. + */ +typedef enum +{ + MESA_SHADER_VERTEX = 0, + MESA_SHADER_GEOMETRY = 1, + MESA_SHADER_FRAGMENT = 2, +} gl_shader_stage; + +#define MESA_SHADER_STAGES (MESA_SHADER_FRAGMENT + 1) + + +/** * Framebuffer configuration (aka visual / pixelformat) * Note: some of these fields should be boolean, but it appears that * code in drivers/dri/common/util.c requires int-sized fields. @@ -2302,6 +2319,7 @@ struct gl_shader * Must be the first field. */ GLenum Type; + gl_shader_stage Stage; GLuint Name; /**< AKA the handle */ GLchar *Label; /**< GL_KHR_debug */ GLint RefCount; /**< Reference count */ @@ -2387,23 +2405,6 @@ struct gl_shader }; -/** - * Shader stages. Note that these will become 5 with tessellation. - * - * The order must match how shaders are ordered in the pipeline. - * The GLSL linker assumes that if i<j, then the j-th shader is - * executed later than the i-th shader. - */ -typedef enum -{ - MESA_SHADER_VERTEX = 0, - MESA_SHADER_GEOMETRY = 1, - MESA_SHADER_FRAGMENT = 2, -} gl_shader_stage; - -#define MESA_SHADER_STAGES (MESA_SHADER_FRAGMENT + 1) - - struct gl_uniform_buffer_variable { char *Name; diff --git a/src/mesa/main/shaderapi.c b/src/mesa/main/shaderapi.c index fc76f23..16a9a38 100644 --- a/src/mesa/main/shaderapi.c +++ b/src/mesa/main/shaderapi.c @@ -778,7 +778,7 @@ compile_shader(struct gl_context *ctx, GLuint shaderObj) if (!sh) return; - options = &ctx->ShaderCompilerOptions[_mesa_shader_enum_to_shader_stage(sh->Type)]; + options = &ctx->ShaderCompilerOptions[sh->Stage]; /* set default pragma state for shader */ sh->Pragmas = options->DefaultPragmas; @@ -791,7 +791,7 @@ compile_shader(struct gl_context *ctx, GLuint shaderObj) } else { if (ctx->Shader.Flags & GLSL_DUMP) { printf("GLSL source for %s shader %d:\n", - _mesa_progshader_enum_to_string(sh->Type), sh->Name); + _mesa_shader_stage_to_string(sh->Stage), sh->Name); printf("%s\n", sh->Source); } @@ -823,7 +823,7 @@ compile_shader(struct gl_context *ctx, GLuint shaderObj) if (!sh->CompileStatus) { if (ctx->Shader.Flags & GLSL_DUMP_ON_ERROR) { fprintf(stderr, "GLSL source for %s shader %d:\n", - _mesa_progshader_enum_to_string(sh->Type), sh->Name); + _mesa_shader_stage_to_string(sh->Stage), sh->Name); fprintf(stderr, "%s\n", sh->Source); fprintf(stderr, "Info Log:\n%s\n", sh->InfoLog); fflush(stderr); @@ -898,7 +898,7 @@ print_shader_info(const struct gl_shader_program *shProg) printf("Mesa: glUseProgram(%u)\n", shProg->Name); for (i = 0; i < shProg->NumShaders; i++) { printf(" %s shader %u, checksum %u\n", - _mesa_progshader_enum_to_string(shProg->Shaders[i]->Type), + _mesa_shader_stage_to_string(shProg->Shaders[i]->Stage), shProg->Shaders[i]->Name, shProg->Shaders[i]->SourceChecksum); } diff --git a/src/mesa/main/shaderobj.c b/src/mesa/main/shaderobj.c index 3076fb4..dc81bbc 100644 --- a/src/mesa/main/shaderobj.c +++ b/src/mesa/main/shaderobj.c @@ -110,6 +110,7 @@ _mesa_new_shader(struct gl_context *ctx, GLuint name, GLenum type) shader = rzalloc(NULL, struct gl_shader); if (shader) { shader->Type = type; + shader->Stage = _mesa_shader_enum_to_shader_stage(type); shader->Name = name; _mesa_init_shader(ctx, shader); } diff --git a/src/mesa/program/ir_to_mesa.cpp b/src/mesa/program/ir_to_mesa.cpp index ae4a6e2..88e94fa 100644 --- a/src/mesa/program/ir_to_mesa.cpp +++ b/src/mesa/program/ir_to_mesa.cpp @@ -2493,8 +2493,7 @@ _mesa_generate_parameters_list_for_uniforms(struct gl_shader_program struct gl_program_parameter_list *params) { - add_uniform_to_shader add(shader_program, params, - _mesa_shader_enum_to_shader_stage(sh->Type)); + add_uniform_to_shader add(shader_program, params, sh->Stage); foreach_list(node, sh->ir) { ir_variable *var = ((ir_instruction *) node)->as_variable(); @@ -2801,18 +2800,18 @@ get_mesa_program(struct gl_context *ctx, int i; struct gl_program *prog; GLenum target; - const char *target_string = _mesa_progshader_enum_to_string(shader->Type); + const char *target_string = _mesa_shader_stage_to_string(shader->Stage); struct gl_shader_compiler_options *options = - &ctx->ShaderCompilerOptions[_mesa_shader_enum_to_shader_stage(shader->Type)]; + &ctx->ShaderCompilerOptions[shader->Stage]; - switch (shader->Type) { - case GL_VERTEX_SHADER: + switch (shader->Stage) { + case MESA_SHADER_VERTEX: target = GL_VERTEX_PROGRAM_ARB; break; - case GL_FRAGMENT_SHADER: + case MESA_SHADER_FRAGMENT: target = GL_FRAGMENT_PROGRAM_ARB; break; - case GL_GEOMETRY_SHADER: + case MESA_SHADER_GEOMETRY: target = GL_GEOMETRY_PROGRAM_NV; break; default: @@ -3007,7 +3006,7 @@ _mesa_ir_link_shader(struct gl_context *ctx, struct gl_shader_program *prog) bool progress; exec_list *ir = prog->_LinkedShaders[i]->ir; const struct gl_shader_compiler_options *options = - &ctx->ShaderCompilerOptions[_mesa_shader_enum_to_shader_stage(prog->_LinkedShaders[i]->Type)]; + &ctx->ShaderCompilerOptions[prog->_LinkedShaders[i]->Stage]; do { progress = false; diff --git a/src/mesa/program/prog_print.c b/src/mesa/program/prog_print.c index fa120cc..9391e99 100644 --- a/src/mesa/program/prog_print.c +++ b/src/mesa/program/prog_print.c @@ -1005,16 +1005,21 @@ _mesa_print_parameter_list(const struct gl_program_parameter_list *list) void _mesa_write_shader_to_file(const struct gl_shader *shader) { - const char *type; + const char *type = "????"; char filename[100]; FILE *f; - if (shader->Type == GL_FRAGMENT_SHADER) + switch (shader->Stage) { + case MESA_SHADER_FRAGMENT: type = "frag"; - else if (shader->Type == GL_VERTEX_SHADER) + break; + case MESA_SHADER_VERTEX: type = "vert"; - else + break; + case MESA_SHADER_GEOMETRY: type = "geom"; + break; + } _mesa_snprintf(filename, sizeof(filename), "shader_%u.%s", shader->Name, type); f = fopen(filename, "w"); @@ -1061,7 +1066,7 @@ _mesa_append_uniforms_to_file(const struct gl_shader *shader) char filename[100]; FILE *f; - if (shader->Type == GL_FRAGMENT_SHADER) + if (shader->Stage == MESA_SHADER_FRAGMENT) type = "frag"; else type = "vert"; diff --git a/src/mesa/state_tracker/st_glsl_to_tgsi.cpp b/src/mesa/state_tracker/st_glsl_to_tgsi.cpp index b2131ed..bd4eb5e 100644 --- a/src/mesa/state_tracker/st_glsl_to_tgsi.cpp +++ b/src/mesa/state_tracker/st_glsl_to_tgsi.cpp @@ -5207,6 +5207,7 @@ st_new_shader(struct gl_context *ctx, GLuint name, GLuint type) shader = rzalloc(NULL, struct gl_shader); if (shader) { shader->Type = type; + shader->Stage = _mesa_shader_enum_to_shader_stage(type); shader->Name = name; _mesa_init_shader(ctx, shader); } -- 1.8.5.2 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev