-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 On 07/05/2011 03:07 PM, Paul Berry wrote: > This patch adds a new build artifact, glsl_test, which can be used for > testing optimization passes in isolation. > > I'm hoping that we will be able to add other useful standalone tests > to this executable in the future. Accordingly, it is built in a > modular fashion: the main() function uses its first argument to > determine which test function to invoke, removes that argument from > argv[], and then calls that function to interpret the rest of the > command line arguments and perform the test. Currently the only test > function is "optpass", which tests optimization passes. > --- > src/glsl/.gitignore | 1 + > src/glsl/Makefile | 23 +++- > src/glsl/test.cpp | 78 +++++++++++ > src/glsl/test_optpass.cpp | 312 > +++++++++++++++++++++++++++++++++++++++++++++ > src/glsl/test_optpass.h | 30 +++++ > 5 files changed, 441 insertions(+), 3 deletions(-) > create mode 100644 src/glsl/test.cpp > create mode 100644 src/glsl/test_optpass.cpp > create mode 100644 src/glsl/test_optpass.h > > diff --git a/src/glsl/.gitignore b/src/glsl/.gitignore > index dfbd572..d26839a 100644 > --- a/src/glsl/.gitignore > +++ b/src/glsl/.gitignore > @@ -5,3 +5,4 @@ glsl_parser.h > glsl_parser.output > builtin_function.cpp > builtin_compiler > +glsl_test > diff --git a/src/glsl/Makefile b/src/glsl/Makefile > index 4100414..ce6a07d 100644 > --- a/src/glsl/Makefile > +++ b/src/glsl/Makefile > @@ -88,7 +88,7 @@ CXX_SOURCES = \ > LIBS = \ > $(TOP)/src/glsl/libglsl.a > > -APPS = glsl_compiler glcpp/glcpp > +APPS = glsl_compiler glsl_test glcpp/glcpp > > GLSL2_C_SOURCES = \ > ../mesa/program/hash_table.c \ > @@ -100,6 +100,18 @@ GLSL2_OBJECTS = \ > $(GLSL2_C_SOURCES:.c=.o) \ > $(GLSL2_CXX_SOURCES:.cpp=.o) > > +TEST_C_SOURCES = \ > + ../mesa/program/hash_table.c \ > + ../mesa/program/symbol_table.c > + > +TEST_CXX_SOURCES = \ > + test.cpp \ > + test_optpass.cpp > + > +TEST_OBJECTS = \ > + $(TEST_C_SOURCES:.c=.o) \ > + $(TEST_CXX_SOURCES:.cpp=.o) > + > ### Basic defines ### > > DEFINES += \ > @@ -128,7 +140,9 @@ ALL_SOURCES = \ > $(C_SOURCES) \ > $(CXX_SOURCES) \ > $(GLSL2_CXX_SOURCES) \ > - $(GLSL2_C_SOURCES) > + $(GLSL2_C_SOURCES) \ > + $(TEST_CXX_SOURCES) \ > + $(TEST_C_SOURCES) > > ##### TARGETS ##### > > @@ -150,7 +164,7 @@ depend: $(ALL_SOURCES) Makefile > > # Remove .o and backup files > clean: clean-dricore > - rm -f $(GLCPP_OBJECTS) $(GLSL2_OBJECTS) $(OBJECTS) lib$(LIBNAME).a > depend depend.bak builtin_function.cpp builtin_function.o builtin_stubs.o > builtin_compiler > + rm -f $(GLCPP_OBJECTS) $(GLSL2_OBJECTS) $(TEST_OBJECTS) $(OBJECTS) > lib$(LIBNAME).a depend depend.bak builtin_function.cpp builtin_function.o > builtin_stubs.o builtin_compiler > -rm -f $(APPS) > > clean-dricore: > @@ -173,6 +187,9 @@ install-dricore: default > glsl_compiler: $(GLSL2_OBJECTS) libglsl.a builtin_stubs.o > $(APP_CXX) $(INCLUDES) $(CFLAGS) $(LDFLAGS) $(GLSL2_OBJECTS) > builtin_stubs.o $(LIBS) -o $@ > > +glsl_test: $(TEST_OBJECTS) libglsl.a builtin_stubs.o > + $(APP_CXX) $(INCLUDES) $(CFLAGS) $(LDFLAGS) $(TEST_OBJECTS) > builtin_stubs.o $(LIBS) -o $@ > + > glcpp: glcpp/glcpp > glcpp/glcpp: $(GLCPP_OBJECTS) > $(APP_CC) $(INCLUDES) $(CFLAGS) $(LDFLAGS) $(GLCPP_OBJECTS) -o $@ > diff --git a/src/glsl/test.cpp b/src/glsl/test.cpp > new file mode 100644 > index 0000000..b1ff92e > --- /dev/null > +++ b/src/glsl/test.cpp > @@ -0,0 +1,78 @@ > +/* > + * Copyright © 2011 Intel Corporation > + * > + * Permission is hereby granted, free of charge, to any person obtaining a > + * copy of this software and associated documentation files (the "Software"), > + * to deal in the Software without restriction, including without limitation > + * the rights to use, copy, modify, merge, publish, distribute, sublicense, > + * and/or sell copies of the Software, and to permit persons to whom the > + * Software is furnished to do so, subject to the following conditions: > + * > + * The above copyright notice and this permission notice (including the next > + * paragraph) shall be included in all copies or substantial portions of the > + * Software. > + * > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL > + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING > + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER > + * DEALINGS IN THE SOFTWARE. > + */ > + > +/** > + * \file test.cpp > + * > + * Standalone tests for the GLSL compiler. > + * > + * This file provides a standalone executable which can be used to > + * test components of the GLSL. > + * > + * Each test is a function with the same signature as main(). The > + * main function interprets its first argument as the name of the test > + * to run, strips out that argument, and then calls the test function. > + */ > + > +#include <stdio.h> > +#include <stdlib.h> > +#include <string.h> > + > +#include "test_optpass.h" > + > +/** > + * Print proper usage and exit with failure. > + */ > +static void > +usage_fail(const char *name) > +{ > + printf("*** usage: %s <command> <options>\n", name); > + printf("\n"); > + printf("Possible commands are:\n"); > + printf(" optpass: test an optimization pass in isolation\n"); > + exit(EXIT_FAILURE); > +} > + > +static const char *extract_command_from_argv(int *argc, char **argv) > +{ > + if (*argc < 2) { > + usage_fail(argv[0]); > + } > + const char *command = argv[1]; > + --*argc; > + memmove(&argv[1], &argv[2], (*argc) * sizeof(argv[1])); > + return command; > +} > + > +int main(int argc, char **argv) > +{ > + const char *command = extract_command_from_argv(&argc, argv); > + if (strcmp(command, "optpass") == 0) { > + return test_optpass(argc, argv); > + } else { > + usage_fail(argv[0]); > + } > + > + /* Execution should never reach here. */ > + return EXIT_FAILURE; > +} > diff --git a/src/glsl/test_optpass.cpp b/src/glsl/test_optpass.cpp > new file mode 100644 > index 0000000..56402c9 > --- /dev/null > +++ b/src/glsl/test_optpass.cpp > @@ -0,0 +1,312 @@ > +/* > + * Copyright © 2011 Intel Corporation > + * > + * Permission is hereby granted, free of charge, to any person obtaining a > + * copy of this software and associated documentation files (the "Software"), > + * to deal in the Software without restriction, including without limitation > + * the rights to use, copy, modify, merge, publish, distribute, sublicense, > + * and/or sell copies of the Software, and to permit persons to whom the > + * Software is furnished to do so, subject to the following conditions: > + * > + * The above copyright notice and this permission notice (including the next > + * paragraph) shall be included in all copies or substantial portions of the > + * Software. > + * > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL > + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING > + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER > + * DEALINGS IN THE SOFTWARE. > + */ > + > +/** > + * \file test_optpass.cpp > + * > + * Standalone test for optimization passes. > + * > + * This file provides the "optpass" command for the standalone > + * glsl_test app. It accepts either GLSL or high-level IR as input, > + * and performs the optimiation passes specified on the command line. > + * It outputs the IR, both before and after optimiations. > + */ > + > +#include <string> > +#include <iostream> > +#include <sstream> > +#include <getopt.h> > + > +#include "ast.h" > +#include "ir_optimization.h" > +#include "ir_print_visitor.h" > +#include "program.h" > +#include "ir_reader.h" > + > +using namespace std; > + > +static struct gl_shader * > +_mesa_new_shader(struct gl_context *ctx, GLuint name, GLenum type) > +{ > + struct gl_shader *shader; > + > + (void) ctx; > + > + assert(type == GL_FRAGMENT_SHADER || type == GL_VERTEX_SHADER); > + shader = rzalloc(NULL, struct gl_shader); > + if (shader) { > + shader->Type = type; > + shader->Name = name; > + shader->RefCount = 1; > + } > + return shader; > +} > + > +static void initialize_context(struct gl_context *ctx, gl_api api) > +{ > + memset(ctx, 0, sizeof(*ctx)); > + > + ctx->API = api; > + > + ctx->Extensions.ARB_ES2_compatibility = GL_TRUE; > + ctx->Extensions.ARB_draw_buffers = GL_TRUE; > + ctx->Extensions.ARB_draw_instanced = GL_TRUE; > + ctx->Extensions.ARB_fragment_coord_conventions = GL_TRUE; > + ctx->Extensions.EXT_texture_array = GL_TRUE; > + ctx->Extensions.NV_texture_rectangle = GL_TRUE; > + ctx->Extensions.EXT_texture3D = GL_TRUE; > + > + ctx->Const.GLSLVersion = 120; > + > + /* 1.10 minimums. */ > + ctx->Const.MaxLights = 8; > + ctx->Const.MaxClipPlanes = 6; > + ctx->Const.MaxTextureUnits = 2; > + ctx->Const.MaxTextureCoordUnits = 2; > + ctx->Const.VertexProgram.MaxAttribs = 16; > + > + ctx->Const.VertexProgram.MaxUniformComponents = 512; > + ctx->Const.MaxVarying = 8; > + ctx->Const.MaxVertexTextureImageUnits = 0; > + ctx->Const.MaxCombinedTextureImageUnits = 2; > + ctx->Const.MaxTextureImageUnits = 2; > + ctx->Const.FragmentProgram.MaxUniformComponents = 64; > + > + ctx->Const.MaxDrawBuffers = 2; > + > + ctx->Driver.NewShader = _mesa_new_shader;
I'm a little uncomfortable with this part. We now have this code in two places outside the usual Mesa tree (the other is in src/glsl/main.cpp). We've had a hard enough time keeping one external set of values up to date, so adding another just seems like asking for trouble. Perhaps this could be refactored into glsl_parser_extras.cpp? > +} > + > +static string read_stdin_to_eof() > +{ > + stringbuf sb; > + cin.get(sb, '\0'); > + return sb.str(); > +} > + > +static GLboolean > +do_optimization(struct exec_list *ir, const char *optimization) > +{ > + int int_0; > + int int_1; > + int int_2; > + int int_3; > + int int_4; > + > + if (sscanf(optimization, "do_common_optimization ( %d , %d ) ", > + &int_0, &int_1) == 2) { > + return do_common_optimization(ir, int_0 != 0, int_1); > + } else if (strcmp(optimization, "do_algebraic") == 0) { > + return do_algebraic(ir); > + } else if (strcmp(optimization, "do_constant_folding") == 0) { > + return do_constant_folding(ir); > + } else if (strcmp(optimization, "do_constant_variable") == 0) { > + return do_constant_variable(ir); > + } else if (strcmp(optimization, "do_constant_variable_unlinked") == 0) { > + return do_constant_variable_unlinked(ir); > + } else if (strcmp(optimization, "do_copy_propagation") == 0) { > + return do_copy_propagation(ir); > + } else if (strcmp(optimization, "do_copy_propagation_elements") == 0) { > + return do_copy_propagation_elements(ir); > + } else if (strcmp(optimization, "do_constant_propagation") == 0) { > + return do_constant_propagation(ir); > + } else if (strcmp(optimization, "do_dead_code") == 0) { > + return do_dead_code(ir); > + } else if (strcmp(optimization, "do_dead_code_local") == 0) { > + return do_dead_code_local(ir); > + } else if (strcmp(optimization, "do_dead_code_unlinked") == 0) { > + return do_dead_code_unlinked(ir); > + } else if (strcmp(optimization, "do_dead_functions") == 0) { > + return do_dead_functions(ir); > + } else if (strcmp(optimization, "do_function_inlining") == 0) { > + return do_function_inlining(ir); > + } else if (sscanf(optimization, > + "do_lower_jumps ( %d , %d , %d , %d , %d ) ", > + &int_0, &int_1, &int_2, &int_3, &int_4) == 5) { > + return do_lower_jumps(ir, int_0 != 0, int_1 != 0, int_2 != 0, > + int_3 != 0, int_4 != 0); > + } else if (strcmp(optimization, "do_lower_texture_projection") == 0) { > + return do_lower_texture_projection(ir); > + } else if (strcmp(optimization, "do_if_simplification") == 0) { > + return do_if_simplification(ir); > + } else if (strcmp(optimization, "do_discard_simplification") == 0) { > + return do_discard_simplification(ir); > + } else if (sscanf(optimization, "lower_if_to_cond_assign ( %d ) ", > + &int_0) == 1) { > + return lower_if_to_cond_assign(ir, int_0); > + } else if (strcmp(optimization, "do_mat_op_to_vec") == 0) { > + return do_mat_op_to_vec(ir); > + } else if (strcmp(optimization, "do_noop_swizzle") == 0) { > + return do_noop_swizzle(ir); > + } else if (strcmp(optimization, "do_structure_splitting") == 0) { > + return do_structure_splitting(ir); > + } else if (strcmp(optimization, "do_swizzle_swizzle") == 0) { > + return do_swizzle_swizzle(ir); > + } else if (strcmp(optimization, "do_tree_grafting") == 0) { > + return do_tree_grafting(ir); > + } else if (strcmp(optimization, "do_vec_index_to_cond_assign") == 0) { > + return do_vec_index_to_cond_assign(ir); > + } else if (strcmp(optimization, "do_vec_index_to_swizzle") == 0) { > + return do_vec_index_to_swizzle(ir); > + } else if (strcmp(optimization, "lower_discard") == 0) { > + return lower_discard(ir); > + } else if (sscanf(optimization, "lower_instructions ( %d ) ", > + &int_0) == 1) { > + return lower_instructions(ir, int_0); > + } else if (strcmp(optimization, "lower_noise") == 0) { > + return lower_noise(ir); > + } else if (sscanf(optimization, "lower_variable_index_to_cond_assign " > + "( %d , %d , %d , %d ) ", &int_0, &int_1, &int_2, > + &int_3) == 4) { > + return lower_variable_index_to_cond_assign(ir, int_0 != 0, int_1 != 0, > + int_2 != 0, int_3 != 0); > + } else if (sscanf(optimization, "lower_quadop_vector ( %d ) ", > + &int_0) == 1) { > + return lower_quadop_vector(ir, int_0 != 0); > + } else if (strcmp(optimization, "optimize_redundant_jumps") == 0) { > + return optimize_redundant_jumps(ir); > + } else { > + printf("Unrecognized optimization %s\n", optimization); > + exit(EXIT_FAILURE); > + return false; > + } > +} > + > +static GLboolean > +do_optimization_passes(struct exec_list *ir, char **optimizations, > + int num_optimizations) > +{ > + GLboolean overall_progress = false; > + > + for (int i = 0; i < num_optimizations; ++i) { > + const char *optimization = optimizations[i]; > + printf("*** Running optimization %s...", optimization); > + GLboolean progress = do_optimization(ir, optimization); > + printf("%s\n", progress ? "progress" : "no progress"); > + validate_ir_tree(ir); > + > + overall_progress = overall_progress || progress; > + } > + > + return overall_progress; > +} > + > +int test_optpass(int argc, char **argv) > +{ > + int input_format_ir = 0; /* 0=glsl, 1=ir */ > + int loop = 0; > + int shader_type = GL_VERTEX_SHADER; > + > + const struct option optpass_opts[] = { > + { "input-ir", no_argument, &input_format_ir, 1 }, > + { "input-glsl", no_argument, &input_format_ir, 0 }, > + { "loop", no_argument, &loop, 1 }, > + { "vertex-shader", no_argument, &shader_type, GL_VERTEX_SHADER }, > + { "fragment-shader", no_argument, &shader_type, GL_FRAGMENT_SHADER }, > + { NULL, 0, NULL, 0 } > + }; > + > + int idx = 0; > + int c; > + while ((c = getopt_long(argc, argv, "", optpass_opts, &idx)) != -1) { > + if (c != 0) { > + printf("*** usage: %s optpass <optimizations> <options>\n", > argv[0]); > + printf("\n"); > + printf("Possible options are:\n"); > + printf(" --input-ir: input format is IR\n"); > + printf(" --input-glsl: input format is GLSL (the default)\n"); > + printf(" --loop: run optimizations repeatedly until no > progress\n"); > + printf(" --vertex-shader: test with a vertex shader (the > default)\n"); > + printf(" --fragment-shader: test with a fragment shader\n"); > + exit(EXIT_FAILURE); > + } > + } > + > + struct gl_context local_ctx; > + struct gl_context *ctx = &local_ctx; > + initialize_context(ctx, API_OPENGL); > + > + struct gl_shader *shader = rzalloc(NULL, struct gl_shader); > + shader->Type = shader_type; > + > + string input = read_stdin_to_eof(); > + > + struct _mesa_glsl_parse_state *state > + = new(shader) _mesa_glsl_parse_state(ctx, shader->Type, shader); > + > + if (input_format_ir) { > + shader->ir = new(shader) exec_list; > + _mesa_glsl_initialize_types(state); > + _mesa_glsl_read_ir(state, shader->ir, input.c_str(), true); > + } else { > + shader->Source = input.c_str(); > + const char *source = shader->Source; > + state->error = preprocess(state, &source, &state->info_log, > + state->extensions, ctx->API) != 0; > + > + if (!state->error) { > + _mesa_glsl_lexer_ctor(state, source); > + _mesa_glsl_parse(state); > + _mesa_glsl_lexer_dtor(state); > + } > + > + shader->ir = new(shader) exec_list; > + if (!state->error && !state->translation_unit.is_empty()) > + _mesa_ast_to_hir(shader->ir, state); > + } > + > + /* Print out the initial IR */ > + if (!state->error) { > + printf("*** pre-optimization IR:\n"); > + _mesa_print_ir(shader->ir, state); > + printf("\n--\n"); > + } > + > + /* Optimization passes */ > + if (!state->error) { > + GLboolean progress; > + do { > + progress = do_optimization_passes(shader->ir, &argv[optind], > + argc - optind); > + } while (loop && progress); > + } > + > + /* Print out the resulting IR */ > + if (!state->error) { > + printf("*** resulting IR:\n"); > + _mesa_print_ir(shader->ir, state); > + printf("\n--\n"); > + } > + > + if (state->error) { > + printf("*** error(s) occurred:\n"); > + printf("%s\n", state->info_log); > + printf("--\n"); > + } > + > + ralloc_free(state); > + ralloc_free(shader); > + > + return state->error; > +} > + > diff --git a/src/glsl/test_optpass.h b/src/glsl/test_optpass.h > new file mode 100644 > index 0000000..923ccf3 > --- /dev/null > +++ b/src/glsl/test_optpass.h > @@ -0,0 +1,30 @@ > +/* > + * Copyright © 2011 Intel Corporation > + * > + * Permission is hereby granted, free of charge, to any person obtaining a > + * copy of this software and associated documentation files (the "Software"), > + * to deal in the Software without restriction, including without limitation > + * the rights to use, copy, modify, merge, publish, distribute, sublicense, > + * and/or sell copies of the Software, and to permit persons to whom the > + * Software is furnished to do so, subject to the following conditions: > + * > + * The above copyright notice and this permission notice (including the next > + * paragraph) shall be included in all copies or substantial portions of the > + * Software. > + * > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL > + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING > + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER > + * DEALINGS IN THE SOFTWARE. > + */ > + > +#pragma once > +#ifndef TEST_OPTPASS_H > +#define TEST_OPTPASS_H > + > +int test_optpass(int argc, char **argv); > + > +#endif /* TEST_OPTPASS_H */ -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org/ iEYEARECAAYFAk4UtQAACgkQX1gOwKyEAw9TIACeMv8ydtfQMVmRsbse7871HOrB 17sAnjJ+wYyq6idFQqkIYfCCRPH229LR =Teie -----END PGP SIGNATURE----- _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev