[Mesa-dev] [PATCH 06/12] glsl: Add arb_cull_distance support (v2)

Dave Airlie airlied at gmail.com
Fri May 13 06:14:28 UTC 2016


From: Tobias Klausmann <tobias.johannes.klausmann at mni.thm.de>

v2: make too large array a compile error

Signed-off-by: Tobias Klausmann <tobias.johannes.klausmann at mni.thm.de>
Signed-off-by: Dave Airlie <airlied at redhat.com>
---
 src/compiler/glsl/ast_to_hir.cpp             |  46 ++++++++----
 src/compiler/glsl/builtin_variables.cpp      |  11 ++-
 src/compiler/glsl/glcpp/glcpp-parse.y        |   3 +
 src/compiler/glsl/glsl_parser_extras.cpp     |   1 +
 src/compiler/glsl/glsl_parser_extras.h       |   8 ++
 src/compiler/glsl/link_varyings.cpp          |  10 +++
 src/compiler/glsl/link_varyings.h            |   1 +
 src/compiler/glsl/linker.cpp                 | 108 +++++++++++++++++++++------
 src/compiler/glsl/standalone_scaffolding.cpp |   1 +
 src/compiler/glsl/tests/varyings_test.cpp    |  27 +++++++
 src/compiler/shader_enums.h                  |   4 +
 11 files changed, 181 insertions(+), 39 deletions(-)

diff --git a/src/compiler/glsl/ast_to_hir.cpp b/src/compiler/glsl/ast_to_hir.cpp
index 5a1fc9f..338edc8 100644
--- a/src/compiler/glsl/ast_to_hir.cpp
+++ b/src/compiler/glsl/ast_to_hir.cpp
@@ -1196,20 +1196,38 @@ check_builtin_array_max_size(const char *name, unsigned size,
       _mesa_glsl_error(&loc, state, "`gl_TexCoord' array size cannot "
                        "be larger than gl_MaxTextureCoords (%u)",
                        state->Const.MaxTextureCoords);
-   } else if (strcmp("gl_ClipDistance", name) == 0
-              && size > state->Const.MaxClipPlanes) {
-      /* From section 7.1 (Vertex Shader Special Variables) of the
-       * GLSL 1.30 spec:
-       *
-       *   "The gl_ClipDistance array is predeclared as unsized and
-       *   must be sized by the shader either redeclaring it with a
-       *   size or indexing it only with integral constant
-       *   expressions. ... The size can be at most
-       *   gl_MaxClipDistances."
-       */
-      _mesa_glsl_error(&loc, state, "`gl_ClipDistance' array size cannot "
-                       "be larger than gl_MaxClipDistances (%u)",
-                       state->Const.MaxClipPlanes);
+   } else if (strcmp("gl_ClipDistance", name) == 0) {
+      state->clip_dist_size = size;
+      if (size + state->cull_dist_size > state->Const.MaxClipPlanes) {
+         /* From section 7.1 (Vertex Shader Special Variables) of the
+          * GLSL 1.30 spec:
+          *
+          *   "The gl_ClipDistance array is predeclared as unsized and
+          *   must be sized by the shader either redeclaring it with a
+          *   size or indexing it only with integral constant
+          *   expressions. ... The size can be at most
+          *   gl_MaxClipDistances."
+          */
+         _mesa_glsl_error(&loc, state, "`gl_ClipDistance' array size cannot "
+                          "be larger than gl_MaxClipDistances (%u)",
+                          state->Const.MaxClipPlanes);
+      }
+   } else if (strcmp("gl_CullDistance", name) == 0) {
+      state->cull_dist_size = size;
+      if (size + state->clip_dist_size > state->Const.MaxClipPlanes) {
+         /* From the ARB_cull_distance spec:
+          *
+          *   "The gl_CullDistance array is predeclared as unsized and
+          *    must be sized by the shader either redeclaring it with
+          *    a size or indexing it only with integral constant
+          *    expressions. The size determines the number and set of
+          *    enabled cull distances and can be at most
+          *    gl_MaxCullDistances."
+          */
+         _mesa_glsl_error(&loc, state, "`gl_CullDistance' array size cannot "
+                          "be larger than gl_MaxCullDistances (%u)",
+                          state->Const.MaxClipPlanes);
+      }
    }
 }
 
diff --git a/src/compiler/glsl/builtin_variables.cpp b/src/compiler/glsl/builtin_variables.cpp
index cc32990..ff8a7e2 100644
--- a/src/compiler/glsl/builtin_variables.cpp
+++ b/src/compiler/glsl/builtin_variables.cpp
@@ -302,7 +302,7 @@ public:
    const glsl_type *construct_interface_instance() const;
 
 private:
-   glsl_struct_field fields[10];
+   glsl_struct_field fields[11];
    unsigned num_fields;
 };
 
@@ -678,6 +678,11 @@ builtin_variable_generator::generate_constants()
       add_const("gl_MaxClipDistances", state->Const.MaxClipPlanes);
       add_const("gl_MaxVaryingComponents", state->ctx->Const.MaxVarying * 4);
    }
+   if (state->is_version(450, 0) || state->ARB_cull_distance_enable) {
+      add_const("gl_MaxCullDistances", state->Const.MaxClipPlanes);
+      add_const("gl_MaxCombinedClipAndCullDistances",
+                state->Const.MaxClipPlanes);
+   }
 
    if (state->has_geometry_shader()) {
       add_const("gl_MaxVertexOutputComponents",
@@ -1249,6 +1254,10 @@ builtin_variable_generator::generate_varyings()
        add_varying(VARYING_SLOT_CLIP_DIST0, array(float_t, 0),
                    "gl_ClipDistance");
    }
+   if (state->is_version(450, 0) || state->ARB_cull_distance_enable) {
+      add_varying(VARYING_SLOT_CULL_DIST0, array(float_t, 0),
+                   "gl_CullDistance");
+   }
 
    if (compatibility) {
       add_varying(VARYING_SLOT_TEX0, array(vec4_t, 0), "gl_TexCoord");
diff --git a/src/compiler/glsl/glcpp/glcpp-parse.y b/src/compiler/glsl/glcpp/glcpp-parse.y
index a48266c..e44f074 100644
--- a/src/compiler/glsl/glcpp/glcpp-parse.y
+++ b/src/compiler/glsl/glcpp/glcpp-parse.y
@@ -2457,6 +2457,9 @@ _glcpp_parser_handle_version_declaration(glcpp_parser_t *parser, intmax_t versio
 
          if (extensions->ARB_shader_draw_parameters)
             add_builtin_define(parser, "GL_ARB_shader_draw_parameters", 1);
+
+         if (extensions->ARB_cull_distance)
+            add_builtin_define(parser, "GL_ARB_cull_distance", 1);
       }
    }
 
diff --git a/src/compiler/glsl/glsl_parser_extras.cpp b/src/compiler/glsl/glsl_parser_extras.cpp
index 463cb97..771fd19 100644
--- a/src/compiler/glsl/glsl_parser_extras.cpp
+++ b/src/compiler/glsl/glsl_parser_extras.cpp
@@ -576,6 +576,7 @@ static const _mesa_glsl_extension _mesa_glsl_supported_extensions[] = {
    EXT(ARB_arrays_of_arrays,             true,  false,     ARB_arrays_of_arrays),
    EXT(ARB_compute_shader,               true,  false,     ARB_compute_shader),
    EXT(ARB_conservative_depth,           true,  false,     ARB_conservative_depth),
+   EXT(ARB_cull_distance,                true,  false,     ARB_cull_distance),
    EXT(ARB_derivative_control,           true,  false,     ARB_derivative_control),
    EXT(ARB_draw_buffers,                 true,  false,     dummy_true),
    EXT(ARB_draw_instanced,               true,  false,     ARB_draw_instanced),
diff --git a/src/compiler/glsl/glsl_parser_extras.h b/src/compiler/glsl/glsl_parser_extras.h
index 7018347..aaf12dd 100644
--- a/src/compiler/glsl/glsl_parser_extras.h
+++ b/src/compiler/glsl/glsl_parser_extras.h
@@ -520,6 +520,8 @@ struct _mesa_glsl_parse_state {
    bool ARB_compute_shader_warn;
    bool ARB_conservative_depth_enable;
    bool ARB_conservative_depth_warn;
+   bool ARB_cull_distance_enable;
+   bool ARB_cull_distance_warn;
    bool ARB_derivative_control_enable;
    bool ARB_derivative_control_warn;
    bool ARB_draw_buffers_enable;
@@ -702,6 +704,12 @@ struct _mesa_glsl_parse_state {
     * did the parser just parse a dot.
     */
    bool is_field;
+
+   /**
+    * seen values for clip/cull distance sizes
+    * so we can check totals aren't too large.
+    */
+   unsigned clip_dist_size, cull_dist_size;
 };
 
 # define YYLLOC_DEFAULT(Current, Rhs, N)			\
diff --git a/src/compiler/glsl/link_varyings.cpp b/src/compiler/glsl/link_varyings.cpp
index 2555cc9..003b9d4 100644
--- a/src/compiler/glsl/link_varyings.cpp
+++ b/src/compiler/glsl/link_varyings.cpp
@@ -631,6 +631,10 @@ tfeedback_decl::init(struct gl_context *ctx, const void *mem_ctx,
        strcmp(this->var_name, "gl_ClipDistance") == 0) {
       this->lowered_builtin_array_variable = clip_distance;
    }
+   if (ctx->Const.ShaderCompilerOptions[MESA_SHADER_VERTEX].LowerCombinedClipCullDistance &&
+       strcmp(this->var_name, "gl_CullDistance") == 0) {
+      this->lowered_builtin_array_variable = cull_distance;
+   }
 
    if (ctx->Const.LowerTessLevel &&
        (strcmp(this->var_name, "gl_TessLevelOuter") == 0))
@@ -691,6 +695,9 @@ tfeedback_decl::assign_location(struct gl_context *ctx,
       case clip_distance:
          actual_array_size = prog->LastClipDistanceArraySize;
          break;
+      case cull_distance:
+         actual_array_size = prog->LastCullDistanceArraySize;
+         break;
       case tess_level_outer:
          actual_array_size = 4;
          break;
@@ -911,6 +918,9 @@ tfeedback_decl::find_candidate(gl_shader_program *prog,
    case clip_distance:
       name = "gl_ClipDistanceMESA";
       break;
+   case cull_distance:
+      name = "gl_CullDistanceMESA";
+      break;
    case tess_level_outer:
       name = "gl_TessLevelOuterMESA";
       break;
diff --git a/src/compiler/glsl/link_varyings.h b/src/compiler/glsl/link_varyings.h
index 543b80f..0ad4f74 100644
--- a/src/compiler/glsl/link_varyings.h
+++ b/src/compiler/glsl/link_varyings.h
@@ -210,6 +210,7 @@ private:
    enum {
       none,
       clip_distance,
+      cull_distance,
       tess_level_outer,
       tess_level_inner,
    } lowered_builtin_array_variable;
diff --git a/src/compiler/glsl/linker.cpp b/src/compiler/glsl/linker.cpp
index a85072d..eae10655 100644
--- a/src/compiler/glsl/linker.cpp
+++ b/src/compiler/glsl/linker.cpp
@@ -641,19 +641,25 @@ link_invalidate_variable_locations(exec_list *ir)
 
 
 /**
- * Set clip_distance_array_size based on the given shader.
+ * Set clip_distance_array_size based and cull_distance_array_size on the given
+ * shader.
  *
  * Also check for errors based on incorrect usage of gl_ClipVertex and
- * gl_ClipDistance.
+ * gl_ClipDistance and gl_CullDistance.
+ * Additionally test whether the arrays gl_ClipDistance and gl_CullDistance
+ * exceed the maximum size defined by gl_MaxCombinedClipAndCullDistances.
  *
  * Return false if an error was reported.
  */
 static void
-analyze_clip_usage(struct gl_shader_program *prog,
-                   struct gl_shader *shader,
-                   GLuint *clip_distance_array_size)
+analyze_clip_cull_usage(struct gl_shader_program *prog,
+                        struct gl_shader *shader,
+                        struct gl_context *ctx,
+                        GLuint *clip_distance_array_size,
+                        GLuint *cull_distance_array_size)
 {
    *clip_distance_array_size = 0;
+   *cull_distance_array_size = 0;
 
    if (!prog->IsES && prog->Version >= 130) {
       /* From section 7.1 (Vertex Shader Special Variables) of the
@@ -667,23 +673,62 @@ analyze_clip_usage(struct gl_shader_program *prog,
        */
       find_assignment_visitor clip_vertex("gl_ClipVertex");
       find_assignment_visitor clip_distance("gl_ClipDistance");
+      find_assignment_visitor cull_distance("gl_CullDistance");
 
       clip_vertex.run(shader->ir);
       clip_distance.run(shader->ir);
+      cull_distance.run(shader->ir);
+
+      /* From the ARB_cull_distance spec:
+       *
+       * It is a compile-time or link-time error for the set of shaders forming
+       * a program to statically read or write both gl_ClipVertex and either
+       * gl_ClipDistance or gl_CullDistance.
+       *
+       * This does not apply to GLSL ES shaders, since GLSL ES defines neither
+       * gl_ClipVertex, gl_ClipDistance or gl_CullDistance.
+       */
       if (clip_vertex.variable_found() && clip_distance.variable_found()) {
          linker_error(prog, "%s shader writes to both `gl_ClipVertex' "
                       "and `gl_ClipDistance'\n",
                       _mesa_shader_stage_to_string(shader->Stage));
          return;
       }
+      if (clip_vertex.variable_found() && cull_distance.variable_found()) {
+         linker_error(prog, "%s shader writes to both `gl_ClipVertex' "
+                      "and `gl_CullDistance'\n",
+                      _mesa_shader_stage_to_string(shader->Stage));
+         return;
+      }
 
       if (clip_distance.variable_found()) {
          ir_variable *clip_distance_var =
-               shader->symbols->get_variable("gl_ClipDistance");
-
+                shader->symbols->get_variable("gl_ClipDistance");
          assert(clip_distance_var);
          *clip_distance_array_size = clip_distance_var->type->length;
       }
+      if (cull_distance.variable_found()) {
+         ir_variable *cull_distance_var =
+                shader->symbols->get_variable("gl_CullDistance");
+         assert(cull_distance_var);
+         *cull_distance_array_size = cull_distance_var->type->length;
+      }
+      /* From the ARB_cull_distance spec:
+       *
+       * It is a compile-time or link-time error for the set of shaders forming
+       * a program to have the sum of the sizes of the gl_ClipDistance and
+       * gl_CullDistance arrays to be larger than
+       * gl_MaxCombinedClipAndCullDistances.
+       */
+      if ((*clip_distance_array_size + *cull_distance_array_size) >
+          ctx->Const.MaxClipPlanes) {
+          linker_error(prog, "%s shader: the combined size of "
+                       "'gl_ClipDistance' and 'gl_CullDistance' size cannot "
+                       "be larger than "
+                       "gl_MaxCombinedClipAndCullDistances (%u)",
+                       _mesa_shader_stage_to_string(shader->Stage),
+                       ctx->Const.MaxClipPlanes);
+      }
    }
 }
 
@@ -691,13 +736,15 @@ analyze_clip_usage(struct gl_shader_program *prog,
 /**
  * Verify that a vertex shader executable meets all semantic requirements.
  *
- * Also sets prog->Vert.ClipDistanceArraySize as a side effect.
+ * Also sets prog->Vert.ClipDistanceArraySize and
+ * prog->Vert.CullDistanceArraySize as a side effect.
  *
  * \param shader  Vertex shader executable to be verified
  */
 void
 validate_vertex_shader_executable(struct gl_shader_program *prog,
-				  struct gl_shader *shader)
+                                  struct gl_shader *shader,
+                                  struct gl_context *ctx)
 {
    if (shader == NULL)
       return;
@@ -744,17 +791,22 @@ validate_vertex_shader_executable(struct gl_shader_program *prog,
       }
    }
 
-   analyze_clip_usage(prog, shader, &prog->Vert.ClipDistanceArraySize);
+   analyze_clip_cull_usage(prog, shader, ctx,
+                           &prog->Vert.ClipDistanceArraySize,
+                           &prog->Vert.CullDistanceArraySize);
 }
 
 void
 validate_tess_eval_shader_executable(struct gl_shader_program *prog,
-                                     struct gl_shader *shader)
+                                     struct gl_shader *shader,
+                                     struct gl_context *ctx)
 {
    if (shader == NULL)
       return;
 
-   analyze_clip_usage(prog, shader, &prog->TessEval.ClipDistanceArraySize);
+   analyze_clip_cull_usage(prog, shader, ctx,
+                           &prog->TessEval.ClipDistanceArraySize,
+                           &prog->TessEval.CullDistanceArraySize);
 }
 
 
@@ -765,7 +817,7 @@ validate_tess_eval_shader_executable(struct gl_shader_program *prog,
  */
 void
 validate_fragment_shader_executable(struct gl_shader_program *prog,
-				    struct gl_shader *shader)
+                                    struct gl_shader *shader)
 {
    if (shader == NULL)
       return;
@@ -785,14 +837,15 @@ validate_fragment_shader_executable(struct gl_shader_program *prog,
 /**
  * Verify that a geometry shader executable meets all semantic requirements
  *
- * Also sets prog->Geom.VerticesIn, and prog->Geom.ClipDistanceArraySize as
- * a side effect.
+ * Also sets prog->Geom.VerticesIn, and prog->Geom.ClipDistanceArraySize and
+ * prog->Geom.CullDistanceArraySize as a side effect.
  *
  * \param shader Geometry shader executable to be verified
  */
 void
 validate_geometry_shader_executable(struct gl_shader_program *prog,
-				    struct gl_shader *shader)
+                                    struct gl_shader *shader,
+                                    struct gl_context *ctx)
 {
    if (shader == NULL)
       return;
@@ -800,7 +853,9 @@ validate_geometry_shader_executable(struct gl_shader_program *prog,
    unsigned num_vertices = vertices_per_prim(prog->Geom.InputType);
    prog->Geom.VerticesIn = num_vertices;
 
-   analyze_clip_usage(prog, shader, &prog->Geom.ClipDistanceArraySize);
+   analyze_clip_cull_usage(prog, shader, ctx,
+                           &prog->Geom.ClipDistanceArraySize,
+                           &prog->Geom.CullDistanceArraySize);
 }
 
 /**
@@ -4427,16 +4482,16 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
 
          switch (stage) {
          case MESA_SHADER_VERTEX:
-            validate_vertex_shader_executable(prog, sh);
+            validate_vertex_shader_executable(prog, sh, ctx);
             break;
          case MESA_SHADER_TESS_CTRL:
             /* nothing to be done */
             break;
          case MESA_SHADER_TESS_EVAL:
-            validate_tess_eval_shader_executable(prog, sh);
+            validate_tess_eval_shader_executable(prog, sh, ctx);
             break;
          case MESA_SHADER_GEOMETRY:
-            validate_geometry_shader_executable(prog, sh);
+            validate_geometry_shader_executable(prog, sh, ctx);
             break;
          case MESA_SHADER_FRAGMENT:
             validate_fragment_shader_executable(prog, sh);
@@ -4452,14 +4507,19 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
       }
    }
 
-   if (num_shaders[MESA_SHADER_GEOMETRY] > 0)
+   if (num_shaders[MESA_SHADER_GEOMETRY] > 0) {
       prog->LastClipDistanceArraySize = prog->Geom.ClipDistanceArraySize;
-   else if (num_shaders[MESA_SHADER_TESS_EVAL] > 0)
+      prog->LastCullDistanceArraySize = prog->Geom.CullDistanceArraySize;
+   } else if (num_shaders[MESA_SHADER_TESS_EVAL] > 0) {
       prog->LastClipDistanceArraySize = prog->TessEval.ClipDistanceArraySize;
-   else if (num_shaders[MESA_SHADER_VERTEX] > 0)
+      prog->LastCullDistanceArraySize = prog->TessEval.CullDistanceArraySize;
+   } else if (num_shaders[MESA_SHADER_VERTEX] > 0) {
       prog->LastClipDistanceArraySize = prog->Vert.ClipDistanceArraySize;
-   else
+      prog->LastCullDistanceArraySize = prog->Vert.CullDistanceArraySize;
+   } else {
       prog->LastClipDistanceArraySize = 0; /* Not used */
+      prog->LastCullDistanceArraySize = 0; /* Not used */
+   }
 
    /* Here begins the inter-stage linking phase.  Some initial validation is
     * performed, then locations are assigned for uniforms, attributes, and
diff --git a/src/compiler/glsl/standalone_scaffolding.cpp b/src/compiler/glsl/standalone_scaffolding.cpp
index 09d7d6e..4edb767 100644
--- a/src/compiler/glsl/standalone_scaffolding.cpp
+++ b/src/compiler/glsl/standalone_scaffolding.cpp
@@ -152,6 +152,7 @@ void initialize_context_to_defaults(struct gl_context *ctx, gl_api api)
    ctx->Extensions.ARB_texture_query_lod = true;
    ctx->Extensions.ARB_uniform_buffer_object = true;
    ctx->Extensions.ARB_viewport_array = true;
+   ctx->Extensions.ARB_cull_distance = true;
 
    ctx->Extensions.OES_EGL_image_external = true;
    ctx->Extensions.OES_standard_derivatives = true;
diff --git a/src/compiler/glsl/tests/varyings_test.cpp b/src/compiler/glsl/tests/varyings_test.cpp
index 9be5e83..936f495 100644
--- a/src/compiler/glsl/tests/varyings_test.cpp
+++ b/src/compiler/glsl/tests/varyings_test.cpp
@@ -194,6 +194,33 @@ TEST_F(link_varyings, gl_ClipDistance)
    EXPECT_TRUE(is_empty(consumer_interface_inputs));
 }
 
+TEST_F(link_varyings, gl_CullDistance)
+{
+   const glsl_type *const array_8_of_float =
+      glsl_type::get_array_instance(glsl_type::vec(1), 8);
+
+   ir_variable *const culldistance =
+      new(mem_ctx) ir_variable(array_8_of_float,
+                               "gl_CullDistance",
+                               ir_var_shader_in);
+
+   culldistance->data.explicit_location = true;
+   culldistance->data.location = VARYING_SLOT_CULL_DIST0;
+   culldistance->data.explicit_index = 0;
+
+   ir.push_tail(culldistance);
+
+   ASSERT_TRUE(linker::populate_consumer_input_sets(mem_ctx,
+                                                    &ir,
+                                                    consumer_inputs,
+                                                    consumer_interface_inputs,
+                                                    junk));
+
+   EXPECT_EQ(culldistance, junk[VARYING_SLOT_CULL_DIST0]);
+   EXPECT_TRUE(is_empty(consumer_inputs));
+   EXPECT_TRUE(is_empty(consumer_interface_inputs));
+}
+
 TEST_F(link_varyings, single_interface_input)
 {
    ir_variable *const v =
diff --git a/src/compiler/shader_enums.h b/src/compiler/shader_enums.h
index 0c27408..e93345d 100644
--- a/src/compiler/shader_enums.h
+++ b/src/compiler/shader_enums.h
@@ -205,6 +205,8 @@ typedef enum
    VARYING_SLOT_CLIP_VERTEX, /* Does not appear in FS */
    VARYING_SLOT_CLIP_DIST0,
    VARYING_SLOT_CLIP_DIST1,
+   VARYING_SLOT_CULL_DIST0,
+   VARYING_SLOT_CULL_DIST1,
    VARYING_SLOT_PRIMITIVE_ID, /* Does not appear in VS */
    VARYING_SLOT_LAYER, /* Appears as VS or GS output */
    VARYING_SLOT_VIEWPORT, /* Appears as VS or GS output */
@@ -282,6 +284,8 @@ const char *gl_varying_slot_name(gl_varying_slot slot);
 #define VARYING_BIT_CLIP_VERTEX BITFIELD64_BIT(VARYING_SLOT_CLIP_VERTEX)
 #define VARYING_BIT_CLIP_DIST0 BITFIELD64_BIT(VARYING_SLOT_CLIP_DIST0)
 #define VARYING_BIT_CLIP_DIST1 BITFIELD64_BIT(VARYING_SLOT_CLIP_DIST1)
+#define VARYING_BIT_CULL_DIST0 BITFIELD64_BIT(VARYING_SLOT_CULL_DIST0)
+#define VARYING_BIT_CULL_DIST1 BITFIELD64_BIT(VARYING_SLOT_CULL_DIST1)
 #define VARYING_BIT_PRIMITIVE_ID BITFIELD64_BIT(VARYING_SLOT_PRIMITIVE_ID)
 #define VARYING_BIT_LAYER BITFIELD64_BIT(VARYING_SLOT_LAYER)
 #define VARYING_BIT_VIEWPORT BITFIELD64_BIT(VARYING_SLOT_VIEWPORT)
-- 
2.5.5



More information about the mesa-dev mailing list