aboutsummaryrefslogtreecommitdiff
path: root/mesalib/src
diff options
context:
space:
mode:
Diffstat (limited to 'mesalib/src')
-rw-r--r--mesalib/src/Makefile.am4
-rw-r--r--mesalib/src/gallium/auxiliary/util/u_cpu_detect.c29
-rw-r--r--mesalib/src/gallium/auxiliary/util/u_cpu_detect.h1
-rw-r--r--mesalib/src/gallium/auxiliary/util/u_format_srgb.h56
-rw-r--r--mesalib/src/gallium/auxiliary/util/u_format_srgb.py57
-rw-r--r--mesalib/src/gallium/auxiliary/util/u_math.c2
-rw-r--r--mesalib/src/glsl/ast.h58
-rw-r--r--mesalib/src/glsl/ast_array_index.cpp3
-rw-r--r--mesalib/src/glsl/ast_to_hir.cpp362
-rw-r--r--mesalib/src/glsl/ast_type.cpp19
-rw-r--r--mesalib/src/glsl/builtin_variables.cpp13
-rw-r--r--mesalib/src/glsl/glsl_parser.yy90
-rw-r--r--mesalib/src/glsl/glsl_parser_extras.cpp35
-rw-r--r--mesalib/src/glsl/glsl_parser_extras.h27
-rw-r--r--mesalib/src/glsl/glsl_types.cpp55
-rw-r--r--mesalib/src/glsl/glsl_types.h12
-rw-r--r--mesalib/src/glsl/ir.cpp21
-rw-r--r--mesalib/src/glsl/ir.h56
-rw-r--r--mesalib/src/glsl/ir_builder.cpp48
-rw-r--r--mesalib/src/glsl/ir_builder.h8
-rw-r--r--mesalib/src/glsl/ir_hierarchical_visitor.cpp18
-rw-r--r--mesalib/src/glsl/ir_hierarchical_visitor.h2
-rw-r--r--mesalib/src/glsl/ir_hv_accept.cpp13
-rw-r--r--mesalib/src/glsl/ir_optimization.h4
-rw-r--r--mesalib/src/glsl/ir_print_visitor.cpp12
-rw-r--r--mesalib/src/glsl/ir_print_visitor.h2
-rw-r--r--mesalib/src/glsl/ir_reader.cpp30
-rw-r--r--mesalib/src/glsl/ir_set_program_inouts.cpp202
-rw-r--r--mesalib/src/glsl/ir_visitor.h4
-rw-r--r--mesalib/src/glsl/link_varyings.cpp23
-rw-r--r--mesalib/src/glsl/link_varyings.h3
-rw-r--r--mesalib/src/glsl/linker.cpp312
-rw-r--r--mesalib/src/glsl/linker.h3
-rw-r--r--mesalib/src/glsl/lower_output_reads.cpp13
-rw-r--r--mesalib/src/glsl/lower_packed_varyings.cpp291
-rw-r--r--mesalib/src/glsl/opt_dead_builtin_varyings.cpp27
-rw-r--r--mesalib/src/glsl/opt_dead_code_local.cpp17
-rw-r--r--mesalib/src/mapi/glapi/gen/EXT_framebuffer_object.xml4
-rw-r--r--mesalib/src/mesa/drivers/common/meta.c38
-rw-r--r--mesalib/src/mesa/drivers/dri/common/dri_util.c4
-rw-r--r--mesalib/src/mesa/drivers/dri/common/xmlconfig.c44
-rw-r--r--mesalib/src/mesa/drivers/dri/common/xmlconfig.h4
-rw-r--r--mesalib/src/mesa/main/api_validate.c70
-rw-r--r--mesalib/src/mesa/main/context.h11
-rw-r--r--mesalib/src/mesa/main/fbobject.c187
-rw-r--r--mesalib/src/mesa/main/fbobject.h6
-rw-r--r--mesalib/src/mesa/main/get.c2
-rw-r--r--mesalib/src/mesa/main/lines.c3
-rw-r--r--mesalib/src/mesa/main/mtypes.h80
-rw-r--r--mesalib/src/mesa/main/shaderapi.c48
-rw-r--r--mesalib/src/mesa/main/shaderapi.h5
-rw-r--r--mesalib/src/mesa/main/shared.c3
-rw-r--r--mesalib/src/mesa/main/texobj.c53
-rw-r--r--mesalib/src/mesa/main/texparam.c22
-rw-r--r--mesalib/src/mesa/main/texstate.c18
-rw-r--r--mesalib/src/mesa/main/varray.c20
-rw-r--r--mesalib/src/mesa/main/version.c1
-rw-r--r--mesalib/src/mesa/program/ir_to_mesa.cpp21
-rw-r--r--mesalib/src/mesa/state_tracker/st_glsl_to_tgsi.cpp76
-rw-r--r--mesalib/src/mesa/vbo/vbo_exec_array.c82
60 files changed, 2296 insertions, 438 deletions
diff --git a/mesalib/src/Makefile.am b/mesalib/src/Makefile.am
index b3dc44d6f..76280a0c0 100644
--- a/mesalib/src/Makefile.am
+++ b/mesalib/src/Makefile.am
@@ -29,6 +29,10 @@ if HAVE_DRI_GLX
SUBDIRS += glx
endif
+if HAVE_EGL_PLATFORM_WAYLAND
+SUBDIRS += egl/wayland
+endif
+
if HAVE_GBM
SUBDIRS += gbm
endif
diff --git a/mesalib/src/gallium/auxiliary/util/u_cpu_detect.c b/mesalib/src/gallium/auxiliary/util/u_cpu_detect.c
index 588fc7c72..87ad78095 100644
--- a/mesalib/src/gallium/auxiliary/util/u_cpu_detect.c
+++ b/mesalib/src/gallium/auxiliary/util/u_cpu_detect.c
@@ -230,8 +230,28 @@ static INLINE uint64_t xgetbv(void)
#else
return 0;
#endif
+}
+
+#if defined(PIPE_ARCH_X86)
+static INLINE boolean sse2_has_daz(void)
+{
+ struct {
+ uint32_t pad1[7];
+ uint32_t mxcsr_mask;
+ uint32_t pad2[128-8];
+ } PIPE_ALIGN_VAR(16) fxarea;
+
+ fxarea.mxcsr_mask = 0;
+#if (defined(PIPE_CC_GCC) || defined(PIPE_CC_SUNPRO))
+ __asm __volatile ("fxsave %0" : "+m" (fxarea));
+#elif (defined(PIPE_CC_MSVC) || defined(PIPE_CC_ICL))
+ _fxsave(&fxarea);
+#endif
+ return !!(fxarea.mxcsr_mask & (1 << 6));
}
+#endif
+
#endif /* X86 or X86_64 */
void
@@ -310,6 +330,12 @@ util_cpu_detect(void)
((xgetbv() & 6) == 6); // XMM & YMM
util_cpu_caps.has_f16c = (regs2[2] >> 29) & 1;
util_cpu_caps.has_mmx2 = util_cpu_caps.has_sse; /* SSE cpus supports mmxext too */
+#if defined(PIPE_ARCH_X86_64)
+ util_cpu_caps.has_daz = 1;
+#else
+ util_cpu_caps.has_daz = util_cpu_caps.has_sse3 ||
+ (util_cpu_caps.has_sse2 && sse2_has_daz());
+#endif
cacheline = ((regs2[1] >> 8) & 0xFF) * 8;
if (cacheline > 0)
@@ -368,9 +394,12 @@ util_cpu_detect(void)
debug_printf("util_cpu_caps.has_sse4_1 = %u\n", util_cpu_caps.has_sse4_1);
debug_printf("util_cpu_caps.has_sse4_2 = %u\n", util_cpu_caps.has_sse4_2);
debug_printf("util_cpu_caps.has_avx = %u\n", util_cpu_caps.has_avx);
+ debug_printf("util_cpu_caps.has_f16c = %u\n", util_cpu_caps.has_f16c);
+ debug_printf("util_cpu_caps.has_popcnt = %u\n", util_cpu_caps.has_popcnt);
debug_printf("util_cpu_caps.has_3dnow = %u\n", util_cpu_caps.has_3dnow);
debug_printf("util_cpu_caps.has_3dnow_ext = %u\n", util_cpu_caps.has_3dnow_ext);
debug_printf("util_cpu_caps.has_altivec = %u\n", util_cpu_caps.has_altivec);
+ debug_printf("util_cpu_caps.has_daz = %u\n", util_cpu_caps.has_daz);
}
#endif
diff --git a/mesalib/src/gallium/auxiliary/util/u_cpu_detect.h b/mesalib/src/gallium/auxiliary/util/u_cpu_detect.h
index f9cd6475e..cc3e0ce03 100644
--- a/mesalib/src/gallium/auxiliary/util/u_cpu_detect.h
+++ b/mesalib/src/gallium/auxiliary/util/u_cpu_detect.h
@@ -68,6 +68,7 @@ struct util_cpu_caps {
unsigned has_3dnow:1;
unsigned has_3dnow_ext:1;
unsigned has_altivec:1;
+ unsigned has_daz:1;
};
extern struct util_cpu_caps
diff --git a/mesalib/src/gallium/auxiliary/util/u_format_srgb.h b/mesalib/src/gallium/auxiliary/util/u_format_srgb.h
index 82ed9575d..740a91974 100644
--- a/mesalib/src/gallium/auxiliary/util/u_format_srgb.h
+++ b/mesalib/src/gallium/auxiliary/util/u_format_srgb.h
@@ -39,6 +39,7 @@
#include "pipe/p_compiler.h"
+#include "u_pack_color.h"
#include "u_math.h"
@@ -51,23 +52,58 @@ util_format_srgb_to_linear_8unorm_table[256];
extern const uint8_t
util_format_linear_to_srgb_8unorm_table[256];
+extern const unsigned
+util_format_linear_to_srgb_helper_table[104];
+
/**
* Convert a unclamped linear float to srgb value in the [0,255].
- * XXX this hasn't been tested (render to srgb surface).
- * XXX this needs optimization.
*/
static INLINE uint8_t
util_format_linear_float_to_srgb_8unorm(float x)
{
- if (x >= 1.0f)
- return 255;
- else if (x >= 0.0031308f)
- return float_to_ubyte(1.055f * powf(x, 0.41666f) - 0.055f);
- else if (x > 0.0f)
- return float_to_ubyte(12.92f * x);
- else
- return 0;
+ /* this would be exact but (probably much) slower */
+ if (0) {
+ if (x >= 1.0f)
+ return 255;
+ else if (x >= 0.0031308f)
+ return float_to_ubyte(1.055f * powf(x, 0.41666666f) - 0.055f);
+ else if (x > 0.0f)
+ return float_to_ubyte(12.92f * x);
+ else
+ return 0;
+ }
+ else {
+ /*
+ * This is taken from https://gist.github.com/rygorous/2203834
+ * Use LUT and do linear interpolation.
+ */
+ union fi almostone, minval, f;
+ unsigned tab, bias, scale, t;
+
+ almostone.ui = 0x3f7fffff;
+ minval.ui = (127-13) << 23;
+
+ /*
+ * Clamp to [2^(-13), 1-eps]; these two values map to 0 and 1, respectively.
+ * The tests are carefully written so that NaNs map to 0, same as in the
+ * reference implementation.
+ */
+ if (!(x > minval.f))
+ x = minval.f;
+ if (x > almostone.f)
+ x = almostone.f;
+
+ /* Do the table lookup and unpack bias, scale */
+ f.f = x;
+ tab = util_format_linear_to_srgb_helper_table[(f.ui - minval.ui) >> 20];
+ bias = (tab >> 16) << 9;
+ scale = tab & 0xffff;
+
+ /* Grab next-highest mantissa bits and perform linear interpolation */
+ t = (f.ui >> 12) & 0xff;
+ return (uint8_t) ((bias + scale*t) >> 16);
+ }
}
diff --git a/mesalib/src/gallium/auxiliary/util/u_format_srgb.py b/mesalib/src/gallium/auxiliary/util/u_format_srgb.py
index cd63ae789..c6c02f053 100644
--- a/mesalib/src/gallium/auxiliary/util/u_format_srgb.py
+++ b/mesalib/src/gallium/auxiliary/util/u_format_srgb.py
@@ -40,6 +40,7 @@ CopyRight = '''
import math
+import struct
def srgb_to_linear(x):
@@ -51,10 +52,11 @@ def srgb_to_linear(x):
def linear_to_srgb(x):
if x >= 0.0031308:
- return 1.055 * math.pow(x, 0.41666) - 0.055
+ return 1.055 * math.pow(x, 0.41666666) - 0.055
else:
return 12.92 * x
+
def generate_srgb_tables():
print 'const float'
print 'util_format_srgb_8unorm_to_linear_float_table[256] = {'
@@ -84,6 +86,59 @@ def generate_srgb_tables():
print '};'
print
+# calculate the table interpolation values used in float linear to unorm8 srgb
+ numexp = 13
+ mantissa_msb = 3
+# stepshift is just used to only use every x-th float to make things faster,
+# 5 is largest value which still gives exact same table as 0
+ stepshift = 5
+ nbuckets = numexp << mantissa_msb
+ bucketsize = (1 << (23 - mantissa_msb)) >> stepshift
+ mantshift = 12
+ valtable = []
+ sum_aa = float(bucketsize)
+ sum_ab = 0.0
+ sum_bb = 0.0
+ for i in range(0, bucketsize):
+ j = (i << stepshift) >> mantshift
+ sum_ab += j
+ sum_bb += j*j
+ inv_det = 1.0 / (sum_aa * sum_bb - sum_ab * sum_ab)
+
+ for bucket in range(0, nbuckets):
+ start = ((127 - numexp) << 23) + bucket*(bucketsize << stepshift)
+ sum_a = 0.0
+ sum_b = 0.0
+
+ for i in range(0, bucketsize):
+ j = (i << stepshift) >> mantshift
+ fint = start + (i << stepshift)
+ ffloat = struct.unpack('f', struct.pack('I', fint))[0]
+ val = linear_to_srgb(ffloat) * 255.0 + 0.5
+ sum_a += val
+ sum_b += j*val
+
+ solved_a = inv_det * (sum_bb*sum_a - sum_ab*sum_b)
+ solved_b = inv_det * (sum_aa*sum_b - sum_ab*sum_a)
+
+ scaled_a = solved_a * 65536.0 / 512.0
+ scaled_b = solved_b * 65536.0
+
+ int_a = int(scaled_a + 0.5)
+ int_b = int(scaled_b + 0.5)
+
+ valtable.append((int_a << 16) + int_b)
+
+ print 'const unsigned'
+ print 'util_format_linear_to_srgb_helper_table[104] = {'
+
+ for j in range(0, nbuckets, 4):
+ print ' ',
+ for i in range(j, j + 4):
+ print '0x%08x,' % (valtable[i],),
+ print
+ print '};'
+ print
def main():
print '/* This file is autogenerated by u_format_srgb.py. Do not edit directly. */'
diff --git a/mesalib/src/gallium/auxiliary/util/u_math.c b/mesalib/src/gallium/auxiliary/util/u_math.c
index f3fe392ba..6981ee939 100644
--- a/mesalib/src/gallium/auxiliary/util/u_math.c
+++ b/mesalib/src/gallium/auxiliary/util/u_math.c
@@ -111,7 +111,7 @@ util_fpstate_set_denorms_to_zero(unsigned current_mxcsr)
if (util_cpu_caps.has_sse) {
/* Enable flush to zero mode */
current_mxcsr |= _MM_FLUSH_ZERO_MASK;
- if (util_cpu_caps.has_sse3) {
+ if (util_cpu_caps.has_daz) {
/* Enable denormals are zero mode */
current_mxcsr |= _MM_DENORMALS_ZERO_MASK;
}
diff --git a/mesalib/src/glsl/ast.h b/mesalib/src/glsl/ast.h
index 5f2d5b1e4..2cf86e797 100644
--- a/mesalib/src/glsl/ast.h
+++ b/mesalib/src/glsl/ast.h
@@ -439,6 +439,12 @@ struct ast_type_qualifier {
unsigned column_major:1;
unsigned row_major:1;
/** \} */
+
+ /** \name Layout qualifiers for GLSL 1.50 geometry shaders */
+ /** \{ */
+ unsigned prim_type:1;
+ unsigned max_vertices:1;
+ /** \} */
}
/** \brief Set of flags, accessed by name. */
q;
@@ -465,6 +471,12 @@ struct ast_type_qualifier {
*/
int index;
+ /** Maximum output vertices in GLSL 1.50 geometry shaders. */
+ int max_vertices;
+
+ /** Input or output primitive type in GLSL 1.50 geometry shaders */
+ GLenum prim_type;
+
/**
* Binding specified via GL_ARB_shading_language_420pack's "binding" keyword.
*
@@ -899,12 +911,14 @@ public:
class ast_interface_block : public ast_node {
public:
ast_interface_block(ast_type_qualifier layout,
- const char *instance_name,
- ast_expression *array_size)
+ const char *instance_name,
+ bool is_array,
+ ast_expression *array_size)
: layout(layout), block_name(NULL), instance_name(instance_name),
- array_size(array_size)
+ is_array(is_array), array_size(array_size)
{
- /* empty */
+ if (!is_array)
+ assert(array_size == NULL);
}
virtual ir_rvalue *hir(exec_list *instructions,
@@ -925,16 +939,44 @@ public:
exec_list declarations;
/**
- * Declared array size of the block instance
- *
- * If the block is not declared as an array, this field will be \c NULL.
+ * True if the block is declared as an array
*
* \note
* A block can only be an array if it also has an instance name. If this
- * field is not \c NULL, ::instance_name must also not be \c NULL.
+ * field is true, ::instance_name must also not be \c NULL.
+ */
+ bool is_array;
+
+ /**
+ * Declared array size of the block instance
+ *
+ * If the block is not declared as an array or if the block instance array
+ * is unsized, this field will be \c NULL.
*/
ast_expression *array_size;
};
+
+
+/**
+ * AST node representing a declaration of the input layout for geometry
+ * shaders.
+ */
+class ast_gs_input_layout : public ast_node
+{
+public:
+ ast_gs_input_layout(const struct YYLTYPE &locp, GLenum prim_type)
+ : prim_type(prim_type)
+ {
+ set_location(locp);
+ }
+
+ virtual ir_rvalue *hir(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state);
+
+private:
+ const GLenum prim_type;
+};
+
/*@}*/
extern void
diff --git a/mesalib/src/glsl/ast_array_index.cpp b/mesalib/src/glsl/ast_array_index.cpp
index 4baeb6f9d..51f6b10f3 100644
--- a/mesalib/src/glsl/ast_array_index.cpp
+++ b/mesalib/src/glsl/ast_array_index.cpp
@@ -117,7 +117,8 @@ _mesa_ast_array_index_to_hir(void *mem_ctx,
} else if (const_index == NULL && array->type->is_array()) {
if (array->type->array_size() == 0) {
_mesa_glsl_error(&loc, state, "unsized array index must be constant");
- } else if (array->type->fields.array->is_interface()) {
+ } else if (array->type->fields.array->is_interface()
+ && array->variable_referenced()->mode == ir_var_uniform) {
/* Page 46 in section 4.3.7 of the OpenGL ES 3.00 spec says:
*
* "All indexes used to index a uniform block array must be
diff --git a/mesalib/src/glsl/ast_to_hir.cpp b/mesalib/src/glsl/ast_to_hir.cpp
index 598da92f8..04b16c8aa 100644
--- a/mesalib/src/glsl/ast_to_hir.cpp
+++ b/mesalib/src/glsl/ast_to_hir.cpp
@@ -72,6 +72,8 @@ _mesa_ast_to_hir(exec_list *instructions, struct _mesa_glsl_parse_state *state)
state->toplevel_ir = instructions;
+ state->gs_input_prim_type_specified = false;
+
/* Section 4.2 of the GLSL 1.20 specification states:
* "The built-in functions are scoped in a scope outside the global scope
* users declare global variables in. That is, a shader's global scope,
@@ -1771,12 +1773,6 @@ process_array_type(YYLTYPE *loc, const glsl_type *base, ast_node *array_size,
}
}
}
- } else if (state->es_shader) {
- /* Section 10.17 of the GLSL ES 1.00 specification states that unsized
- * array declarations have been removed from the language.
- */
- _mesa_glsl_error(loc, state, "unsized array declarations are not "
- "allowed in GLSL ES 1.00");
}
const glsl_type *array_type = glsl_type::get_array_instance(base, length);
@@ -1936,6 +1932,8 @@ apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual,
bool ubo_qualifiers_valid,
bool is_parameter)
{
+ STATIC_ASSERT(sizeof(qual->flags.q) <= sizeof(qual->flags.i));
+
if (qual->flags.q.invariant) {
if (var->used) {
_mesa_glsl_error(loc, state,
@@ -1963,6 +1961,21 @@ apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual,
_mesa_glsl_shader_target_name(state->target));
}
+ /* Section 6.1.1 (Function Calling Conventions) of the GLSL 1.10 spec says:
+ *
+ * "However, the const qualifier cannot be used with out or inout."
+ *
+ * The same section of the GLSL 4.40 spec further clarifies this saying:
+ *
+ * "The const qualifier cannot be used with out or inout, or a
+ * compile-time error results."
+ */
+ if (is_parameter && qual->flags.q.constant && qual->flags.q.out) {
+ _mesa_glsl_error(loc, state,
+ "`const' may not be applied to `out' or `inout' "
+ "function parameters");
+ }
+
/* If there is no qualifier that changes the mode of the variable, leave
* the setting alone.
*/
@@ -2055,13 +2068,24 @@ apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual,
else
var->interpolation = INTERP_QUALIFIER_NONE;
- if (var->interpolation != INTERP_QUALIFIER_NONE &&
- !(state->target == vertex_shader && var->mode == ir_var_shader_out) &&
- !(state->target == fragment_shader && var->mode == ir_var_shader_in)) {
- _mesa_glsl_error(loc, state,
- "interpolation qualifier `%s' can only be applied to "
- "vertex shader outputs and fragment shader inputs",
- var->interpolation_string());
+ if (var->interpolation != INTERP_QUALIFIER_NONE) {
+ ir_variable_mode mode = (ir_variable_mode) var->mode;
+
+ if (mode != ir_var_shader_in && mode != ir_var_shader_out) {
+ _mesa_glsl_error(loc, state,
+ "interpolation qualifier `%s' can only be applied to "
+ "shader inputs or outputs.",
+ var->interpolation_string());
+
+ }
+
+ if ((state->target == vertex_shader && mode == ir_var_shader_in) ||
+ (state->target == fragment_shader && mode == ir_var_shader_out)) {
+ _mesa_glsl_error(loc, state,
+ "interpolation qualifier `%s' cannot be applied to "
+ "vertex shader inputs or fragment shader outputs",
+ var->interpolation_string());
+ }
}
var->pixel_center_integer = qual->flags.q.pixel_center_integer;
@@ -2317,7 +2341,8 @@ get_variable_being_redeclared(ir_variable *var, ast_declaration *decl,
earlier->type = var->type;
delete var;
var = NULL;
- } else if (state->ARB_fragment_coord_conventions_enable
+ } else if ((state->ARB_fragment_coord_conventions_enable ||
+ state->is_version(150, 0))
&& strcmp(var->name, "gl_FragCoord") == 0
&& earlier->type == var->type
&& earlier->mode == var->mode) {
@@ -2519,6 +2544,81 @@ process_initializer(ir_variable *var, ast_declaration *decl,
return result;
}
+
+/**
+ * Do additional processing necessary for geometry shader input declarations
+ * (this covers both interface blocks arrays and bare input variables).
+ */
+static void
+handle_geometry_shader_input_decl(struct _mesa_glsl_parse_state *state,
+ YYLTYPE loc, ir_variable *var)
+{
+ unsigned num_vertices = 0;
+ if (state->gs_input_prim_type_specified) {
+ num_vertices = vertices_per_prim(state->gs_input_prim_type);
+ }
+
+ /* Geometry shader input variables must be arrays. Caller should have
+ * reported an error for this.
+ */
+ if (!var->type->is_array()) {
+ assert(state->error);
+
+ /* To avoid cascading failures, short circuit the checks below. */
+ return;
+ }
+
+ if (var->type->length == 0) {
+ /* Section 4.3.8.1 (Input Layout Qualifiers) of the GLSL 1.50 spec says:
+ *
+ * All geometry shader input unsized array declarations will be
+ * sized by an earlier input layout qualifier, when present, as per
+ * the following table.
+ *
+ * Followed by a table mapping each allowed input layout qualifier to
+ * the corresponding input length.
+ */
+ if (num_vertices != 0)
+ var->type = glsl_type::get_array_instance(var->type->fields.array,
+ num_vertices);
+ } else {
+ /* Section 4.3.8.1 (Input Layout Qualifiers) of the GLSL 1.50 spec
+ * includes the following examples of compile-time errors:
+ *
+ * // code sequence within one shader...
+ * in vec4 Color1[]; // size unknown
+ * ...Color1.length()...// illegal, length() unknown
+ * in vec4 Color2[2]; // size is 2
+ * ...Color1.length()...// illegal, Color1 still has no size
+ * in vec4 Color3[3]; // illegal, input sizes are inconsistent
+ * layout(lines) in; // legal, input size is 2, matching
+ * in vec4 Color4[3]; // illegal, contradicts layout
+ * ...
+ *
+ * To detect the case illustrated by Color3, we verify that the size of
+ * an explicitly-sized array matches the size of any previously declared
+ * explicitly-sized array. To detect the case illustrated by Color4, we
+ * verify that the size of an explicitly-sized array is consistent with
+ * any previously declared input layout.
+ */
+ if (num_vertices != 0 && var->type->length != num_vertices) {
+ _mesa_glsl_error(&loc, state,
+ "geometry shader input size contradicts previously"
+ " declared layout (size is %u, but layout requires a"
+ " size of %u)", var->type->length, num_vertices);
+ } else if (state->gs_input_size != 0 &&
+ var->type->length != state->gs_input_size) {
+ _mesa_glsl_error(&loc, state,
+ "geometry shader input sizes are "
+ "inconsistent (size is %u, but a previous "
+ "declaration has size %u)",
+ var->type->length, state->gs_input_size);
+ } else {
+ state->gs_input_size = var->type->length;
+ }
+ }
+}
+
ir_rvalue *
ast_declarator_list::hir(exec_list *instructions,
struct _mesa_glsl_parse_state *state)
@@ -2605,6 +2705,11 @@ ast_declarator_list::hir(exec_list *instructions,
* name of a known structure type. This is both invalid and weird.
* Emit an error.
*
+ * - The program text contained something like 'mediump float;'
+ * when the programmer probably meant 'precision mediump
+ * float;' Emit a warning with a description of what they
+ * probably meant to do.
+ *
* Note that if decl_type is NULL and there is a structure involved,
* there must have been some sort of error with the structure. In this
* case we assume that an error was already generated on this line of
@@ -2613,20 +2718,33 @@ ast_declarator_list::hir(exec_list *instructions,
*/
assert(this->type->specifier->structure == NULL || decl_type != NULL
|| state->error);
- if (this->type->specifier->structure == NULL) {
- if (decl_type != NULL) {
- _mesa_glsl_warning(&loc, state, "empty declaration");
- } else {
- _mesa_glsl_error(&loc, state,
- "invalid type `%s' in empty declaration",
- type_name);
- }
- }
- if (this->type->qualifier.precision != ast_precision_none &&
- this->type->specifier->structure != NULL) {
- _mesa_glsl_error(&loc, state, "precision qualifiers can't be applied "
- "to structures");
+ if (decl_type == NULL) {
+ _mesa_glsl_error(&loc, state,
+ "invalid type `%s' in empty declaration",
+ type_name);
+ } else if (this->type->qualifier.precision != ast_precision_none) {
+ if (this->type->specifier->structure != NULL) {
+ _mesa_glsl_error(&loc, state,
+ "precision qualifiers can't be applied "
+ "to structures");
+ } else {
+ static const char *const precision_names[] = {
+ "highp",
+ "highp",
+ "mediump",
+ "lowp"
+ };
+
+ _mesa_glsl_warning(&loc, state,
+ "empty declaration with precision qualifier, "
+ "to set the default precision, use "
+ "`precision %s %s;'",
+ precision_names[this->type->qualifier.precision],
+ type_name);
+ }
+ } else {
+ _mesa_glsl_warning(&loc, state, "empty declaration");
}
}
@@ -2662,6 +2780,26 @@ ast_declarator_list::hir(exec_list *instructions,
var = new(ctx) ir_variable(var_type, decl->identifier, ir_var_auto);
+ /* The 'varying in' and 'varying out' qualifiers can only be used with
+ * ARB_geometry_shader4 and EXT_geometry_shader4, which we don't support
+ * yet.
+ */
+ if (this->type->qualifier.flags.q.varying) {
+ if (this->type->qualifier.flags.q.in) {
+ _mesa_glsl_error(& loc, state,
+ "`varying in' qualifier in declaration of "
+ "`%s' only valid for geometry shaders using "
+ "ARB_geometry_shader4 or EXT_geometry_shader4",
+ decl->identifier);
+ } else if (this->type->qualifier.flags.q.out) {
+ _mesa_glsl_error(& loc, state,
+ "`varying out' qualifier in declaration of "
+ "`%s' only valid for geometry shaders using "
+ "ARB_geometry_shader4 or EXT_geometry_shader4",
+ decl->identifier);
+ }
+ }
+
/* From page 22 (page 28 of the PDF) of the GLSL 1.10 specification;
*
* "Global variables can only use the qualifiers const,
@@ -2796,7 +2934,22 @@ ast_declarator_list::hir(exec_list *instructions,
"cannot have array type")) {
error_emitted = true;
}
- }
+ } else if (state->target == geometry_shader) {
+ /* From section 4.3.4 (Inputs) of the GLSL 1.50 spec:
+ *
+ * Geometry shader input variables get the per-vertex values
+ * written out by vertex shader output variables of the same
+ * names. Since a geometry shader operates on a set of
+ * vertices, each input varying variable (or input block, see
+ * interface blocks below) needs to be declared as an array.
+ */
+ if (!var->type->is_array()) {
+ _mesa_glsl_error(&loc, state,
+ "geometry shader inputs must be arrays");
+ }
+
+ handle_geometry_shader_input_decl(state, loc, var);
+ }
}
/* Integer fragment inputs must be qualified with 'flat'. In GLSL ES,
@@ -2906,7 +3059,7 @@ ast_declarator_list::hir(exec_list *instructions,
}
break;
default:
- assert(0);
+ break;
}
}
@@ -3015,6 +3168,33 @@ ast_declarator_list::hir(exec_list *instructions,
decl->identifier);
}
+ if (state->es_shader) {
+ const glsl_type *const t = (earlier == NULL)
+ ? var->type : earlier->type;
+
+ if (t->is_array() && t->length == 0)
+ /* Section 10.17 of the GLSL ES 1.00 specification states that
+ * unsized array declarations have been removed from the language.
+ * Arrays that are sized using an initializer are still explicitly
+ * sized. However, GLSL ES 1.00 does not allow array
+ * initializers. That is only allowed in GLSL ES 3.00.
+ *
+ * Section 4.1.9 (Arrays) of the GLSL ES 3.00 spec says:
+ *
+ * "An array type can also be formed without specifying a size
+ * if the definition includes an initializer:
+ *
+ * float x[] = float[2] (1.0, 2.0); // declares an array of size 2
+ * float y[] = float[] (1.0, 2.0, 3.0); // declares an array of size 3
+ *
+ * float a[5];
+ * float b[] = a;"
+ */
+ _mesa_glsl_error(& loc, state,
+ "unsized array declarations are not allowed in "
+ "GLSL ES");
+ }
+
/* If the declaration is not a redeclaration, there are a few additional
* semantic checks that must be applied. In addition, variable that was
* created for the declaration should be added to the IR stream.
@@ -3323,6 +3503,18 @@ ast_function::hir(exec_list *instructions,
"function `%s' return type has qualifiers", name);
}
+ /* Section 6.1 (Function Definitions) of the GLSL 1.20 spec says:
+ *
+ * "Arrays are allowed as arguments and as the return type. In both
+ * cases, the array must be explicitly sized."
+ */
+ if (return_type->is_array() && return_type->length == 0) {
+ YYLTYPE loc = this->get_location();
+ _mesa_glsl_error(& loc, state,
+ "function `%s' return type array must be explicitly "
+ "sized", name);
+ }
+
/* From page 17 (page 23 of the PDF) of the GLSL 1.20 spec:
*
* "[Sampler types] can only be declared as function parameters
@@ -4362,6 +4554,19 @@ ast_interface_block::hir(exec_list *instructions,
*/
assert(declared_variables.is_empty());
+ /* From section 4.3.4 (Inputs) of the GLSL 1.50 spec:
+ *
+ * Geometry shader input variables get the per-vertex values written
+ * out by vertex shader output variables of the same names. Since a
+ * geometry shader operates on a set of vertices, each input varying
+ * variable (or input block, see interface blocks below) needs to be
+ * declared as an array.
+ */
+ if (state->target == geometry_shader && !this->is_array &&
+ var_mode == ir_var_shader_in) {
+ _mesa_glsl_error(&loc, state, "geometry shader inputs must be arrays");
+ }
+
/* Page 39 (page 45 of the PDF) of section 4.3.7 in the GLSL ES 3.00 spec
* says:
*
@@ -4372,7 +4577,34 @@ ast_interface_block::hir(exec_list *instructions,
if (this->instance_name) {
ir_variable *var;
- if (this->array_size != NULL) {
+ if (this->is_array) {
+ /* Section 4.3.7 (Interface Blocks) of the GLSL 1.50 spec says:
+ *
+ * For uniform blocks declared an array, each individual array
+ * element corresponds to a separate buffer object backing one
+ * instance of the block. As the array size indicates the number
+ * of buffer objects needed, uniform block array declarations
+ * must specify an array size.
+ *
+ * And a few paragraphs later:
+ *
+ * Geometry shader input blocks must be declared as arrays and
+ * follow the array declaration and linking rules for all
+ * geometry shader inputs. All other input and output block
+ * arrays must specify an array size.
+ *
+ * The upshot of this is that the only circumstance where an
+ * interface array size *doesn't* need to be specified is on a
+ * geometry shader input.
+ */
+ if (this->array_size == NULL &&
+ (state->target != geometry_shader || !this->layout.flags.q.in)) {
+ _mesa_glsl_error(&loc, state,
+ "only geometry shader inputs may be unsized "
+ "instance block arrays");
+
+ }
+
const glsl_type *block_array_type =
process_array_type(&loc, block_type, this->array_size, state);
@@ -4386,13 +4618,15 @@ ast_interface_block::hir(exec_list *instructions,
}
var->interface_type = block_type;
+ if (state->target == geometry_shader && var_mode == ir_var_shader_in)
+ handle_geometry_shader_input_decl(state, loc, var);
state->symbols->add_variable(var);
instructions->push_tail(var);
} else {
/* In order to have an array size, the block must also be declared with
* an instane name.
*/
- assert(this->array_size == NULL);
+ assert(!this->is_array);
for (unsigned i = 0; i < num_variables; i++) {
ir_variable *var =
@@ -4416,6 +4650,72 @@ ast_interface_block::hir(exec_list *instructions,
return NULL;
}
+
+ir_rvalue *
+ast_gs_input_layout::hir(exec_list *instructions,
+ struct _mesa_glsl_parse_state *state)
+{
+ YYLTYPE loc = this->get_location();
+
+ /* If any geometry input layout declaration preceded this one, make sure it
+ * was consistent with this one.
+ */
+ if (state->gs_input_prim_type_specified &&
+ state->gs_input_prim_type != this->prim_type) {
+ _mesa_glsl_error(&loc, state,
+ "geometry shader input layout does not match"
+ " previous declaration");
+ return NULL;
+ }
+
+ /* If any shader inputs occurred before this declaration and specified an
+ * array size, make sure the size they specified is consistent with the
+ * primitive type.
+ */
+ unsigned num_vertices = vertices_per_prim(this->prim_type);
+ if (state->gs_input_size != 0 && state->gs_input_size != num_vertices) {
+ _mesa_glsl_error(&loc, state,
+ "this geometry shader input layout implies %u vertices"
+ " per primitive, but a previous input is declared"
+ " with size %u", num_vertices, state->gs_input_size);
+ return NULL;
+ }
+
+ state->gs_input_prim_type_specified = true;
+ state->gs_input_prim_type = this->prim_type;
+
+ /* If any shader inputs occurred before this declaration and did not
+ * specify an array size, their size is determined now.
+ */
+ foreach_list (node, instructions) {
+ ir_variable *var = ((ir_instruction *) node)->as_variable();
+ if (var == NULL || var->mode != ir_var_shader_in)
+ continue;
+
+ /* Note: gl_PrimitiveIDIn has mode ir_var_shader_in, but it's not an
+ * array; skip it.
+ */
+ if (!var->type->is_array())
+ continue;
+
+ if (var->type->length == 0) {
+ if (var->max_array_access >= num_vertices) {
+ _mesa_glsl_error(&loc, state,
+ "this geometry shader input layout implies %u"
+ " vertices, but an access to element %u of input"
+ " `%s' already exists", num_vertices,
+ var->max_array_access, var->name);
+ } else {
+ var->type = glsl_type::get_array_instance(var->type->fields.array,
+ num_vertices);
+ }
+ }
+ }
+
+ return NULL;
+}
+
+
static void
detect_conflicting_assignments(struct _mesa_glsl_parse_state *state,
exec_list *instructions)
diff --git a/mesalib/src/glsl/ast_type.cpp b/mesalib/src/glsl/ast_type.cpp
index 38c3f8eb0..ce6b6a771 100644
--- a/mesalib/src/glsl/ast_type.cpp
+++ b/mesalib/src/glsl/ast_type.cpp
@@ -133,6 +133,25 @@ ast_type_qualifier::merge_qualifier(YYLTYPE *loc,
return false;
}
+ if (q.flags.q.prim_type) {
+ if (this->flags.q.prim_type && this->prim_type != q.prim_type) {
+ _mesa_glsl_error(loc, state,
+ "conflicting primitive type qualifiers used");
+ return false;
+ }
+ this->prim_type = q.prim_type;
+ }
+
+ if (q.flags.q.max_vertices) {
+ if (this->flags.q.max_vertices && this->max_vertices != q.max_vertices) {
+ _mesa_glsl_error(loc, state,
+ "geometry shader set conflicting max_vertices "
+ "(%d and %d)", this->max_vertices, q.max_vertices);
+ return false;
+ }
+ this->max_vertices = q.max_vertices;
+ }
+
if ((q.flags.i & ubo_mat_mask.flags.i) != 0)
this->flags.i &= ~ubo_mat_mask.flags.i;
if ((q.flags.i & ubo_layout_mask.flags.i) != 0)
diff --git a/mesalib/src/glsl/builtin_variables.cpp b/mesalib/src/glsl/builtin_variables.cpp
index 1e88b6a73..6a808c072 100644
--- a/mesalib/src/glsl/builtin_variables.cpp
+++ b/mesalib/src/glsl/builtin_variables.cpp
@@ -686,8 +686,11 @@ builtin_variable_generator::generate_gs_special_vars()
* the specific case of gl_PrimitiveIDIn. So we don't need to treat
* gl_PrimitiveIDIn as an {ARB,EXT}_geometry_shader4-only variable.
*/
- add_input(VARYING_SLOT_PRIMITIVE_ID, int_t, "gl_PrimitiveIDIn");
- add_output(VARYING_SLOT_PRIMITIVE_ID, int_t, "gl_PrimitiveID");
+ ir_variable *var;
+ var = add_input(VARYING_SLOT_PRIMITIVE_ID, int_t, "gl_PrimitiveIDIn");
+ var->interpolation = INTERP_QUALIFIER_FLAT;
+ var = add_output(VARYING_SLOT_PRIMITIVE_ID, int_t, "gl_PrimitiveID");
+ var->interpolation = INTERP_QUALIFIER_FLAT;
}
@@ -702,6 +705,12 @@ builtin_variable_generator::generate_fs_special_vars()
if (state->is_version(120, 100))
add_input(VARYING_SLOT_PNTC, vec2_t, "gl_PointCoord");
+ if (state->is_version(150, 0)) {
+ ir_variable *var =
+ add_input(VARYING_SLOT_PRIMITIVE_ID, int_t, "gl_PrimitiveID");
+ var->interpolation = INTERP_QUALIFIER_FLAT;
+ }
+
/* gl_FragColor and gl_FragData were deprecated starting in desktop GLSL
* 1.30, and were relegated to the compatibility profile in GLSL 4.20.
* They were removed from GLSL ES 3.00.
diff --git a/mesalib/src/glsl/glsl_parser.yy b/mesalib/src/glsl/glsl_parser.yy
index fcc5620cd..e3a57ea02 100644
--- a/mesalib/src/glsl/glsl_parser.yy
+++ b/mesalib/src/glsl/glsl_parser.yy
@@ -254,6 +254,7 @@ _mesa_glsl_lex(YYSTYPE *val, YYLTYPE *loc, _mesa_glsl_parse_state *state)
%type <node> for_init_statement
%type <for_rest_statement> for_rest_statement
%type <n> integer_constant
+%type <node> layout_defaults
%right THEN ELSE
%%
@@ -1157,7 +1158,8 @@ layout_qualifier_id:
memset(& $$, 0, sizeof($$));
/* Layout qualifiers for ARB_fragment_coord_conventions. */
- if (!$$.flags.i && state->ARB_fragment_coord_conventions_enable) {
+ if (!$$.flags.i && (state->ARB_fragment_coord_conventions_enable ||
+ state->is_version(150, 0))) {
if (strcmp($1, "origin_upper_left") == 0) {
$$.flags.q.origin_upper_left = 1;
} else if (strcmp($1, "pixel_center_integer") == 0) {
@@ -1222,6 +1224,34 @@ layout_qualifier_id:
}
}
+ /* Layout qualifiers for GLSL 1.50 geometry shaders. */
+ if (!$$.flags.i) {
+ struct {
+ const char *s;
+ GLenum e;
+ } map[] = {
+ { "points", GL_POINTS },
+ { "lines", GL_LINES },
+ { "lines_adjacency", GL_LINES_ADJACENCY },
+ { "line_strip", GL_LINE_STRIP },
+ { "triangles", GL_TRIANGLES },
+ { "triangles_adjacency", GL_TRIANGLES_ADJACENCY },
+ { "triangle_strip", GL_TRIANGLE_STRIP },
+ };
+ for (unsigned i = 0; i < Elements(map); i++) {
+ if (strcmp($1, map[i].s) == 0) {
+ $$.flags.q.prim_type = 1;
+ $$.prim_type = map[i].e;
+ break;
+ }
+ }
+
+ if ($$.flags.i && !state->is_version(150, 0)) {
+ _mesa_glsl_error(& @1, state, "#version 150 layout "
+ "qualifier `%s' used", $1);
+ }
+ }
+
if (!$$.flags.i) {
_mesa_glsl_error(& @1, state, "unrecognized layout identifier "
"`%s'", $1);
@@ -1264,6 +1294,23 @@ layout_qualifier_id:
$$.binding = $3;
}
+ if (strcmp("max_vertices", $1) == 0) {
+ $$.flags.q.max_vertices = 1;
+
+ if ($3 < 0) {
+ _mesa_glsl_error(& @3, state,
+ "invalid max_vertices %d specified", $3);
+ YYERROR;
+ } else {
+ $$.max_vertices = $3;
+ if (!state->is_version(150, 0)) {
+ _mesa_glsl_error(& @3, state,
+ "#version 150 max_vertices qualifier "
+ "specified", $3);
+ }
+ }
+ }
+
/* If the identifier didn't match any known layout identifiers,
* emit an error.
*/
@@ -2046,7 +2093,7 @@ external_declaration:
function_definition { $$ = $1; }
| declaration { $$ = $1; }
| pragma_statement { $$ = NULL; }
- | layout_defaults { $$ = NULL; }
+ | layout_defaults { $$ = $1; }
;
function_definition:
@@ -2197,25 +2244,22 @@ instance_name_opt:
/* empty */
{
$$ = new(state) ast_interface_block(*state->default_uniform_qualifier,
- NULL, NULL);
+ NULL, false, NULL);
}
| NEW_IDENTIFIER
{
$$ = new(state) ast_interface_block(*state->default_uniform_qualifier,
- $1, NULL);
+ $1, false, NULL);
}
| NEW_IDENTIFIER '[' constant_expression ']'
{
$$ = new(state) ast_interface_block(*state->default_uniform_qualifier,
- $1, $3);
+ $1, true, $3);
}
| NEW_IDENTIFIER '[' ']'
{
- _mesa_glsl_error(& @1, state,
- "instance block arrays must be explicitly sized");
-
$$ = new(state) ast_interface_block(*state->default_uniform_qualifier,
- $1, NULL);
+ $1, true, NULL);
}
;
@@ -2263,4 +2307,32 @@ layout_defaults:
if (!state->default_uniform_qualifier->merge_qualifier(& @1, state, $1)) {
YYERROR;
}
+ $$ = NULL;
+ }
+
+ | layout_qualifier IN_TOK ';'
+ {
+ void *ctx = state;
+ if (state->target != geometry_shader) {
+ _mesa_glsl_error(& @1, state,
+ "input layout qualifiers only valid in "
+ "geometry shaders");
+ } else if (!$1.flags.q.prim_type) {
+ _mesa_glsl_error(& @1, state,
+ "input layout qualifiers must specify a primitive"
+ " type");
+ }
+ $$ = new(ctx) ast_gs_input_layout(@1, $1.prim_type);
+ }
+
+ | layout_qualifier OUT_TOK ';'
+ {
+ if (state->target != geometry_shader) {
+ _mesa_glsl_error(& @1, state,
+ "out layout qualifiers only valid in "
+ "geometry shaders");
+ } else if (!state->out_qualifier->merge_qualifier(& @1, state, $1)) {
+ YYERROR;
+ }
+ $$ = NULL;
}
diff --git a/mesalib/src/glsl/glsl_parser_extras.cpp b/mesalib/src/glsl/glsl_parser_extras.cpp
index a5bc20c23..88f048365 100644
--- a/mesalib/src/glsl/glsl_parser_extras.cpp
+++ b/mesalib/src/glsl/glsl_parser_extras.cpp
@@ -159,6 +159,10 @@ _mesa_glsl_parse_state::_mesa_glsl_parse_state(struct gl_context *_ctx,
this->default_uniform_qualifier = new(this) ast_type_qualifier();
this->default_uniform_qualifier->flags.q.shared = 1;
this->default_uniform_qualifier->flags.q.column_major = 1;
+
+ this->gs_input_prim_type_specified = false;
+ this->gs_input_prim_type = GL_POINTS;
+ this->out_qualifier = new(this) ast_type_qualifier();
}
/**
@@ -1410,6 +1414,34 @@ ast_struct_specifier::ast_struct_specifier(const char *identifier,
is_declaration = true;
}
+static void
+set_shader_inout_layout(struct gl_shader *shader,
+ struct _mesa_glsl_parse_state *state)
+{
+ if (shader->Type != GL_GEOMETRY_SHADER) {
+ /* Should have been prevented by the parser. */
+ assert(!state->gs_input_prim_type_specified);
+ assert(!state->out_qualifier->flags.i);
+ return;
+ }
+
+ shader->Geom.VerticesOut = 0;
+ if (state->out_qualifier->flags.q.max_vertices)
+ shader->Geom.VerticesOut = state->out_qualifier->max_vertices;
+
+ if (state->gs_input_prim_type_specified) {
+ shader->Geom.InputType = state->gs_input_prim_type;
+ } else {
+ shader->Geom.InputType = PRIM_UNKNOWN;
+ }
+
+ if (state->out_qualifier->flags.q.prim_type) {
+ shader->Geom.OutputType = state->out_qualifier->prim_type;
+ } else {
+ shader->Geom.OutputType = PRIM_UNKNOWN;
+ }
+}
+
extern "C" {
void
@@ -1485,6 +1517,9 @@ _mesa_glsl_compile_shader(struct gl_context *ctx, struct gl_shader *shader,
shader->UniformBlocks = state->uniform_blocks;
ralloc_steal(shader, shader->UniformBlocks);
+ if (!state->error)
+ set_shader_inout_layout(shader, state);
+
/* Retain any live IR, but trash the rest. */
reparent_ir(shader->ir, shader->ir);
diff --git a/mesalib/src/glsl/glsl_parser_extras.h b/mesalib/src/glsl/glsl_parser_extras.h
index 45f5246f7..7e5a77fa6 100644
--- a/mesalib/src/glsl/glsl_parser_extras.h
+++ b/mesalib/src/glsl/glsl_parser_extras.h
@@ -170,6 +170,24 @@ struct _mesa_glsl_parse_state {
struct ast_type_qualifier *default_uniform_qualifier;
/**
+ * True if a geometry shader input primitive type was specified using a
+ * layout directive.
+ *
+ * Note: this value is computed at ast_to_hir time rather than at parse
+ * time.
+ */
+ bool gs_input_prim_type_specified;
+
+ /**
+ * If gs_input_prim_type_specified is true, the primitive type that was
+ * specified. Otherwise ignored.
+ */
+ GLenum gs_input_prim_type;
+
+ /** Output layout qualifiers from GLSL 1.50. (geometry shader controls)*/
+ struct ast_type_qualifier *out_qualifier;
+
+ /**
* Printable list of GLSL versions supported by the current context
*
* \note
@@ -302,6 +320,15 @@ struct _mesa_glsl_parse_state {
/** Shaders containing built-in functions that are used for linking. */
struct gl_shader *builtins_to_link[16];
unsigned num_builtins_to_link;
+
+ /**
+ * For geometry shaders, size of the most recently seen input declaration
+ * that was a sized array, or 0 if no sized input array declarations have
+ * been seen.
+ *
+ * Unused for other shader types.
+ */
+ unsigned gs_input_size;
};
# define YYLLOC_DEFAULT(Current, Rhs, N) \
diff --git a/mesalib/src/glsl/glsl_types.cpp b/mesalib/src/glsl/glsl_types.cpp
index 8324b8ade..0c7e8eb11 100644
--- a/mesalib/src/glsl/glsl_types.cpp
+++ b/mesalib/src/glsl/glsl_types.cpp
@@ -828,3 +828,58 @@ glsl_type::std140_size(bool row_major) const
assert(!"not reached");
return -1;
}
+
+
+unsigned
+glsl_type::count_attribute_slots() const
+{
+ /* From page 31 (page 37 of the PDF) of the GLSL 1.50 spec:
+ *
+ * "A scalar input counts the same amount against this limit as a vec4,
+ * so applications may want to consider packing groups of four
+ * unrelated float inputs together into a vector to better utilize the
+ * capabilities of the underlying hardware. A matrix input will use up
+ * multiple locations. The number of locations used will equal the
+ * number of columns in the matrix."
+ *
+ * The spec does not explicitly say how arrays are counted. However, it
+ * should be safe to assume the total number of slots consumed by an array
+ * is the number of entries in the array multiplied by the number of slots
+ * consumed by a single element of the array.
+ *
+ * The spec says nothing about how structs are counted, because vertex
+ * attributes are not allowed to be (or contain) structs. However, Mesa
+ * allows varying structs, the number of varying slots taken up by a
+ * varying struct is simply equal to the sum of the number of slots taken
+ * up by each element.
+ */
+ switch (this->base_type) {
+ case GLSL_TYPE_UINT:
+ case GLSL_TYPE_INT:
+ case GLSL_TYPE_FLOAT:
+ case GLSL_TYPE_BOOL:
+ return this->matrix_columns;
+
+ case GLSL_TYPE_STRUCT:
+ case GLSL_TYPE_INTERFACE: {
+ unsigned size = 0;
+
+ for (unsigned i = 0; i < this->length; i++)
+ size += this->fields.structure[i].type->count_attribute_slots();
+
+ return size;
+ }
+
+ case GLSL_TYPE_ARRAY:
+ return this->length * this->fields.array->count_attribute_slots();
+
+ case GLSL_TYPE_SAMPLER:
+ case GLSL_TYPE_VOID:
+ case GLSL_TYPE_ERROR:
+ break;
+ }
+
+ assert(!"Unexpected type in count_attribute_slots()");
+
+ return 0;
+}
diff --git a/mesalib/src/glsl/glsl_types.h b/mesalib/src/glsl/glsl_types.h
index 8172309a7..647867a23 100644
--- a/mesalib/src/glsl/glsl_types.h
+++ b/mesalib/src/glsl/glsl_types.h
@@ -253,6 +253,18 @@ struct glsl_type {
unsigned component_slots() const;
/**
+ * Calculate the number of attribute slots required to hold this type
+ *
+ * This implements the language rules of GLSL 1.50 for counting the number
+ * of slots used by a vertex attribute. It also determines the number of
+ * varying slots the type will use up in the absence of varying packing
+ * (and thus, it can be used to measure the number of varying slots used by
+ * the varyings that are generated by lower_packed_varyings).
+ */
+ unsigned count_attribute_slots() const;
+
+
+ /**
* Alignment in bytes of the start of this type in a std140 uniform
* block.
*/
diff --git a/mesalib/src/glsl/ir.cpp b/mesalib/src/glsl/ir.cpp
index dad58deeb..99dceacf8 100644
--- a/mesalib/src/glsl/ir.cpp
+++ b/mesalib/src/glsl/ir.cpp
@@ -1778,3 +1778,24 @@ ir_rvalue::as_rvalue_to_saturate()
return NULL;
}
+
+
+unsigned
+vertices_per_prim(GLenum prim)
+{
+ switch (prim) {
+ case GL_POINTS:
+ return 1;
+ case GL_LINES:
+ return 2;
+ case GL_TRIANGLES:
+ return 3;
+ case GL_LINES_ADJACENCY:
+ return 4;
+ case GL_TRIANGLES_ADJACENCY:
+ return 6;
+ default:
+ assert(!"Bad primitive");
+ return 3;
+ }
+}
diff --git a/mesalib/src/glsl/ir.h b/mesalib/src/glsl/ir.h
index 7ac291cf4..62e3b27ca 100644
--- a/mesalib/src/glsl/ir.h
+++ b/mesalib/src/glsl/ir.h
@@ -81,6 +81,8 @@ enum ir_node_type {
ir_type_return,
ir_type_swizzle,
ir_type_texture,
+ ir_type_emit_vertex,
+ ir_type_end_primitive,
ir_type_max /**< maximum ir_type enum number, for validation */
};
@@ -519,6 +521,8 @@ public:
*
* - Vertex shader input: one of the values from \c gl_vert_attrib.
* - Vertex shader output: one of the values from \c gl_varying_slot.
+ * - Geometry shader input: one of the values from \c gl_varying_slot.
+ * - Geometry shader output: one of the values from \c gl_varying_slot.
* - Fragment shader input: one of the values from \c gl_varying_slot.
* - Fragment shader output: one of the values from \c gl_frag_result.
* - Uniforms: Per-stage uniform slot number for default uniform block.
@@ -1992,6 +1996,53 @@ private:
/*@}*/
/**
+ * IR instruction to emit a vertex in a geometry shader.
+ */
+class ir_emit_vertex : public ir_instruction {
+public:
+ ir_emit_vertex()
+ {
+ ir_type = ir_type_emit_vertex;
+ }
+
+ virtual void accept(ir_visitor *v)
+ {
+ v->visit(this);
+ }
+
+ virtual ir_emit_vertex *clone(void *mem_ctx, struct hash_table *) const
+ {
+ return new(mem_ctx) ir_emit_vertex();
+ }
+
+ virtual ir_visitor_status accept(ir_hierarchical_visitor *);
+};
+
+/**
+ * IR instruction to complete the current primitive and start a new one in a
+ * geometry shader.
+ */
+class ir_end_primitive : public ir_instruction {
+public:
+ ir_end_primitive()
+ {
+ ir_type = ir_type_end_primitive;
+ }
+
+ virtual void accept(ir_visitor *v)
+ {
+ v->visit(this);
+ }
+
+ virtual ir_end_primitive *clone(void *mem_ctx, struct hash_table *) const
+ {
+ return new(mem_ctx) ir_end_primitive();
+ }
+
+ virtual ir_visitor_status accept(ir_hierarchical_visitor *);
+};
+
+/**
* Apply a visitor to each IR node in a list
*/
void
@@ -2061,7 +2112,7 @@ ir_has_call(ir_instruction *ir);
extern void
do_set_program_inouts(exec_list *instructions, struct gl_program *prog,
- bool is_fragment_shader);
+ GLenum shader_type);
extern char *
prototype_string(const glsl_type *return_type, const char *name,
@@ -2077,4 +2128,7 @@ extern void _mesa_print_ir(struct exec_list *instructions,
} /* extern "C" */
#endif
+unsigned
+vertices_per_prim(GLenum prim);
+
#endif /* IR_H */
diff --git a/mesalib/src/glsl/ir_builder.cpp b/mesalib/src/glsl/ir_builder.cpp
index 8fb30a02a..7d9cf5e47 100644
--- a/mesalib/src/glsl/ir_builder.cpp
+++ b/mesalib/src/glsl/ir_builder.cpp
@@ -219,6 +219,12 @@ saturate(operand a)
new(mem_ctx) ir_constant(0.0f));
}
+ir_expression *
+abs(operand a)
+{
+ return expr(ir_unop_abs, a);
+}
+
ir_expression*
equal(operand a, operand b)
{
@@ -226,6 +232,12 @@ equal(operand a, operand b)
}
ir_expression*
+nequal(operand a, operand b)
+{
+ return expr(ir_binop_nequal, a, b);
+}
+
+ir_expression*
less(operand a, operand b)
{
return expr(ir_binop_less, a, b);
@@ -304,12 +316,24 @@ f2i(operand a)
}
ir_expression*
+bitcast_f2i(operand a)
+{
+ return expr(ir_unop_bitcast_f2i, a);
+}
+
+ir_expression*
i2f(operand a)
{
return expr(ir_unop_i2f, a);
}
ir_expression*
+bitcast_i2f(operand a)
+{
+ return expr(ir_unop_bitcast_i2f, a);
+}
+
+ir_expression*
i2u(operand a)
{
return expr(ir_unop_i2u, a);
@@ -328,11 +352,35 @@ f2u(operand a)
}
ir_expression*
+bitcast_f2u(operand a)
+{
+ return expr(ir_unop_bitcast_f2u, a);
+}
+
+ir_expression*
u2f(operand a)
{
return expr(ir_unop_u2f, a);
}
+ir_expression*
+bitcast_u2f(operand a)
+{
+ return expr(ir_unop_bitcast_u2f, a);
+}
+
+ir_expression*
+i2b(operand a)
+{
+ return expr(ir_unop_i2b, a);
+}
+
+ir_expression*
+b2i(operand a)
+{
+ return expr(ir_unop_b2i, a);
+}
+
ir_if*
if_tree(operand condition,
ir_instruction *then_branch)
diff --git a/mesalib/src/glsl/ir_builder.h b/mesalib/src/glsl/ir_builder.h
index 690ac74eb..7049476a1 100644
--- a/mesalib/src/glsl/ir_builder.h
+++ b/mesalib/src/glsl/ir_builder.h
@@ -133,8 +133,10 @@ ir_expression *round_even(operand a);
ir_expression *dot(operand a, operand b);
ir_expression *clamp(operand a, operand b, operand c);
ir_expression *saturate(operand a);
+ir_expression *abs(operand a);
ir_expression *equal(operand a, operand b);
+ir_expression *nequal(operand a, operand b);
ir_expression *less(operand a, operand b);
ir_expression *greater(operand a, operand b);
ir_expression *lequal(operand a, operand b);
@@ -151,11 +153,17 @@ ir_expression *lshift(operand a, operand b);
ir_expression *rshift(operand a, operand b);
ir_expression *f2i(operand a);
+ir_expression *bitcast_f2i(operand a);
ir_expression *i2f(operand a);
+ir_expression *bitcast_i2f(operand a);
ir_expression *f2u(operand a);
+ir_expression *bitcast_f2u(operand a);
ir_expression *u2f(operand a);
+ir_expression *bitcast_u2f(operand a);
ir_expression *i2u(operand a);
ir_expression *u2i(operand a);
+ir_expression *b2i(operand a);
+ir_expression *i2b(operand a);
/**
* Swizzle away later components, but preserve the ordering.
diff --git a/mesalib/src/glsl/ir_hierarchical_visitor.cpp b/mesalib/src/glsl/ir_hierarchical_visitor.cpp
index f24414046..2e606dda4 100644
--- a/mesalib/src/glsl/ir_hierarchical_visitor.cpp
+++ b/mesalib/src/glsl/ir_hierarchical_visitor.cpp
@@ -69,6 +69,24 @@ ir_hierarchical_visitor::visit(ir_loop_jump *ir)
}
ir_visitor_status
+ir_hierarchical_visitor::visit(ir_emit_vertex *ir)
+{
+ if (this->callback != NULL)
+ this->callback(ir, this->data);
+
+ return visit_continue;
+}
+
+ir_visitor_status
+ir_hierarchical_visitor::visit(ir_end_primitive *ir)
+{
+ if (this->callback != NULL)
+ this->callback(ir, this->data);
+
+ return visit_continue;
+}
+
+ir_visitor_status
ir_hierarchical_visitor::visit(ir_dereference_variable *ir)
{
if (this->callback != NULL)
diff --git a/mesalib/src/glsl/ir_hierarchical_visitor.h b/mesalib/src/glsl/ir_hierarchical_visitor.h
index 1988ad091..647d2e002 100644
--- a/mesalib/src/glsl/ir_hierarchical_visitor.h
+++ b/mesalib/src/glsl/ir_hierarchical_visitor.h
@@ -87,6 +87,8 @@ public:
virtual ir_visitor_status visit(class ir_variable *);
virtual ir_visitor_status visit(class ir_constant *);
virtual ir_visitor_status visit(class ir_loop_jump *);
+ virtual ir_visitor_status visit(class ir_emit_vertex *);
+ virtual ir_visitor_status visit(class ir_end_primitive *);
/**
* ir_dereference_variable isn't technically a leaf, but it is treated as a
diff --git a/mesalib/src/glsl/ir_hv_accept.cpp b/mesalib/src/glsl/ir_hv_accept.cpp
index 559b71af3..76a607d17 100644
--- a/mesalib/src/glsl/ir_hv_accept.cpp
+++ b/mesalib/src/glsl/ir_hv_accept.cpp
@@ -415,3 +415,16 @@ ir_if::accept(ir_hierarchical_visitor *v)
return v->visit_leave(this);
}
+
+ir_visitor_status
+ir_emit_vertex::accept(ir_hierarchical_visitor *v)
+{
+ return v->visit(this);
+}
+
+
+ir_visitor_status
+ir_end_primitive::accept(ir_hierarchical_visitor *v)
+{
+ return v->visit(this);
+}
diff --git a/mesalib/src/glsl/ir_optimization.h b/mesalib/src/glsl/ir_optimization.h
index 2c1479ff4..b79c2b787 100644
--- a/mesalib/src/glsl/ir_optimization.h
+++ b/mesalib/src/glsl/ir_optimization.h
@@ -77,7 +77,7 @@ bool do_copy_propagation(exec_list *instructions);
bool do_copy_propagation_elements(exec_list *instructions);
bool do_constant_propagation(exec_list *instructions);
void do_dead_builtin_varyings(struct gl_context *ctx,
- exec_list *producer, exec_list *consumer,
+ gl_shader *producer, gl_shader *consumer,
unsigned num_tfeedback_decls,
class tfeedback_decl *tfeedback_decls);
bool do_dead_code(exec_list *instructions, bool uniform_locations_assigned);
@@ -112,7 +112,7 @@ bool lower_packing_builtins(exec_list *instructions, int op_mask);
void lower_ubo_reference(struct gl_shader *shader, exec_list *instructions);
void lower_packed_varyings(void *mem_ctx, unsigned location_base,
unsigned locations_used, ir_variable_mode mode,
- gl_shader *shader);
+ unsigned gs_input_vertices, gl_shader *shader);
bool lower_vector_insert(exec_list *instructions, bool lower_nonconstant_index);
void lower_named_interface_blocks(void *mem_ctx, gl_shader *shader);
bool optimize_redundant_jumps(exec_list *instructions);
diff --git a/mesalib/src/glsl/ir_print_visitor.cpp b/mesalib/src/glsl/ir_print_visitor.cpp
index ca973a5f3..541231a33 100644
--- a/mesalib/src/glsl/ir_print_visitor.cpp
+++ b/mesalib/src/glsl/ir_print_visitor.cpp
@@ -539,3 +539,15 @@ ir_print_visitor::visit(ir_loop_jump *ir)
{
printf("%s", ir->is_break() ? "break" : "continue");
}
+
+void
+ir_print_visitor::visit(ir_emit_vertex *ir)
+{
+ printf("(emit-vertex)");
+}
+
+void
+ir_print_visitor::visit(ir_end_primitive *ir)
+{
+ printf("(end-primitive)");
+}
diff --git a/mesalib/src/glsl/ir_print_visitor.h b/mesalib/src/glsl/ir_print_visitor.h
index a84056d16..865376fe0 100644
--- a/mesalib/src/glsl/ir_print_visitor.h
+++ b/mesalib/src/glsl/ir_print_visitor.h
@@ -69,6 +69,8 @@ public:
virtual void visit(ir_if *);
virtual void visit(ir_loop *);
virtual void visit(ir_loop_jump *);
+ virtual void visit(ir_emit_vertex *);
+ virtual void visit(ir_end_primitive *);
/*@}*/
private:
diff --git a/mesalib/src/glsl/ir_reader.cpp b/mesalib/src/glsl/ir_reader.cpp
index 51534ca7c..f263fe810 100644
--- a/mesalib/src/glsl/ir_reader.cpp
+++ b/mesalib/src/glsl/ir_reader.cpp
@@ -59,6 +59,8 @@ private:
ir_swizzle *read_swizzle(s_expression *);
ir_constant *read_constant(s_expression *);
ir_texture *read_texture(s_expression *);
+ ir_emit_vertex *read_emit_vertex(s_expression *);
+ ir_end_primitive *read_end_primitive(s_expression *);
ir_dereference *read_dereference(s_expression *);
ir_dereference_variable *read_var_ref(s_expression *);
@@ -355,6 +357,10 @@ ir_reader::read_instruction(s_expression *expr, ir_loop *loop_ctx)
inst = read_return(list);
} else if (strcmp(tag->value(), "function") == 0) {
inst = read_function(list, false);
+ } else if (strcmp(tag->value(), "emit-vertex") == 0) {
+ inst = read_emit_vertex(list);
+ } else if (strcmp(tag->value(), "end-primitive") == 0) {
+ inst = read_end_primitive(list);
} else {
inst = read_rvalue(list);
if (inst == NULL)
@@ -1065,3 +1071,27 @@ ir_reader::read_texture(s_expression *expr)
};
return tex;
}
+
+ir_emit_vertex *
+ir_reader::read_emit_vertex(s_expression *expr)
+{
+ s_pattern pat[] = { "emit-vertex" };
+
+ if (MATCH(expr, pat)) {
+ return new(mem_ctx) ir_emit_vertex();
+ }
+ ir_read_error(NULL, "when reading emit-vertex");
+ return NULL;
+}
+
+ir_end_primitive *
+ir_reader::read_end_primitive(s_expression *expr)
+{
+ s_pattern pat[] = { "end-primitive" };
+
+ if (MATCH(expr, pat)) {
+ return new(mem_ctx) ir_end_primitive();
+ }
+ ir_read_error(NULL, "when reading end-primitive");
+ return NULL;
+}
diff --git a/mesalib/src/glsl/ir_set_program_inouts.cpp b/mesalib/src/glsl/ir_set_program_inouts.cpp
index 91a8b4526..6196d6a64 100644
--- a/mesalib/src/glsl/ir_set_program_inouts.cpp
+++ b/mesalib/src/glsl/ir_set_program_inouts.cpp
@@ -44,11 +44,10 @@
class ir_set_program_inouts_visitor : public ir_hierarchical_visitor {
public:
- ir_set_program_inouts_visitor(struct gl_program *prog,
- bool is_fragment_shader)
+ ir_set_program_inouts_visitor(struct gl_program *prog, GLenum shader_type)
{
this->prog = prog;
- this->is_fragment_shader = is_fragment_shader;
+ this->shader_type = shader_type;
}
~ir_set_program_inouts_visitor()
{
@@ -60,8 +59,12 @@ public:
virtual ir_visitor_status visit_enter(ir_discard *);
virtual ir_visitor_status visit(ir_dereference_variable *);
+private:
+ void mark_whole_variable(ir_variable *var);
+ bool try_mark_partial_variable(ir_variable *var, ir_rvalue *index);
+
struct gl_program *prog;
- bool is_fragment_shader;
+ GLenum shader_type;
};
static inline bool
@@ -104,6 +107,23 @@ mark(struct gl_program *prog, ir_variable *var, int offset, int len,
}
}
+/**
+ * Mark an entire variable as used. Caller must ensure that the variable
+ * represents a shader input or output.
+ */
+void
+ir_set_program_inouts_visitor::mark_whole_variable(ir_variable *var)
+{
+ const glsl_type *type = var->type;
+ if (this->shader_type == GL_GEOMETRY_SHADER &&
+ var->mode == ir_var_shader_in && type->is_array()) {
+ type = type->fields.array;
+ }
+
+ mark(this->prog, var, 0, type->count_attribute_slots(),
+ this->shader_type == GL_FRAGMENT_SHADER);
+}
+
/* Default handler: Mark all the locations in the variable as used. */
ir_visitor_status
ir_set_program_inouts_visitor::visit(ir_dereference_variable *ir)
@@ -111,43 +131,154 @@ ir_set_program_inouts_visitor::visit(ir_dereference_variable *ir)
if (!is_shader_inout(ir->var))
return visit_continue;
- if (ir->type->is_array()) {
- mark(this->prog, ir->var, 0,
- ir->type->length * ir->type->fields.array->matrix_columns,
- this->is_fragment_shader);
- } else {
- mark(this->prog, ir->var, 0, ir->type->matrix_columns,
- this->is_fragment_shader);
- }
+ mark_whole_variable(ir->var);
return visit_continue;
}
-ir_visitor_status
-ir_set_program_inouts_visitor::visit_enter(ir_dereference_array *ir)
+/**
+ * Try to mark a portion of the given variable as used. Caller must ensure
+ * that the variable represents a shader input or output which can be indexed
+ * into in array fashion (an array or matrix). For the purpose of geometry
+ * shader inputs (which are always arrays*), this means that the array element
+ * must be something that can be indexed into in array fashion.
+ *
+ * *Except gl_PrimitiveIDIn, as noted below.
+ *
+ * If the index can't be interpreted as a constant, or some other problem
+ * occurs, then nothing will be marked and false will be returned.
+ */
+bool
+ir_set_program_inouts_visitor::try_mark_partial_variable(ir_variable *var,
+ ir_rvalue *index)
{
- ir_dereference_variable *deref_var;
- ir_constant *index = ir->array_index->as_constant();
- deref_var = ir->array->as_dereference_variable();
- ir_variable *var = deref_var ? deref_var->var : NULL;
+ const glsl_type *type = var->type;
- /* Check that we're dereferencing a shader in or out */
- if (!var || !is_shader_inout(var))
- return visit_continue;
+ if (this->shader_type == GL_GEOMETRY_SHADER &&
+ var->mode == ir_var_shader_in) {
+ /* The only geometry shader input that is not an array is
+ * gl_PrimitiveIDIn, and in that case, this code will never be reached,
+ * because gl_PrimitiveIDIn can't be indexed into in array fashion.
+ */
+ assert(type->is_array());
+ type = type->fields.array;
+ }
- if (index) {
- int width = 1;
+ /* The code below only handles:
+ *
+ * - Indexing into matrices
+ * - Indexing into arrays of (matrices, vectors, or scalars)
+ *
+ * All other possibilities are either prohibited by GLSL (vertex inputs and
+ * fragment outputs can't be structs) or should have been eliminated by
+ * lowering passes (do_vec_index_to_swizzle() gets rid of indexing into
+ * vectors, and lower_packed_varyings() gets rid of structs that occur in
+ * varyings).
+ */
+ if (!(type->is_matrix() ||
+ (type->is_array() &&
+ (type->fields.array->is_numeric() ||
+ type->fields.array->is_boolean())))) {
+ assert(!"Unexpected indexing in ir_set_program_inouts");
- if (deref_var->type->is_array() &&
- deref_var->type->fields.array->is_matrix()) {
- width = deref_var->type->fields.array->matrix_columns;
- }
+ /* For safety in release builds, in case we ever encounter unexpected
+ * indexing, give up and let the caller mark the whole variable as used.
+ */
+ return false;
+ }
+
+ ir_constant *index_as_constant = index->as_constant();
+ if (!index_as_constant)
+ return false;
+
+ unsigned elem_width;
+ unsigned num_elems;
+ if (type->is_array()) {
+ num_elems = type->length;
+ if (type->fields.array->is_matrix())
+ elem_width = type->fields.array->matrix_columns;
+ else
+ elem_width = 1;
+ } else {
+ num_elems = type->matrix_columns;
+ elem_width = 1;
+ }
- mark(this->prog, var, index->value.i[0] * width, width,
- this->is_fragment_shader);
- return visit_continue_with_parent;
+ if (index_as_constant->value.u[0] >= num_elems) {
+ /* Constant index outside the bounds of the matrix/array. This could
+ * arise as a result of constant folding of a legal GLSL program.
+ *
+ * Even though the spec says that indexing outside the bounds of a
+ * matrix/array results in undefined behaviour, we don't want to pass
+ * out-of-range values to mark() (since this could result in slots that
+ * don't exist being marked as used), so just let the caller mark the
+ * whole variable as used.
+ */
+ return false;
}
+ mark(this->prog, var, index_as_constant->value.u[0] * elem_width,
+ elem_width, this->shader_type == GL_FRAGMENT_SHADER);
+ return true;
+}
+
+ir_visitor_status
+ir_set_program_inouts_visitor::visit_enter(ir_dereference_array *ir)
+{
+ /* Note: for geometry shader inputs, lower_named_interface_blocks may
+ * create 2D arrays, so we need to be able to handle those. 2D arrays
+ * shouldn't be able to crop up for any other reason.
+ */
+ if (ir_dereference_array * const inner_array =
+ ir->array->as_dereference_array()) {
+ /* ir => foo[i][j]
+ * inner_array => foo[i]
+ */
+ if (ir_dereference_variable * const deref_var =
+ inner_array->array->as_dereference_variable()) {
+ if (this->shader_type == GL_GEOMETRY_SHADER &&
+ deref_var->var->mode == ir_var_shader_in) {
+ /* foo is a geometry shader input, so i is the vertex, and j the
+ * part of the input we're accessing.
+ */
+ if (try_mark_partial_variable(deref_var->var, ir->array_index))
+ {
+ /* We've now taken care of foo and j, but i might contain a
+ * subexpression that accesses shader inputs. So manually
+ * visit i and then continue with the parent.
+ */
+ inner_array->array_index->accept(this);
+ return visit_continue_with_parent;
+ }
+ }
+ }
+ } else if (ir_dereference_variable * const deref_var =
+ ir->array->as_dereference_variable()) {
+ /* ir => foo[i], where foo is a variable. */
+ if (this->shader_type == GL_GEOMETRY_SHADER &&
+ deref_var->var->mode == ir_var_shader_in) {
+ /* foo is a geometry shader input, so i is the vertex, and we're
+ * accessing the entire input.
+ */
+ mark_whole_variable(deref_var->var);
+ /* We've now taken care of foo, but i might contain a subexpression
+ * that accesses shader inputs. So manually visit i and then
+ * continue with the parent.
+ */
+ ir->array_index->accept(this);
+ return visit_continue_with_parent;
+ } else if (is_shader_inout(deref_var->var)) {
+ /* foo is a shader input/output, but not a geometry shader input,
+ * so i is the part of the input we're accessing.
+ */
+ if (try_mark_partial_variable(deref_var->var, ir->array_index))
+ return visit_continue_with_parent;
+ }
+ }
+
+ /* The expression is something we don't recognize. Just visit its
+ * subexpressions.
+ */
return visit_continue;
}
@@ -164,7 +295,8 @@ ir_set_program_inouts_visitor::visit_enter(ir_function_signature *ir)
ir_visitor_status
ir_set_program_inouts_visitor::visit_enter(ir_expression *ir)
{
- if (is_fragment_shader && ir->operation == ir_unop_dFdy) {
+ if (this->shader_type == GL_FRAGMENT_SHADER &&
+ ir->operation == ir_unop_dFdy) {
gl_fragment_program *fprog = (gl_fragment_program *) prog;
fprog->UsesDFdy = true;
}
@@ -175,7 +307,7 @@ ir_visitor_status
ir_set_program_inouts_visitor::visit_enter(ir_discard *)
{
/* discards are only allowed in fragment shaders. */
- assert(is_fragment_shader);
+ assert(this->shader_type == GL_FRAGMENT_SHADER);
gl_fragment_program *fprog = (gl_fragment_program *) prog;
fprog->UsesKill = true;
@@ -185,14 +317,14 @@ ir_set_program_inouts_visitor::visit_enter(ir_discard *)
void
do_set_program_inouts(exec_list *instructions, struct gl_program *prog,
- bool is_fragment_shader)
+ GLenum shader_type)
{
- ir_set_program_inouts_visitor v(prog, is_fragment_shader);
+ ir_set_program_inouts_visitor v(prog, shader_type);
prog->InputsRead = 0;
prog->OutputsWritten = 0;
prog->SystemValuesRead = 0;
- if (is_fragment_shader) {
+ if (shader_type == GL_FRAGMENT_SHADER) {
gl_fragment_program *fprog = (gl_fragment_program *) prog;
memset(fprog->InterpQualifier, 0, sizeof(fprog->InterpQualifier));
fprog->IsCentroid = 0;
diff --git a/mesalib/src/glsl/ir_visitor.h b/mesalib/src/glsl/ir_visitor.h
index bd47ef7d5..40f96ffbc 100644
--- a/mesalib/src/glsl/ir_visitor.h
+++ b/mesalib/src/glsl/ir_visitor.h
@@ -63,6 +63,8 @@ public:
virtual void visit(class ir_if *) = 0;
virtual void visit(class ir_loop *) = 0;
virtual void visit(class ir_loop_jump *) = 0;
+ virtual void visit(class ir_emit_vertex *) = 0;
+ virtual void visit(class ir_end_primitive *) = 0;
/*@}*/
};
@@ -81,6 +83,8 @@ public:
virtual void visit(class ir_assignment *) {}
virtual void visit(class ir_constant *) {}
virtual void visit(class ir_call *) {}
+ virtual void visit(class ir_emit_vertex *) {}
+ virtual void visit(class ir_end_primitive *) {}
};
#endif /* __cplusplus */
diff --git a/mesalib/src/glsl/link_varyings.cpp b/mesalib/src/glsl/link_varyings.cpp
index 2c7e4514e..4ceb1d33e 100644
--- a/mesalib/src/glsl/link_varyings.cpp
+++ b/mesalib/src/glsl/link_varyings.cpp
@@ -68,6 +68,10 @@ cross_validate_outputs_to_inputs(struct gl_shader_program *prog,
/* Find all shader inputs in the "consumer" stage. Any variables that have
* matching outputs already in the symbol table must have the same type and
* qualifiers.
+ *
+ * Exception: if the consumer is the geometry shader, then the inputs
+ * should be arrays and the type of the array element should match the type
+ * of the corresponding producer output.
*/
foreach_list(node, consumer->ir) {
ir_variable *const input = ((ir_instruction *) node)->as_variable();
@@ -79,7 +83,12 @@ cross_validate_outputs_to_inputs(struct gl_shader_program *prog,
if (output != NULL) {
/* Check that the types match between stages.
*/
- if (input->type != output->type) {
+ const glsl_type *type_to_match = input->type;
+ if (consumer->Type == GL_GEOMETRY_SHADER) {
+ assert(type_to_match->is_array()); /* Enforced by ast_to_hir */
+ type_to_match = type_to_match->element_type();
+ }
+ if (type_to_match != output->type) {
/* There is a bit of a special case for gl_TexCoord. This
* built-in is unsized by default. Applications that variable
* access it must redeclare it with a size. There is some
@@ -973,6 +982,9 @@ private:
* each of these objects that matches one of the outputs of the
* producer.
*
+ * \param gs_input_vertices: if \c consumer is a geometry shader, this is the
+ * number of input vertices it accepts. Otherwise zero.
+ *
* When num_tfeedback_decls is nonzero, it is permissible for the consumer to
* be NULL. In this case, varying locations are assigned solely based on the
* requirements of transform feedback.
@@ -983,7 +995,8 @@ assign_varying_locations(struct gl_context *ctx,
struct gl_shader_program *prog,
gl_shader *producer, gl_shader *consumer,
unsigned num_tfeedback_decls,
- tfeedback_decl *tfeedback_decls)
+ tfeedback_decl *tfeedback_decls,
+ unsigned gs_input_vertices)
{
const unsigned producer_base = VARYING_SLOT_VAR0;
const unsigned consumer_base = VARYING_SLOT_VAR0;
@@ -1104,10 +1117,10 @@ assign_varying_locations(struct gl_context *ctx,
assert(!ctx->Extensions.EXT_transform_feedback);
} else {
lower_packed_varyings(mem_ctx, producer_base, slots_used,
- ir_var_shader_out, producer);
+ ir_var_shader_out, 0, producer);
if (consumer) {
lower_packed_varyings(mem_ctx, consumer_base, slots_used,
- ir_var_shader_in, consumer);
+ ir_var_shader_in, gs_input_vertices, consumer);
}
}
@@ -1164,7 +1177,7 @@ check_against_varying_limit(struct gl_context *ctx,
/* The packing rules used for vertex shader inputs are also
* used for fragment shader inputs.
*/
- varying_vectors += count_attribute_slots(var->type);
+ varying_vectors += var->type->count_attribute_slots();
}
}
diff --git a/mesalib/src/glsl/link_varyings.h b/mesalib/src/glsl/link_varyings.h
index cfc6e474f..302ab5c26 100644
--- a/mesalib/src/glsl/link_varyings.h
+++ b/mesalib/src/glsl/link_varyings.h
@@ -234,7 +234,8 @@ assign_varying_locations(struct gl_context *ctx,
struct gl_shader_program *prog,
gl_shader *producer, gl_shader *consumer,
unsigned num_tfeedback_decls,
- tfeedback_decl *tfeedback_decls);
+ tfeedback_decl *tfeedback_decls,
+ unsigned gs_input_vertices);
bool
check_against_varying_limit(struct gl_context *ctx,
diff --git a/mesalib/src/glsl/linker.cpp b/mesalib/src/glsl/linker.cpp
index 942f90615..f87ae0eec 100644
--- a/mesalib/src/glsl/linker.cpp
+++ b/mesalib/src/glsl/linker.cpp
@@ -73,11 +73,15 @@
#include "linker.h"
#include "link_varyings.h"
#include "ir_optimization.h"
+#include "ir_rvalue_visitor.h"
extern "C" {
#include "main/shaderobj.h"
+#include "main/enums.h"
}
+void linker_error(gl_shader_program *, const char *, ...);
+
/**
* Visitor that determines whether or not a variable is ever written.
*/
@@ -174,6 +178,77 @@ private:
};
+class geom_array_resize_visitor : public ir_hierarchical_visitor {
+public:
+ unsigned num_vertices;
+ gl_shader_program *prog;
+
+ geom_array_resize_visitor(unsigned num_vertices, gl_shader_program *prog)
+ {
+ this->num_vertices = num_vertices;
+ this->prog = prog;
+ }
+
+ virtual ~geom_array_resize_visitor()
+ {
+ /* empty */
+ }
+
+ virtual ir_visitor_status visit(ir_variable *var)
+ {
+ if (!var->type->is_array() || var->mode != ir_var_shader_in)
+ return visit_continue;
+
+ unsigned size = var->type->length;
+
+ /* Generate a link error if the shader has declared this array with an
+ * incorrect size.
+ */
+ if (size && size != this->num_vertices) {
+ linker_error(this->prog, "size of array %s declared as %u, "
+ "but number of input vertices is %u\n",
+ var->name, size, this->num_vertices);
+ return visit_continue;
+ }
+
+ /* Generate a link error if the shader attempts to access an input
+ * array using an index too large for its actual size assigned at link
+ * time.
+ */
+ if (var->max_array_access >= this->num_vertices) {
+ linker_error(this->prog, "geometry shader accesses element %i of "
+ "%s, but only %i input vertices\n",
+ var->max_array_access, var->name, this->num_vertices);
+ return visit_continue;
+ }
+
+ var->type = glsl_type::get_array_instance(var->type->element_type(),
+ this->num_vertices);
+ var->max_array_access = this->num_vertices - 1;
+
+ return visit_continue;
+ }
+
+ /* Dereferences of input variables need to be updated so that their type
+ * matches the newly assigned type of the variable they are accessing. */
+ virtual ir_visitor_status visit(ir_dereference_variable *ir)
+ {
+ ir->type = ir->var->type;
+ return visit_continue;
+ }
+
+ /* Dereferences of 2D input arrays need to be updated so that their type
+ * matches the newly assigned type of the array they are accessing. */
+ virtual ir_visitor_status visit_leave(ir_dereference_array *ir)
+ {
+ const glsl_type *const vt = ir->array->type;
+ if (vt->is_array())
+ ir->type = vt->element_type();
+ return visit_continue;
+ }
+};
+
+
void
linker_error(gl_shader_program *prog, const char *fmt, ...)
{
@@ -298,41 +373,6 @@ link_invalidate_variable_locations(gl_shader *sh, int input_base,
/**
- * Determine the number of attribute slots required for a particular type
- *
- * This code is here because it implements the language rules of a specific
- * GLSL version. Since it's a property of the language and not a property of
- * types in general, it doesn't really belong in glsl_type.
- */
-unsigned
-count_attribute_slots(const glsl_type *t)
-{
- /* From page 31 (page 37 of the PDF) of the GLSL 1.50 spec:
- *
- * "A scalar input counts the same amount against this limit as a vec4,
- * so applications may want to consider packing groups of four
- * unrelated float inputs together into a vector to better utilize the
- * capabilities of the underlying hardware. A matrix input will use up
- * multiple locations. The number of locations used will equal the
- * number of columns in the matrix."
- *
- * The spec does not explicitly say how arrays are counted. However, it
- * should be safe to assume the total number of slots consumed by an array
- * is the number of entries in the array multiplied by the number of slots
- * consumed by a single element of the array.
- */
-
- if (t->is_array())
- return t->array_size() * count_attribute_slots(t->element_type());
-
- if (t->is_matrix())
- return t->matrix_columns;
-
- return 1;
-}
-
-
-/**
* Verify that a vertex shader executable meets all semantic requirements.
*
* Also sets prog->Vert.UsesClipDistance and prog->Vert.ClipDistanceArraySize
@@ -437,6 +477,24 @@ validate_fragment_shader_executable(struct gl_shader_program *prog,
}
}
+/**
+ * Verify that a geometry shader executable meets all semantic requirements
+ *
+ * Also sets prog->Geom.VerticesIn 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)
+{
+ if (shader == NULL)
+ return;
+
+ unsigned num_vertices = vertices_per_prim(prog->Geom.InputType);
+ prog->Geom.VerticesIn = num_vertices;
+}
+
/**
* Generate a string describing the mode of a variable
@@ -931,6 +989,99 @@ public:
};
/**
+ * Performs the cross-validation of geometry shader max_vertices and
+ * primitive type layout qualifiers for the attached geometry shaders,
+ * and propagates them to the linked GS and linked shader program.
+ */
+static void
+link_gs_inout_layout_qualifiers(struct gl_shader_program *prog,
+ struct gl_shader *linked_shader,
+ struct gl_shader **shader_list,
+ unsigned num_shaders)
+{
+ linked_shader->Geom.VerticesOut = 0;
+ linked_shader->Geom.InputType = PRIM_UNKNOWN;
+ linked_shader->Geom.OutputType = PRIM_UNKNOWN;
+
+ /* 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)
+ return;
+
+ /* From the GLSL 1.50 spec, page 46:
+ *
+ * "All geometry shader output layout declarations in a program
+ * must declare the same layout and same value for
+ * max_vertices. There must be at least one geometry output
+ * layout declaration somewhere in a program, but not all
+ * geometry shaders (compilation units) are required to
+ * declare it."
+ */
+
+ for (unsigned i = 0; i < num_shaders; i++) {
+ struct gl_shader *shader = shader_list[i];
+
+ if (shader->Geom.InputType != PRIM_UNKNOWN) {
+ if (linked_shader->Geom.InputType != PRIM_UNKNOWN &&
+ linked_shader->Geom.InputType != shader->Geom.InputType) {
+ linker_error(prog, "geometry shader defined with conflicting "
+ "input types\n");
+ return;
+ }
+ linked_shader->Geom.InputType = shader->Geom.InputType;
+ }
+
+ if (shader->Geom.OutputType != PRIM_UNKNOWN) {
+ if (linked_shader->Geom.OutputType != PRIM_UNKNOWN &&
+ linked_shader->Geom.OutputType != shader->Geom.OutputType) {
+ linker_error(prog, "geometry shader defined with conflicting "
+ "output types\n");
+ return;
+ }
+ linked_shader->Geom.OutputType = shader->Geom.OutputType;
+ }
+
+ if (shader->Geom.VerticesOut != 0) {
+ if (linked_shader->Geom.VerticesOut != 0 &&
+ linked_shader->Geom.VerticesOut != shader->Geom.VerticesOut) {
+ linker_error(prog, "geometry shader defined with conflicting "
+ "output vertex count (%d and %d)\n",
+ linked_shader->Geom.VerticesOut,
+ shader->Geom.VerticesOut);
+ return;
+ }
+ linked_shader->Geom.VerticesOut = shader->Geom.VerticesOut;
+ }
+ }
+
+ /* 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->Geom.InputType == PRIM_UNKNOWN) {
+ linker_error(prog,
+ "geometry shader didn't declare primitive input type\n");
+ return;
+ }
+ prog->Geom.InputType = linked_shader->Geom.InputType;
+
+ if (linked_shader->Geom.OutputType == PRIM_UNKNOWN) {
+ linker_error(prog,
+ "geometry shader didn't declare primitive output type\n");
+ return;
+ }
+ prog->Geom.OutputType = linked_shader->Geom.OutputType;
+
+ if (linked_shader->Geom.VerticesOut == 0) {
+ linker_error(prog,
+ "geometry shader didn't declare max_vertices\n");
+ return;
+ }
+ prog->Geom.VerticesOut = linked_shader->Geom.VerticesOut;
+}
+
+/**
* Combine a group of shaders for a single stage to generate a linked shader
*
* \note
@@ -1034,6 +1185,8 @@ link_intrastage_shaders(void *mem_ctx,
linked->NumUniformBlocks = num_uniform_blocks;
ralloc_steal(linked, linked->UniformBlocks);
+ link_gs_inout_layout_qualifiers(prog, linked, shader_list, num_shaders);
+
populate_symbol_table(linked);
/* The a pointer to the main function in the final linked shader (i.e., the
@@ -1080,7 +1233,8 @@ link_intrastage_shaders(void *mem_ctx,
if (!link_function_calls(prog, linked, linking_shaders,
num_linking_shaders)) {
ctx->Driver.DeleteShader(ctx, linked);
- linked = NULL;
+ free(linking_shaders);
+ return NULL;
}
free(linking_shaders);
@@ -1088,18 +1242,24 @@ link_intrastage_shaders(void *mem_ctx,
/* At this point linked should contain all of the linked IR, so
* validate it to make sure nothing went wrong.
*/
- if (linked)
- validate_ir_tree(linked->ir);
+ validate_ir_tree(linked->ir);
+
+ /* Set the size of geometry shader input arrays */
+ if (linked->Type == GL_GEOMETRY_SHADER) {
+ 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) {
+ ir_instruction *ir = (ir_instruction *)iter.get();
+ ir->accept(&input_resize_visitor);
+ }
+ }
/* Make a pass over all variable declarations to ensure that arrays with
* unspecified sizes have a size specified. The size is inferred from the
* max_array_access field.
*/
- if (linked != NULL) {
- array_sizing_visitor v;
-
- v.run(linked->ir);
- }
+ array_sizing_visitor v;
+ v.run(linked->ir);
return linked;
}
@@ -1129,9 +1289,7 @@ update_array_sizes(struct gl_shader_program *prog)
foreach_list(node, prog->_LinkedShaders[i]->ir) {
ir_variable *const var = ((ir_instruction *) node)->as_variable();
- if ((var == NULL) || (var->mode != ir_var_uniform &&
- var->mode != ir_var_shader_in &&
- var->mode != ir_var_shader_out) ||
+ if ((var == NULL) || (var->mode != ir_var_uniform) ||
!var->type->is_array())
continue;
@@ -1334,7 +1492,7 @@ assign_attribute_or_color_locations(gl_shader_program *prog,
* that it doesn't collide with other assigned locations. Otherwise,
* add it to the list of variables that need linker-assigned locations.
*/
- const unsigned slots = count_attribute_slots(var->type);
+ const unsigned slots = var->type->count_attribute_slots();
if (var->location != -1) {
if (var->location >= generic_base && var->index < 1) {
/* From page 61 of the OpenGL 4.0 spec:
@@ -1650,10 +1808,15 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
unsigned num_vert_shaders = 0;
struct gl_shader **frag_shader_list;
unsigned num_frag_shaders = 0;
+ struct gl_shader **geom_shader_list;
+ unsigned num_geom_shaders = 0;
vert_shader_list = (struct gl_shader **)
- calloc(2 * prog->NumShaders, sizeof(struct gl_shader *));
- frag_shader_list = &vert_shader_list[prog->NumShaders];
+ calloc(prog->NumShaders, sizeof(struct gl_shader *));
+ frag_shader_list = (struct gl_shader **)
+ calloc(prog->NumShaders, sizeof(struct gl_shader *));
+ geom_shader_list = (struct gl_shader **)
+ calloc(prog->NumShaders, sizeof(struct gl_shader *));
unsigned min_version = UINT_MAX;
unsigned max_version = 0;
@@ -1679,8 +1842,8 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
num_frag_shaders++;
break;
case GL_GEOMETRY_SHADER:
- /* FINISHME: Support geometry shaders. */
- assert(prog->Shaders[i]->Type != GL_GEOMETRY_SHADER);
+ geom_shader_list[num_geom_shaders] = prog->Shaders[i];
+ num_geom_shaders++;
break;
}
}
@@ -1701,6 +1864,14 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
prog->Version = max_version;
prog->IsES = is_es_prog;
+ /* Geometry shaders have to be linked with vertex shaders.
+ */
+ if (num_geom_shaders > 0 && num_vert_shaders == 0) {
+ linker_error(prog, "Geometry shader must be linked with "
+ "vertex shader\n");
+ goto done;
+ }
+
for (unsigned int i = 0; i < MESA_SHADER_TYPES; i++) {
if (prog->_LinkedShaders[i] != NULL)
ctx->Driver.DeleteShader(ctx, prog->_LinkedShaders[i]);
@@ -1742,6 +1913,22 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
sh);
}
+ if (num_geom_shaders > 0) {
+ gl_shader *const sh =
+ link_intrastage_shaders(mem_ctx, ctx, prog, geom_shader_list,
+ num_geom_shaders);
+
+ if (!prog->LinkStatus)
+ goto done;
+
+ validate_geometry_shader_executable(prog, sh);
+ if (!prog->LinkStatus)
+ goto done;
+
+ _mesa_reference_shader(ctx, &prog->_LinkedShaders[MESA_SHADER_GEOMETRY],
+ sh);
+ }
+
/* Here begins the inter-stage linking phase. Some initial validation is
* performed, then locations are assigned for uniforms, attributes, and
* varyings.
@@ -1828,7 +2015,11 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
prog->_LinkedShaders[MESA_SHADER_VERTEX],
VERT_ATTRIB_GENERIC0, VARYING_SLOT_VAR0);
}
- /* FINISHME: Geometry shaders not implemented yet */
+ if (prog->_LinkedShaders[MESA_SHADER_GEOMETRY] != NULL) {
+ link_invalidate_variable_locations(
+ prog->_LinkedShaders[MESA_SHADER_GEOMETRY],
+ VARYING_SLOT_VAR0, VARYING_SLOT_VAR0);
+ }
if (prog->_LinkedShaders[MESA_SHADER_FRAGMENT] != NULL) {
link_invalidate_variable_locations(
prog->_LinkedShaders[MESA_SHADER_FRAGMENT],
@@ -1862,7 +2053,7 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
* non-zero, but the program object has no vertex or geometry
* shader;
*/
- if (first >= MESA_SHADER_FRAGMENT) {
+ if (first == MESA_SHADER_FRAGMENT) {
linker_error(prog, "Transform feedback varyings specified, but "
"no vertex or geometry shader is present.");
goto done;
@@ -1895,11 +2086,12 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
*/
if (!assign_varying_locations(ctx, mem_ctx, prog,
sh, NULL,
- num_tfeedback_decls, tfeedback_decls))
+ num_tfeedback_decls, tfeedback_decls,
+ 0))
goto done;
}
- do_dead_builtin_varyings(ctx, sh->ir, NULL,
+ do_dead_builtin_varyings(ctx, sh, NULL,
num_tfeedback_decls, tfeedback_decls);
demote_shader_inputs_and_outputs(sh, ir_var_shader_out);
@@ -1914,7 +2106,7 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
*/
gl_shader *const sh = prog->_LinkedShaders[first];
- do_dead_builtin_varyings(ctx, NULL, sh->ir,
+ do_dead_builtin_varyings(ctx, NULL, sh,
num_tfeedback_decls, tfeedback_decls);
demote_shader_inputs_and_outputs(sh, ir_var_shader_in);
@@ -1930,13 +2122,15 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
gl_shader *const sh_i = prog->_LinkedShaders[i];
gl_shader *const sh_next = prog->_LinkedShaders[next];
+ unsigned gs_input_vertices =
+ next == MESA_SHADER_GEOMETRY ? prog->Geom.VerticesIn : 0;
if (!assign_varying_locations(ctx, mem_ctx, prog, sh_i, sh_next,
next == MESA_SHADER_FRAGMENT ? num_tfeedback_decls : 0,
- tfeedback_decls))
+ tfeedback_decls, gs_input_vertices))
goto done;
- do_dead_builtin_varyings(ctx, sh_i->ir, sh_next->ir,
+ do_dead_builtin_varyings(ctx, sh_i, sh_next,
next == MESA_SHADER_FRAGMENT ? num_tfeedback_decls : 0,
tfeedback_decls);
@@ -1985,6 +2179,8 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
done:
free(vert_shader_list);
+ free(frag_shader_list);
+ free(geom_shader_list);
for (unsigned i = 0; i < MESA_SHADER_TYPES; i++) {
if (prog->_LinkedShaders[i] == NULL)
diff --git a/mesalib/src/glsl/linker.h b/mesalib/src/glsl/linker.h
index 0ce747d6c..64a683d15 100644
--- a/mesalib/src/glsl/linker.h
+++ b/mesalib/src/glsl/linker.h
@@ -155,7 +155,4 @@ linker_error(gl_shader_program *prog, const char *fmt, ...);
void
linker_warning(gl_shader_program *prog, const char *fmt, ...);
-unsigned
-count_attribute_slots(const glsl_type *t);
-
#endif /* GLSL_LINKER_H */
diff --git a/mesalib/src/glsl/lower_output_reads.cpp b/mesalib/src/glsl/lower_output_reads.cpp
index b93e254ec..5ba9720d0 100644
--- a/mesalib/src/glsl/lower_output_reads.cpp
+++ b/mesalib/src/glsl/lower_output_reads.cpp
@@ -50,6 +50,7 @@ public:
output_read_remover();
~output_read_remover();
virtual ir_visitor_status visit(class ir_dereference_variable *);
+ virtual ir_visitor_status visit(class ir_emit_vertex *);
virtual ir_visitor_status visit_leave(class ir_return *);
virtual ir_visitor_status visit_leave(class ir_function_signature *);
};
@@ -117,7 +118,9 @@ copy(void *ctx, ir_variable *output, ir_variable *temp)
return new(ctx) ir_assignment(lhs, rhs);
}
-/** Insert a copy-back assignment before a "return" statement */
+/** Insert a copy-back assignment before a "return" statement or a call to
+ * EmitVertex().
+ */
static void
emit_return_copy(const void *key, void *data, void *closure)
{
@@ -141,6 +144,14 @@ output_read_remover::visit_leave(ir_return *ir)
}
ir_visitor_status
+output_read_remover::visit(ir_emit_vertex *ir)
+{
+ hash_table_call_foreach(replacements, emit_return_copy, ir);
+ hash_table_clear(replacements);
+ return visit_continue;
+}
+
+ir_visitor_status
output_read_remover::visit_leave(ir_function_signature *sig)
{
if (strcmp(sig->function_name(), "main") != 0)
diff --git a/mesalib/src/glsl/lower_packed_varyings.cpp b/mesalib/src/glsl/lower_packed_varyings.cpp
index cdf2289b4..31a50bba5 100644
--- a/mesalib/src/glsl/lower_packed_varyings.cpp
+++ b/mesalib/src/glsl/lower_packed_varyings.cpp
@@ -74,6 +74,74 @@
* This lowering pass also handles varyings whose type is a struct or an array
* of struct. Structs are packed in order and with no gaps, so there may be a
* performance penalty due to structure elements being double-parked.
+ *
+ * Lowering of geometry shader inputs is slightly more complex, since geometry
+ * inputs are always arrays, so we need to lower arrays to arrays. For
+ * example, the following input:
+ *
+ * in struct Foo {
+ * float f;
+ * vec3 v;
+ * vec2 a[2];
+ * } arr[3]; // location=4, location_frac=0
+ *
+ * Would get lowered like this if it occurred in a fragment shader:
+ *
+ * struct Foo {
+ * float f;
+ * vec3 v;
+ * vec2 a[2];
+ * } arr[3];
+ * in vec4 packed4; // location=4, location_frac=0
+ * in vec4 packed5; // location=5, location_frac=0
+ * in vec4 packed6; // location=6, location_frac=0
+ * in vec4 packed7; // location=7, location_frac=0
+ * in vec4 packed8; // location=8, location_frac=0
+ * in vec4 packed9; // location=9, location_frac=0
+ *
+ * main()
+ * {
+ * arr[0].f = packed4.x;
+ * arr[0].v = packed4.yzw;
+ * arr[0].a[0] = packed5.xy;
+ * arr[0].a[1] = packed5.zw;
+ * arr[1].f = packed6.x;
+ * arr[1].v = packed6.yzw;
+ * arr[1].a[0] = packed7.xy;
+ * arr[1].a[1] = packed7.zw;
+ * arr[2].f = packed8.x;
+ * arr[2].v = packed8.yzw;
+ * arr[2].a[0] = packed9.xy;
+ * arr[2].a[1] = packed9.zw;
+ * ...
+ * }
+ *
+ * But it would get lowered like this if it occurred in a geometry shader:
+ *
+ * struct Foo {
+ * float f;
+ * vec3 v;
+ * vec2 a[2];
+ * } arr[3];
+ * in vec4 packed4[3]; // location=4, location_frac=0
+ * in vec4 packed5[3]; // location=5, location_frac=0
+ *
+ * main()
+ * {
+ * arr[0].f = packed4[0].x;
+ * arr[0].v = packed4[0].yzw;
+ * arr[0].a[0] = packed5[0].xy;
+ * arr[0].a[1] = packed5[0].zw;
+ * arr[1].f = packed4[1].x;
+ * arr[1].v = packed4[1].yzw;
+ * arr[1].a[0] = packed5[1].xy;
+ * arr[1].a[1] = packed5[1].zw;
+ * arr[2].f = packed4[2].x;
+ * arr[2].v = packed4[2].yzw;
+ * arr[2].a[0] = packed5[2].xy;
+ * arr[2].a[1] = packed5[2].zw;
+ * ...
+ * }
*/
#include "glsl_symbol_table.h"
@@ -93,7 +161,8 @@ public:
lower_packed_varyings_visitor(void *mem_ctx, unsigned location_base,
unsigned locations_used,
ir_variable_mode mode,
- exec_list *main_instructions);
+ unsigned gs_input_vertices,
+ exec_list *out_instructions);
void run(exec_list *instructions);
@@ -101,13 +170,16 @@ private:
ir_assignment *bitwise_assign_pack(ir_rvalue *lhs, ir_rvalue *rhs);
ir_assignment *bitwise_assign_unpack(ir_rvalue *lhs, ir_rvalue *rhs);
unsigned lower_rvalue(ir_rvalue *rvalue, unsigned fine_location,
- ir_variable *unpacked_var, const char *name);
+ ir_variable *unpacked_var, const char *name,
+ bool gs_input_toplevel, unsigned vertex_index);
unsigned lower_arraylike(ir_rvalue *rvalue, unsigned array_size,
unsigned fine_location,
- ir_variable *unpacked_var, const char *name);
- ir_variable *get_packed_varying(unsigned location,
- ir_variable *unpacked_var,
- const char *name);
+ ir_variable *unpacked_var, const char *name,
+ bool gs_input_toplevel, unsigned vertex_index);
+ ir_dereference *get_packed_varying_deref(unsigned location,
+ ir_variable *unpacked_var,
+ const char *name,
+ unsigned vertex_index);
bool needs_lowering(ir_variable *var);
/**
@@ -145,15 +217,23 @@ private:
const ir_variable_mode mode;
/**
- * List of instructions corresponding to the main() function. This is
- * where we add instructions to pack or unpack the varyings.
+ * If we are currently lowering geometry shader inputs, the number of input
+ * vertices the geometry shader accepts. Otherwise zero.
*/
- exec_list *main_instructions;
+ const unsigned gs_input_vertices;
+
+ /**
+ * Exec list into which the visitor should insert the packing instructions.
+ * Caller provides this list; it should insert the instructions into the
+ * appropriate place in the shader once the visitor has finished running.
+ */
+ exec_list *out_instructions;
};
lower_packed_varyings_visitor::lower_packed_varyings_visitor(
void *mem_ctx, unsigned location_base, unsigned locations_used,
- ir_variable_mode mode, exec_list *main_instructions)
+ ir_variable_mode mode, unsigned gs_input_vertices,
+ exec_list *out_instructions)
: mem_ctx(mem_ctx),
location_base(location_base),
locations_used(locations_used),
@@ -161,7 +241,8 @@ lower_packed_varyings_visitor::lower_packed_varyings_visitor(
rzalloc_array_size(mem_ctx, sizeof(*packed_varyings),
locations_used)),
mode(mode),
- main_instructions(main_instructions)
+ gs_input_vertices(gs_input_vertices),
+ out_instructions(out_instructions)
{
}
@@ -195,7 +276,7 @@ lower_packed_varyings_visitor::run(exec_list *instructions)
/* Recursively pack or unpack it. */
this->lower_rvalue(deref, var->location * 4 + var->location_frac, var,
- var->name);
+ var->name, this->gs_input_vertices != 0, 0);
}
}
@@ -277,6 +358,15 @@ lower_packed_varyings_visitor::bitwise_assign_unpack(ir_rvalue *lhs,
* in multiples of a float, rather than multiples of a vec4 as is used
* elsewhere in Mesa.
*
+ * \param gs_input_toplevel should be set to true if we are lowering geometry
+ * shader inputs, and we are currently lowering the whole input variable
+ * (i.e. we are lowering the array whose index selects the vertex).
+ *
+ * \param vertex_index: if we are lowering geometry shader inputs, and the
+ * level of the array that we are currently lowering is *not* the top level,
+ * then this indicates which vertex we are currently lowering. Otherwise it
+ * is ignored.
+ *
* \return the location where the next constituent vector (after this one)
* should be packed.
*/
@@ -284,8 +374,15 @@ unsigned
lower_packed_varyings_visitor::lower_rvalue(ir_rvalue *rvalue,
unsigned fine_location,
ir_variable *unpacked_var,
- const char *name)
+ const char *name,
+ bool gs_input_toplevel,
+ unsigned vertex_index)
{
+ /* When gs_input_toplevel is set, we should be looking at a geometry shader
+ * input array.
+ */
+ assert(!gs_input_toplevel || rvalue->type->is_array());
+
if (rvalue->type->is_record()) {
for (unsigned i = 0; i < rvalue->type->length; i++) {
if (i != 0)
@@ -296,7 +393,8 @@ lower_packed_varyings_visitor::lower_rvalue(ir_rvalue *rvalue,
char *deref_name
= ralloc_asprintf(this->mem_ctx, "%s.%s", name, field_name);
fine_location = this->lower_rvalue(dereference_record, fine_location,
- unpacked_var, deref_name);
+ unpacked_var, deref_name, false,
+ vertex_index);
}
return fine_location;
} else if (rvalue->type->is_array()) {
@@ -304,13 +402,15 @@ lower_packed_varyings_visitor::lower_rvalue(ir_rvalue *rvalue,
* sequence.
*/
return this->lower_arraylike(rvalue, rvalue->type->array_size(),
- fine_location, unpacked_var, name);
+ fine_location, unpacked_var, name,
+ gs_input_toplevel, vertex_index);
} else if (rvalue->type->is_matrix()) {
/* Matrices are packed/unpacked by considering each column vector in
* sequence.
*/
return this->lower_arraylike(rvalue, rvalue->type->matrix_columns,
- fine_location, unpacked_var, name);
+ fine_location, unpacked_var, name,
+ false, vertex_index);
} else if (rvalue->type->vector_elements + fine_location % 4 > 4) {
/* This vector is going to be "double parked" across two varying slots,
* so handle it as two separate assignments.
@@ -340,9 +440,10 @@ lower_packed_varyings_visitor::lower_rvalue(ir_rvalue *rvalue,
char *right_name
= ralloc_asprintf(this->mem_ctx, "%s.%s", name, right_swizzle_name);
fine_location = this->lower_rvalue(left_swizzle, fine_location,
- unpacked_var, left_name);
+ unpacked_var, left_name, false,
+ vertex_index);
return this->lower_rvalue(right_swizzle, fine_location, unpacked_var,
- right_name);
+ right_name, false, vertex_index);
} else {
/* No special handling is necessary; pack the rvalue into the
* varying.
@@ -353,19 +454,19 @@ lower_packed_varyings_visitor::lower_rvalue(ir_rvalue *rvalue,
unsigned location_frac = fine_location % 4;
for (unsigned i = 0; i < components; ++i)
swizzle_values[i] = i + location_frac;
- ir_dereference_variable *packed_deref = new(this->mem_ctx)
- ir_dereference_variable(this->get_packed_varying(location,
- unpacked_var, name));
+ ir_dereference *packed_deref =
+ this->get_packed_varying_deref(location, unpacked_var, name,
+ vertex_index);
ir_swizzle *swizzle = new(this->mem_ctx)
ir_swizzle(packed_deref, swizzle_values, components);
if (this->mode == ir_var_shader_out) {
ir_assignment *assignment
= this->bitwise_assign_pack(swizzle, rvalue);
- this->main_instructions->push_tail(assignment);
+ this->out_instructions->push_tail(assignment);
} else {
ir_assignment *assignment
= this->bitwise_assign_unpack(rvalue, swizzle);
- this->main_instructions->push_head(assignment);
+ this->out_instructions->push_tail(assignment);
}
return fine_location + components;
}
@@ -376,13 +477,24 @@ lower_packed_varyings_visitor::lower_rvalue(ir_rvalue *rvalue,
* constituent elements, accessing each one using an ir_dereference_array.
* This takes care of both arrays and matrices, since ir_dereference_array
* treats a matrix like an array of its column vectors.
+ *
+ * \param gs_input_toplevel should be set to true if we are lowering geometry
+ * shader inputs, and we are currently lowering the whole input variable
+ * (i.e. we are lowering the array whose index selects the vertex).
+ *
+ * \param vertex_index: if we are lowering geometry shader inputs, and the
+ * level of the array that we are currently lowering is *not* the top level,
+ * then this indicates which vertex we are currently lowering. Otherwise it
+ * is ignored.
*/
unsigned
lower_packed_varyings_visitor::lower_arraylike(ir_rvalue *rvalue,
unsigned array_size,
unsigned fine_location,
ir_variable *unpacked_var,
- const char *name)
+ const char *name,
+ bool gs_input_toplevel,
+ unsigned vertex_index)
{
for (unsigned i = 0; i < array_size; i++) {
if (i != 0)
@@ -392,8 +504,20 @@ lower_packed_varyings_visitor::lower_arraylike(ir_rvalue *rvalue,
ir_dereference_array(rvalue, constant);
char *subscripted_name
= ralloc_asprintf(this->mem_ctx, "%s[%d]", name, i);
- fine_location = this->lower_rvalue(dereference_array, fine_location,
- unpacked_var, subscripted_name);
+ if (gs_input_toplevel) {
+ /* Geometry shader inputs are a special case. Instead of storing
+ * each element of the array at a different location, all elements
+ * are at the same location, but with a different vertex index.
+ */
+ (void) this->lower_rvalue(dereference_array, fine_location,
+ unpacked_var, subscripted_name,
+ false, i);
+ } else {
+ fine_location =
+ this->lower_rvalue(dereference_array, fine_location,
+ unpacked_var, subscripted_name,
+ false, vertex_index);
+ }
}
return fine_location;
}
@@ -406,11 +530,14 @@ lower_packed_varyings_visitor::lower_arraylike(ir_rvalue *rvalue,
* The newly created varying inherits its interpolation parameters from \c
* unpacked_var. Its base type is ivec4 if we are lowering a flat varying,
* vec4 otherwise.
+ *
+ * \param vertex_index: if we are lowering geometry shader inputs, then this
+ * indicates which vertex we are currently lowering. Otherwise it is ignored.
*/
-ir_variable *
-lower_packed_varyings_visitor::get_packed_varying(unsigned location,
- ir_variable *unpacked_var,
- const char *name)
+ir_dereference *
+lower_packed_varyings_visitor::get_packed_varying_deref(
+ unsigned location, ir_variable *unpacked_var, const char *name,
+ unsigned vertex_index)
{
unsigned slot = location - this->location_base;
assert(slot < locations_used);
@@ -421,18 +548,44 @@ lower_packed_varyings_visitor::get_packed_varying(unsigned location,
packed_type = glsl_type::ivec4_type;
else
packed_type = glsl_type::vec4_type;
+ if (this->gs_input_vertices != 0) {
+ packed_type =
+ glsl_type::get_array_instance(packed_type,
+ this->gs_input_vertices);
+ }
ir_variable *packed_var = new(this->mem_ctx)
ir_variable(packed_type, packed_name, this->mode);
+ if (this->gs_input_vertices != 0) {
+ /* Prevent update_array_sizes() from messing with the size of the
+ * array.
+ */
+ packed_var->max_array_access = this->gs_input_vertices - 1;
+ }
packed_var->centroid = unpacked_var->centroid;
packed_var->interpolation = unpacked_var->interpolation;
packed_var->location = location;
unpacked_var->insert_before(packed_var);
this->packed_varyings[slot] = packed_var;
} else {
- ralloc_asprintf_append((char **) &this->packed_varyings[slot]->name,
- ",%s", name);
+ /* For geometry shader inputs, only update the packed variable name the
+ * first time we visit each component.
+ */
+ if (this->gs_input_vertices == 0 || vertex_index == 0) {
+ ralloc_asprintf_append((char **) &this->packed_varyings[slot]->name,
+ ",%s", name);
+ }
+ }
+
+ ir_dereference *deref = new(this->mem_ctx)
+ ir_dereference_variable(this->packed_varyings[slot]);
+ if (this->gs_input_vertices != 0) {
+ /* When lowering GS inputs, the packed variable is an array, so we need
+ * to dereference it using vertex_index.
+ */
+ ir_constant *constant = new(this->mem_ctx) ir_constant(vertex_index);
+ deref = new(this->mem_ctx) ir_dereference_array(deref, constant);
}
- return this->packed_varyings[slot];
+ return deref;
}
bool
@@ -440,6 +593,10 @@ lower_packed_varyings_visitor::needs_lowering(ir_variable *var)
{
/* Things composed of vec4's don't need lowering. Everything else does. */
const glsl_type *type = var->type;
+ if (this->gs_input_vertices != 0) {
+ assert(type->is_array());
+ type = type->element_type();
+ }
if (type->is_array())
type = type->fields.array;
if (type->vector_elements == 4)
@@ -447,19 +604,81 @@ lower_packed_varyings_visitor::needs_lowering(ir_variable *var)
return true;
}
+
+/**
+ * Visitor that splices varying packing code before every use of EmitVertex()
+ * in a geometry shader.
+ */
+class lower_packed_varyings_gs_splicer : public ir_hierarchical_visitor
+{
+public:
+ explicit lower_packed_varyings_gs_splicer(void *mem_ctx,
+ const exec_list *instructions);
+
+ virtual ir_visitor_status visit(ir_emit_vertex *ev);
+
+private:
+ /**
+ * Memory context used to allocate new instructions for the shader.
+ */
+ void * const mem_ctx;
+
+ /**
+ * Instructions that should be spliced into place before each EmitVertex()
+ * call.
+ */
+ const exec_list *instructions;
+};
+
+
+lower_packed_varyings_gs_splicer::lower_packed_varyings_gs_splicer(
+ void *mem_ctx, const exec_list *instructions)
+ : mem_ctx(mem_ctx), instructions(instructions)
+{
+}
+
+
+ir_visitor_status
+lower_packed_varyings_gs_splicer::visit(ir_emit_vertex *ev)
+{
+ foreach_list(node, this->instructions) {
+ ir_instruction *ir = (ir_instruction *) node;
+ ev->insert_before(ir->clone(this->mem_ctx, NULL));
+ }
+ return visit_continue;
+}
+
+
void
lower_packed_varyings(void *mem_ctx, unsigned location_base,
unsigned locations_used, ir_variable_mode mode,
- gl_shader *shader)
+ unsigned gs_input_vertices, gl_shader *shader)
{
exec_list *instructions = shader->ir;
ir_function *main_func = shader->symbols->get_function("main");
exec_list void_parameters;
ir_function_signature *main_func_sig
= main_func->matching_signature(&void_parameters);
- exec_list *main_instructions = &main_func_sig->body;
+ exec_list new_instructions;
lower_packed_varyings_visitor visitor(mem_ctx, location_base,
locations_used, mode,
- main_instructions);
+ gs_input_vertices, &new_instructions);
visitor.run(instructions);
+ if (mode == ir_var_shader_out) {
+ if (shader->Type == GL_GEOMETRY_SHADER) {
+ /* For geometry shaders, outputs need to be lowered before each call
+ * to EmitVertex()
+ */
+ lower_packed_varyings_gs_splicer splicer(mem_ctx, &new_instructions);
+ splicer.run(instructions);
+ } else {
+ /* For other shader types, outputs need to be lowered at the end of
+ * main()
+ */
+ main_func_sig->body.append_list(&new_instructions);
+ }
+ } else {
+ /* Shader inputs need to be lowered at the beginning of main() */
+ main_func_sig->body.head->insert_before(&new_instructions);
+ }
}
diff --git a/mesalib/src/glsl/opt_dead_builtin_varyings.cpp b/mesalib/src/glsl/opt_dead_builtin_varyings.cpp
index 2e813d24e..6745d5c64 100644
--- a/mesalib/src/glsl/opt_dead_builtin_varyings.cpp
+++ b/mesalib/src/glsl/opt_dead_builtin_varyings.cpp
@@ -409,7 +409,7 @@ lower_texcoord_array(exec_list *ir, const varying_info_visitor *info)
void
do_dead_builtin_varyings(struct gl_context *ctx,
- exec_list *producer, exec_list *consumer,
+ gl_shader *producer, gl_shader *consumer,
unsigned num_tfeedback_decls,
tfeedback_decl *tfeedback_decls)
{
@@ -431,44 +431,55 @@ do_dead_builtin_varyings(struct gl_context *ctx,
varying_info_visitor consumer_info(ir_var_shader_in);
if (producer) {
- producer_info.get(producer, num_tfeedback_decls, tfeedback_decls);
+ producer_info.get(producer->ir, num_tfeedback_decls, tfeedback_decls);
if (!consumer) {
/* At least eliminate unused gl_TexCoord elements. */
if (producer_info.lower_texcoord_array) {
- lower_texcoord_array(producer, &producer_info);
+ lower_texcoord_array(producer->ir, &producer_info);
}
return;
}
}
if (consumer) {
- consumer_info.get(consumer, 0, NULL);
+ consumer_info.get(consumer->ir, 0, NULL);
if (!producer) {
/* At least eliminate unused gl_TexCoord elements. */
if (consumer_info.lower_texcoord_array) {
- lower_texcoord_array(consumer, &consumer_info);
+ lower_texcoord_array(consumer->ir, &consumer_info);
}
return;
}
}
- /* Eliminate the varyings unused by the other shader. */
+ /* Eliminate the outputs unused by the consumer. */
if (producer_info.lower_texcoord_array ||
producer_info.color_usage ||
producer_info.has_fog) {
- replace_varyings_visitor(producer,
+ replace_varyings_visitor(producer->ir,
&producer_info,
consumer_info.texcoord_usage,
consumer_info.color_usage,
consumer_info.has_fog);
}
+ /* The gl_TexCoord fragment shader inputs can be initialized
+ * by GL_COORD_REPLACE, so we can't eliminate them.
+ *
+ * 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) {
+ producer_info.texcoord_usage = (1 << MAX_TEXTURE_COORD_UNITS) - 1;
+ }
+
+ /* Eliminate the inputs uninitialized by the producer. */
if (consumer_info.lower_texcoord_array ||
consumer_info.color_usage ||
consumer_info.has_fog) {
- replace_varyings_visitor(consumer,
+ replace_varyings_visitor(consumer->ir,
&consumer_info,
producer_info.texcoord_usage,
producer_info.color_usage,
diff --git a/mesalib/src/glsl/opt_dead_code_local.cpp b/mesalib/src/glsl/opt_dead_code_local.cpp
index 8c31802a6..42a30b3d8 100644
--- a/mesalib/src/glsl/opt_dead_code_local.cpp
+++ b/mesalib/src/glsl/opt_dead_code_local.cpp
@@ -114,6 +114,23 @@ public:
return visit_continue_with_parent;
}
+ virtual ir_visitor_status visit(ir_emit_vertex *ir)
+ {
+ /* For the purpose of dead code elimination, emitting a vertex counts as
+ * "reading" all of the currently assigned output variables.
+ */
+ foreach_iter(exec_list_iterator, iter, *this->assignments) {
+ assignment_entry *entry = (assignment_entry *)iter.get();
+ if (entry->lhs->mode == ir_var_shader_out) {
+ if (debug)
+ printf("kill %s\n", entry->lhs->name);
+ entry->remove();
+ }
+ }
+
+ return visit_continue;
+ }
+
private:
exec_list *assignments;
};
diff --git a/mesalib/src/mapi/glapi/gen/EXT_framebuffer_object.xml b/mesalib/src/mapi/glapi/gen/EXT_framebuffer_object.xml
index 16c82a4a2..2cf75bc67 100644
--- a/mesalib/src/mapi/glapi/gen/EXT_framebuffer_object.xml
+++ b/mesalib/src/mapi/glapi/gen/EXT_framebuffer_object.xml
@@ -78,7 +78,7 @@
<return type="GLboolean"/>
</function>
- <function name="BindRenderbufferEXT" offset="assign">
+ <function name="BindRenderbufferEXT" offset="assign" deprecated="3.1">
<param name="target" type="GLenum"/>
<param name="renderbuffer" type="GLuint"/>
<glx rop="4316"/>
@@ -112,7 +112,7 @@
<return type="GLboolean"/>
</function>
- <function name="BindFramebufferEXT" offset="assign">
+ <function name="BindFramebufferEXT" offset="assign" deprecated="3.1">
<param name="target" type="GLenum"/>
<param name="framebuffer" type="GLuint"/>
<glx rop="4319"/>
diff --git a/mesalib/src/mesa/drivers/common/meta.c b/mesalib/src/mesa/drivers/common/meta.c
index 4a3497c9a..60157af98 100644
--- a/mesalib/src/mesa/drivers/common/meta.c
+++ b/mesalib/src/mesa/drivers/common/meta.c
@@ -704,9 +704,14 @@ _mesa_meta_begin(struct gl_context *ctx, GLbitfield state)
_mesa_LoadIdentity();
_mesa_MatrixMode(GL_PROJECTION);
_mesa_LoadIdentity();
- _mesa_Ortho(0.0, ctx->DrawBuffer->Width,
- 0.0, ctx->DrawBuffer->Height,
- -1.0, 1.0);
+
+ /* glOrtho with width = 0 or height = 0 generates GL_INVALID_VALUE.
+ * This can occur when there is no draw buffer.
+ */
+ if (ctx->DrawBuffer->Width != 0 && ctx->DrawBuffer->Height != 0)
+ _mesa_Ortho(0.0, ctx->DrawBuffer->Width,
+ 0.0, ctx->DrawBuffer->Height,
+ -1.0, 1.0);
}
if (state & MESA_META_CLIP) {
@@ -956,7 +961,7 @@ _mesa_meta_end(struct gl_context *ctx)
if (ctx->Extensions.ARB_vertex_shader)
_mesa_use_shader_program(ctx, GL_VERTEX_SHADER, save->VertexShader);
- if (ctx->Extensions.ARB_geometry_shader4)
+ if (_mesa_has_geometry_shaders(ctx))
_mesa_use_shader_program(ctx, GL_GEOMETRY_SHADER_ARB,
save->GeometryShader);
@@ -1879,19 +1884,24 @@ _mesa_meta_BlitFramebuffer(struct gl_context *ctx,
const GLenum rb_base_format =
_mesa_base_tex_format(ctx, colorReadRb->InternalFormat);
- newTex = alloc_texture(tex, srcW, srcH, rb_base_format);
- setup_copypix_texture(ctx, tex, newTex, srcX, srcY, srcW, srcH,
+ /* Using the exact source rectangle to create the texture does incorrect
+ * linear filtering along the edges. So, allocate the texture extended along
+ * edges by one pixel in x, y directions.
+ */
+ newTex = alloc_texture(tex, srcW + 2, srcH + 2, rb_base_format);
+ setup_copypix_texture(ctx, tex, newTex,
+ srcX - 1, srcY - 1, srcW + 2, srcH + 2,
rb_base_format, filter);
/* texcoords (after texture allocation!) */
{
- verts[0].s = 0.0F;
- verts[0].t = 0.0F;
- verts[1].s = tex->Sright;
- verts[1].t = 0.0F;
- verts[2].s = tex->Sright;
- verts[2].t = tex->Ttop;
- verts[3].s = 0.0F;
- verts[3].t = tex->Ttop;
+ verts[0].s = 1.0F;
+ verts[0].t = 1.0F;
+ verts[1].s = tex->Sright - 1.0F;
+ verts[1].t = 1.0F;
+ verts[2].s = tex->Sright - 1.0F;
+ verts[2].t = tex->Ttop - 1.0F;
+ verts[3].s = 1.0F;
+ verts[3].t = tex->Ttop - 1.0F;
/* upload new vertex data */
_mesa_BufferSubData(GL_ARRAY_BUFFER_ARB, 0, sizeof(verts), verts);
diff --git a/mesalib/src/mesa/drivers/dri/common/dri_util.c b/mesalib/src/mesa/drivers/dri/common/dri_util.c
index 9ed9df4b3..fa520ea90 100644
--- a/mesalib/src/mesa/drivers/dri/common/dri_util.c
+++ b/mesalib/src/mesa/drivers/dri/common/dri_util.c
@@ -52,8 +52,6 @@ PUBLIC const char __dri2ConfigOptions[] =
DRI_CONF_SECTION_END
DRI_CONF_END;
-static const uint __dri2NConfigOptions = 1;
-
/*****************************************************************/
/** \name Screen handling functions */
/*****************************************************************/
@@ -112,7 +110,7 @@ dri2CreateNewScreen(int scrn, int fd,
return NULL;
}
- driParseOptionInfo(&psp->optionInfo, __dri2ConfigOptions, __dri2NConfigOptions);
+ driParseOptionInfo(&psp->optionInfo, __dri2ConfigOptions);
driParseConfigFiles(&psp->optionCache, &psp->optionInfo, psp->myNum, "dri2");
return psp;
diff --git a/mesalib/src/mesa/drivers/dri/common/xmlconfig.c b/mesalib/src/mesa/drivers/dri/common/xmlconfig.c
index 5c97c20fc..b95e452f1 100644
--- a/mesalib/src/mesa/drivers/dri/common/xmlconfig.c
+++ b/mesalib/src/mesa/drivers/dri/common/xmlconfig.c
@@ -132,16 +132,6 @@ static GLuint findOption (const driOptionCache *cache, const char *name) {
return hash;
}
-/** \brief Count the real number of options in an option cache */
-static GLuint countOptions (const driOptionCache *cache) {
- GLuint size = 1 << cache->tableSize;
- GLuint i, count = 0;
- for (i = 0; i < size; ++i)
- if (cache->info[i].name)
- count++;
- return count;
-}
-
/** \brief Like strdup but using malloc and with error checking. */
#define XSTRDUP(dest,source) do { \
GLuint len = strlen (source); \
@@ -685,25 +675,18 @@ static void optInfoEndElem (void *userData, const XML_Char *name) {
}
}
-void driParseOptionInfo (driOptionCache *info,
- const char *configOptions, GLuint nConfigOptions) {
+void driParseOptionInfo (driOptionCache *info, const char *configOptions) {
XML_Parser p;
int status;
struct OptInfoData userData;
struct OptInfoData *data = &userData;
- GLuint realNoptions;
-
- /* determine hash table size and allocate memory:
- * 3/2 of the number of options, rounded up, so there remains always
- * at least one free entry. This is needed for detecting undefined
- * options in configuration files without getting a hash table overflow.
- * Round this up to a power of two. */
- GLuint minSize = (nConfigOptions*3 + 1) / 2;
- GLuint size, log2size;
- for (size = 1, log2size = 0; size < minSize; size <<= 1, ++log2size);
- info->tableSize = log2size;
- info->info = calloc(size, sizeof (driOptionInfo));
- info->values = calloc(size, sizeof (driOptionValue));
+
+ /* Make the hash table big enough to fit more than the maximum number of
+ * config options we've ever seen in a driver.
+ */
+ info->tableSize = 6;
+ info->info = calloc(1 << info->tableSize, sizeof (driOptionInfo));
+ info->values = calloc(1 << info->tableSize, sizeof (driOptionValue));
if (info->info == NULL || info->values == NULL) {
fprintf (stderr, "%s: %d: out of memory.\n", __FILE__, __LINE__);
abort();
@@ -728,17 +711,6 @@ void driParseOptionInfo (driOptionCache *info,
XML_FATAL ("%s.", XML_ErrorString(XML_GetErrorCode(p)));
XML_ParserFree (p);
-
- /* Check if the actual number of options matches nConfigOptions.
- * A mismatch is not fatal (a hash table overflow would be) but we
- * want the driver developer's attention anyway. */
- realNoptions = countOptions (info);
- if (realNoptions != nConfigOptions) {
- fprintf (stderr,
- "Error: nConfigOptions (%u) does not match the actual number of options in\n"
- " __driConfigOptions (%u).\n",
- nConfigOptions, realNoptions);
- }
}
/** \brief Parser context for configuration files. */
diff --git a/mesalib/src/mesa/drivers/dri/common/xmlconfig.h b/mesalib/src/mesa/drivers/dri/common/xmlconfig.h
index c363af764..d0ad42c19 100644
--- a/mesalib/src/mesa/drivers/dri/common/xmlconfig.h
+++ b/mesalib/src/mesa/drivers/dri/common/xmlconfig.h
@@ -76,7 +76,6 @@ typedef struct driOptionCache {
GLuint tableSize;
/**< \brief Size of the arrays
*
- * Depending on the hash function this may differ from __driNConfigOptions.
* In the current implementation it's not actually a size but log2(size).
* The value is the same in the screen and all contexts. */
} driOptionCache;
@@ -87,14 +86,13 @@ typedef struct driOptionCache {
*
* \param info pointer to a driOptionCache that will store the option info
* \param configOptions XML document describing available configuration opts
- * \param nConfigOptions number of options, used to choose a hash table size
*
* For the option information to be available to external configuration tools
* it must be a public symbol __driConfigOptions. It is also passed as a
* parameter to driParseOptionInfo in order to avoid driver-independent code
* depending on symbols in driver-specific code. */
void driParseOptionInfo (driOptionCache *info,
- const char *configOptions, GLuint nConfigOptions);
+ const char *configOptions);
/** \brief Initialize option cache from info and parse configuration files
*
* To be called in <driver>CreateContext. screenNum and driverName select
diff --git a/mesalib/src/mesa/main/api_validate.c b/mesalib/src/mesa/main/api_validate.c
index 7ab8e305d..243bb89d1 100644
--- a/mesalib/src/mesa/main/api_validate.c
+++ b/mesalib/src/mesa/main/api_validate.c
@@ -222,7 +222,7 @@ _mesa_is_valid_prim_mode(struct gl_context *ctx, GLenum mode)
case GL_LINE_STRIP_ADJACENCY:
case GL_TRIANGLES_ADJACENCY:
case GL_TRIANGLE_STRIP_ADJACENCY:
- return _mesa_is_desktop_gl(ctx) && ctx->Extensions.ARB_geometry_shader4;
+ return _mesa_has_geometry_shaders(ctx);
default:
return false;
}
@@ -245,6 +245,74 @@ _mesa_valid_prim_mode(struct gl_context *ctx, GLenum mode, const char *name)
return GL_FALSE;
}
+ /* From the ARB_geometry_shader4 spec:
+ *
+ * The error INVALID_OPERATION is generated if Begin, or any command that
+ * implicitly calls Begin, is called when a geometry shader is active and:
+ *
+ * * the input primitive type of the current geometry shader is
+ * POINTS and <mode> is not POINTS,
+ *
+ * * the input primitive type of the current geometry shader is
+ * LINES and <mode> is not LINES, LINE_STRIP, or LINE_LOOP,
+ *
+ * * the input primitive type of the current geometry shader is
+ * TRIANGLES and <mode> is not TRIANGLES, TRIANGLE_STRIP or
+ * TRIANGLE_FAN,
+ *
+ * * the input primitive type of the current geometry shader is
+ * LINES_ADJACENCY_ARB and <mode> is not LINES_ADJACENCY_ARB or
+ * LINE_STRIP_ADJACENCY_ARB, or
+ *
+ * * the input primitive type of the current geometry shader is
+ * TRIANGLES_ADJACENCY_ARB and <mode> is not
+ * TRIANGLES_ADJACENCY_ARB or TRIANGLE_STRIP_ADJACENCY_ARB.
+ *
+ */
+ if (ctx->Shader.CurrentGeometryProgram) {
+ const GLenum geom_mode =
+ ctx->Shader.CurrentGeometryProgram->Geom.InputType;
+ switch (mode) {
+ case GL_POINTS:
+ valid_enum = (geom_mode == GL_POINTS);
+ break;
+ case GL_LINES:
+ case GL_LINE_LOOP:
+ case GL_LINE_STRIP:
+ valid_enum = (geom_mode == GL_LINES);
+ break;
+ case GL_TRIANGLES:
+ case GL_TRIANGLE_STRIP:
+ case GL_TRIANGLE_FAN:
+ valid_enum = (geom_mode == GL_TRIANGLES);
+ break;
+ case GL_QUADS:
+ case GL_QUAD_STRIP:
+ case GL_POLYGON:
+ valid_enum = false;
+ break;
+ case GL_LINES_ADJACENCY:
+ case GL_LINE_STRIP_ADJACENCY:
+ valid_enum = (geom_mode == GL_LINES_ADJACENCY);
+ break;
+ case GL_TRIANGLES_ADJACENCY:
+ case GL_TRIANGLE_STRIP_ADJACENCY:
+ valid_enum = (geom_mode == GL_TRIANGLES_ADJACENCY);
+ break;
+ default:
+ valid_enum = false;
+ break;
+ }
+ if (!valid_enum) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "%s(mode=%s vs geometry shader input %s)",
+ name,
+ _mesa_lookup_prim_by_nr(mode),
+ _mesa_lookup_prim_by_nr(geom_mode));
+ return GL_FALSE;
+ }
+ }
+
/* From the GL_EXT_transform_feedback spec:
*
* "The error INVALID_OPERATION is generated if Begin, or any command
diff --git a/mesalib/src/mesa/main/context.h b/mesalib/src/mesa/main/context.h
index 8872be1f4..792ab4cd5 100644
--- a/mesalib/src/mesa/main/context.h
+++ b/mesalib/src/mesa/main/context.h
@@ -312,6 +312,17 @@ _mesa_is_gles3(const struct gl_context *ctx)
}
+/**
+ * Checks if the context supports geometry shaders.
+ */
+static inline GLboolean
+_mesa_has_geometry_shaders(const struct gl_context *ctx)
+{
+ return _mesa_is_desktop_gl(ctx) &&
+ (ctx->Version >= 32 || ctx->Extensions.ARB_geometry_shader4);
+}
+
+
#ifdef __cplusplus
}
#endif
diff --git a/mesalib/src/mesa/main/fbobject.c b/mesalib/src/mesa/main/fbobject.c
index bf7e85c88..1034c7a71 100644
--- a/mesalib/src/mesa/main/fbobject.c
+++ b/mesalib/src/mesa/main/fbobject.c
@@ -343,6 +343,28 @@ _mesa_remove_attachment(struct gl_context *ctx,
}
/**
+ * Verify a couple error conditions that will lead to an incomplete FBO and
+ * may cause problems for the driver's RenderTexture path.
+ */
+static bool
+driver_RenderTexture_is_safe(const struct gl_renderbuffer_attachment *att)
+{
+ const struct gl_texture_image *const texImage =
+ att->Texture->Image[att->CubeMapFace][att->TextureLevel];
+
+ if (texImage->Width == 0 || texImage->Height == 0 || texImage->Depth == 0)
+ return false;
+
+ if ((texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY
+ && att->Zoffset >= texImage->Height)
+ || (texImage->TexObject->Target != GL_TEXTURE_1D_ARRAY
+ && att->Zoffset >= texImage->Depth))
+ return false;
+
+ return true;
+}
+
+/**
* Create a renderbuffer which will be set up by the driver to wrap the
* texture image slice.
*
@@ -363,8 +385,6 @@ _mesa_update_texture_renderbuffer(struct gl_context *ctx,
struct gl_renderbuffer *rb;
texImage = att->Texture->Image[att->CubeMapFace][att->TextureLevel];
- if (!texImage)
- return;
rb = att->Renderbuffer;
if (!rb) {
@@ -383,6 +403,9 @@ _mesa_update_texture_renderbuffer(struct gl_context *ctx,
rb->NeedsFinishRenderTexture = ctx->Driver.FinishRenderTexture != NULL;
}
+ if (!texImage)
+ return;
+
rb->_BaseFormat = texImage->_BaseFormat;
rb->Format = texImage->TexFormat;
rb->InternalFormat = texImage->InternalFormat;
@@ -391,7 +414,8 @@ _mesa_update_texture_renderbuffer(struct gl_context *ctx,
rb->NumSamples = texImage->NumSamples;
rb->TexImage = texImage;
- ctx->Driver.RenderTexture(ctx, fb, att);
+ if (driver_RenderTexture_is_safe(att))
+ ctx->Driver.RenderTexture(ctx, fb, att);
}
/**
@@ -703,15 +727,39 @@ test_attachment_completeness(const struct gl_context *ctx, GLenum format,
}
if (texImage->Width < 1 || texImage->Height < 1) {
att_incomplete("teximage width/height=0");
- printf("texobj = %u\n", texObj->Name);
- printf("level = %d\n", att->TextureLevel);
att->Complete = GL_FALSE;
return;
}
- if (texObj->Target == GL_TEXTURE_3D && att->Zoffset >= texImage->Depth) {
- att_incomplete("bad z offset");
- att->Complete = GL_FALSE;
- return;
+
+ switch (texObj->Target) {
+ case GL_TEXTURE_3D:
+ if (att->Zoffset >= texImage->Depth) {
+ att_incomplete("bad z offset");
+ att->Complete = GL_FALSE;
+ return;
+ }
+ break;
+ case GL_TEXTURE_1D_ARRAY:
+ if (att->Zoffset >= texImage->Height) {
+ att_incomplete("bad 1D-array layer");
+ att->Complete = GL_FALSE;
+ return;
+ }
+ break;
+ case GL_TEXTURE_2D_ARRAY:
+ if (att->Zoffset >= texImage->Depth) {
+ att_incomplete("bad 2D-array layer");
+ att->Complete = GL_FALSE;
+ return;
+ }
+ break;
+ case GL_TEXTURE_CUBE_MAP_ARRAY:
+ if (att->Zoffset >= texImage->Depth) {
+ att_incomplete("bad cube-array layer");
+ att->Complete = GL_FALSE;
+ return;
+ }
+ break;
}
baseFormat = _mesa_get_format_base_format(texImage->TexFormat);
@@ -1104,8 +1152,8 @@ _mesa_IsRenderbuffer(GLuint renderbuffer)
}
-void GLAPIENTRY
-_mesa_BindRenderbuffer(GLenum target, GLuint renderbuffer)
+static void
+bind_renderbuffer(GLenum target, GLuint renderbuffer, bool allow_user_names)
{
struct gl_renderbuffer *newRb;
GET_CURRENT_CONTEXT(ctx);
@@ -1125,9 +1173,7 @@ _mesa_BindRenderbuffer(GLenum target, GLuint renderbuffer)
/* ID was reserved, but no real renderbuffer object made yet */
newRb = NULL;
}
- else if (!newRb
- && _mesa_is_desktop_gl(ctx)
- && ctx->Extensions.ARB_framebuffer_object) {
+ else if (!newRb && !allow_user_names) {
/* All RB IDs must be Gen'd */
_mesa_error(ctx, GL_INVALID_OPERATION, "glBindRenderbuffer(buffer)");
return;
@@ -1154,32 +1200,68 @@ _mesa_BindRenderbuffer(GLenum target, GLuint renderbuffer)
_mesa_reference_renderbuffer(&ctx->CurrentRenderbuffer, newRb);
}
+void GLAPIENTRY
+_mesa_BindRenderbuffer(GLenum target, GLuint renderbuffer)
+{
+ GET_CURRENT_CONTEXT(ctx);
+
+ /* OpenGL ES glBindRenderbuffer and glBindRenderbufferOES use this same
+ * entry point, but they allow the use of user-generated names.
+ */
+ bind_renderbuffer(target, renderbuffer, _mesa_is_gles(ctx));
+}
void GLAPIENTRY
_mesa_BindRenderbufferEXT(GLenum target, GLuint renderbuffer)
{
- _mesa_BindRenderbuffer(target, renderbuffer);
+ /* This function should not be in the dispatch table for core profile /
+ * OpenGL 3.1, so execution should never get here in those cases -- no
+ * need for an explicit test.
+ */
+ bind_renderbuffer(target, renderbuffer, true);
}
/**
- * If the given renderbuffer is anywhere attached to the framebuffer, detach
- * the renderbuffer.
- * This is used when a renderbuffer object is deleted.
- * The spec calls for unbinding.
+ * Remove the specified renderbuffer or texture from any attachment point in
+ * the framebuffer.
+ *
+ * \returns
+ * \c true if the renderbuffer was detached from an attachment point. \c
+ * false otherwise.
*/
-static void
-detach_renderbuffer(struct gl_context *ctx,
- struct gl_framebuffer *fb,
- struct gl_renderbuffer *rb)
+bool
+_mesa_detach_renderbuffer(struct gl_context *ctx,
+ struct gl_framebuffer *fb,
+ const void *att)
{
- GLuint i;
+ unsigned i;
+ bool progress = false;
+
for (i = 0; i < BUFFER_COUNT; i++) {
- if (fb->Attachment[i].Renderbuffer == rb) {
+ if (fb->Attachment[i].Texture == att
+ || fb->Attachment[i].Renderbuffer == att) {
_mesa_remove_attachment(ctx, &fb->Attachment[i]);
+ progress = true;
}
}
- invalidate_framebuffer(fb);
+
+ /* Section 4.4.4 (Framebuffer Completeness), subsection "Whole Framebuffer
+ * Completeness," of the OpenGL 3.1 spec says:
+ *
+ * "Performing any of the following actions may change whether the
+ * framebuffer is considered complete or incomplete:
+ *
+ * ...
+ *
+ * - Deleting, with DeleteTextures or DeleteRenderbuffers, an object
+ * containing an image that is attached to a framebuffer object
+ * that is bound to the framebuffer."
+ */
+ if (progress)
+ invalidate_framebuffer(fb);
+
+ return progress;
}
@@ -1203,12 +1285,29 @@ _mesa_DeleteRenderbuffers(GLsizei n, const GLuint *renderbuffers)
_mesa_BindRenderbuffer(GL_RENDERBUFFER_EXT, 0);
}
+ /* Section 4.4.2 (Attaching Images to Framebuffer Objects),
+ * subsection "Attaching Renderbuffer Images to a Framebuffer," of
+ * the OpenGL 3.1 spec says:
+ *
+ * "If a renderbuffer object is deleted while its image is
+ * attached to one or more attachment points in the currently
+ * bound framebuffer, then it is as if FramebufferRenderbuffer
+ * had been called, with a renderbuffer of 0, for each
+ * attachment point to which this image was attached in the
+ * currently bound framebuffer. In other words, this
+ * renderbuffer image is first detached from all attachment
+ * points in the currently bound framebuffer. Note that the
+ * renderbuffer image is specifically not detached from any
+ * non-bound framebuffers. Detaching the image from any
+ * non-bound framebuffers is the responsibility of the
+ * application.
+ */
if (_mesa_is_user_fbo(ctx->DrawBuffer)) {
- detach_renderbuffer(ctx, ctx->DrawBuffer, rb);
+ _mesa_detach_renderbuffer(ctx, ctx->DrawBuffer, rb);
}
if (_mesa_is_user_fbo(ctx->ReadBuffer)
&& ctx->ReadBuffer != ctx->DrawBuffer) {
- detach_renderbuffer(ctx, ctx->ReadBuffer, rb);
+ _mesa_detach_renderbuffer(ctx, ctx->ReadBuffer, rb);
}
/* Remove from hash table immediately, to free the ID.
@@ -1875,7 +1974,8 @@ check_begin_texture_render(struct gl_context *ctx, struct gl_framebuffer *fb)
for (i = 0; i < BUFFER_COUNT; i++) {
struct gl_renderbuffer_attachment *att = fb->Attachment + i;
- if (att->Texture && att->Renderbuffer->TexImage) {
+ if (att->Texture && att->Renderbuffer->TexImage
+ && driver_RenderTexture_is_safe(att)) {
ctx->Driver.RenderTexture(ctx, fb, att);
}
}
@@ -1906,8 +2006,8 @@ check_end_texture_render(struct gl_context *ctx, struct gl_framebuffer *fb)
}
-void GLAPIENTRY
-_mesa_BindFramebuffer(GLenum target, GLuint framebuffer)
+static void
+bind_framebuffer(GLenum target, GLuint framebuffer, bool allow_user_names)
{
struct gl_framebuffer *newDrawFb, *newReadFb;
struct gl_framebuffer *oldDrawFb, *oldReadFb;
@@ -1953,9 +2053,7 @@ _mesa_BindFramebuffer(GLenum target, GLuint framebuffer)
/* ID was reserved, but no real framebuffer object made yet */
newDrawFb = NULL;
}
- else if (!newDrawFb
- && _mesa_is_desktop_gl(ctx)
- && ctx->Extensions.ARB_framebuffer_object) {
+ else if (!newDrawFb && !allow_user_names) {
/* All FBO IDs must be Gen'd */
_mesa_error(ctx, GL_INVALID_OPERATION, "glBindFramebuffer(buffer)");
return;
@@ -2033,12 +2131,25 @@ _mesa_BindFramebuffer(GLenum target, GLuint framebuffer)
}
void GLAPIENTRY
-_mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer)
+_mesa_BindFramebuffer(GLenum target, GLuint framebuffer)
{
- _mesa_BindFramebuffer(target, framebuffer);
-}
+ GET_CURRENT_CONTEXT(ctx);
+ /* OpenGL ES glBindFramebuffer and glBindFramebufferOES use this same entry
+ * point, but they allow the use of user-generated names.
+ */
+ bind_framebuffer(target, framebuffer, _mesa_is_gles(ctx));
+}
+void GLAPIENTRY
+_mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer)
+{
+ /* This function should not be in the dispatch table for core profile /
+ * OpenGL 3.1, so execution should never get here in those cases -- no
+ * need for an explicit test.
+ */
+ bind_framebuffer(target, framebuffer, true);
+}
void GLAPIENTRY
_mesa_DeleteFramebuffers(GLsizei n, const GLuint *framebuffers)
@@ -2476,7 +2587,7 @@ _mesa_FramebufferTexture(GLenum target, GLenum attachment,
{
GET_CURRENT_CONTEXT(ctx);
- if (ctx->Version >= 32 || ctx->Extensions.ARB_geometry_shader4) {
+ if (_mesa_has_geometry_shaders(ctx)) {
framebuffer_texture(ctx, "Layer", target, attachment, 0, texture,
level, 0, GL_TRUE);
} else {
diff --git a/mesalib/src/mesa/main/fbobject.h b/mesalib/src/mesa/main/fbobject.h
index 0a2a5cc59..ab138cfff 100644
--- a/mesalib/src/mesa/main/fbobject.h
+++ b/mesalib/src/mesa/main/fbobject.h
@@ -28,6 +28,7 @@
#include "compiler.h"
#include "glheader.h"
+#include <stdbool.h>
struct gl_context;
struct gl_texture_object;
@@ -113,6 +114,11 @@ _mesa_is_legal_color_format(const struct gl_context *ctx, GLenum baseFormat);
extern GLenum
_mesa_base_fbo_format(struct gl_context *ctx, GLenum internalFormat);
+extern bool
+_mesa_detach_renderbuffer(struct gl_context *ctx,
+ struct gl_framebuffer *fb,
+ const void *att);
+
extern GLboolean GLAPIENTRY
_mesa_IsRenderbuffer(GLuint renderbuffer);
diff --git a/mesalib/src/mesa/main/get.c b/mesalib/src/mesa/main/get.c
index 0b33fa49b..09b008a07 100644
--- a/mesalib/src/mesa/main/get.c
+++ b/mesalib/src/mesa/main/get.c
@@ -989,7 +989,7 @@ check_extra(struct gl_context *ctx, const char *func, const struct value_desc *d
case EXTRA_EXT_UBO_GS4:
api_check = GL_TRUE;
api_found = (ctx->Extensions.ARB_uniform_buffer_object &&
- ctx->Extensions.ARB_geometry_shader4);
+ _mesa_has_geometry_shaders(ctx));
break;
case EXTRA_END:
break;
diff --git a/mesalib/src/mesa/main/lines.c b/mesalib/src/mesa/main/lines.c
index 0df9d66b0..3c08ed2e7 100644
--- a/mesalib/src/mesa/main/lines.c
+++ b/mesalib/src/mesa/main/lines.c
@@ -62,7 +62,8 @@ _mesa_LineWidth( GLfloat width )
*/
if (ctx->API == API_OPENGL_CORE
&& ((ctx->Const.ContextFlags & GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT)
- != 0)) {
+ != 0)
+ && width > 1.0) {
_mesa_error( ctx, GL_INVALID_VALUE, "glLineWidth" );
return;
}
diff --git a/mesalib/src/mesa/main/mtypes.h b/mesalib/src/mesa/main/mtypes.h
index 5bb680745..5f9b7f983 100644
--- a/mesalib/src/mesa/main/mtypes.h
+++ b/mesalib/src/mesa/main/mtypes.h
@@ -1152,31 +1152,32 @@ struct gl_sampler_object
*/
struct gl_texture_object
{
- _glthread_Mutex Mutex; /**< for thread safety */
- GLint RefCount; /**< reference count */
- GLuint Name; /**< the user-visible texture object ID */
- GLenum Target; /**< GL_TEXTURE_1D, GL_TEXTURE_2D, etc. */
+ _glthread_Mutex Mutex; /**< for thread safety */
+ GLint RefCount; /**< reference count */
+ GLuint Name; /**< the user-visible texture object ID */
+ GLenum Target; /**< GL_TEXTURE_1D, GL_TEXTURE_2D, etc. */
struct gl_sampler_object Sampler;
- GLenum DepthMode; /**< GL_ARB_depth_texture */
-
- GLfloat Priority; /**< in [0,1] */
- GLint BaseLevel; /**< min mipmap level, OpenGL 1.2 */
- GLint MaxLevel; /**< max mipmap level, OpenGL 1.2 */
- GLint ImmutableLevels; /**< ES 3.0 / ARB_texture_view */
- GLint _MaxLevel; /**< actual max mipmap level (q in the spec) */
- GLfloat _MaxLambda; /**< = _MaxLevel - BaseLevel (q - b in spec) */
- GLint CropRect[4]; /**< GL_OES_draw_texture */
- GLenum Swizzle[4]; /**< GL_EXT_texture_swizzle */
- GLuint _Swizzle; /**< same as Swizzle, but SWIZZLE_* format */
- GLboolean GenerateMipmap; /**< GL_SGIS_generate_mipmap */
- GLboolean _BaseComplete; /**< Is the base texture level valid? */
- GLboolean _MipmapComplete; /**< Is the whole mipmap valid? */
- GLboolean _IsIntegerFormat; /**< Does the texture store integer values? */
- GLboolean _RenderToTexture; /**< Any rendering to this texture? */
- GLboolean Purgeable; /**< Is the buffer purgeable under memory pressure? */
- GLboolean Immutable; /**< GL_ARB_texture_storage */
+ GLenum DepthMode; /**< GL_ARB_depth_texture */
+
+ GLfloat Priority; /**< in [0,1] */
+ GLint BaseLevel; /**< min mipmap level, OpenGL 1.2 */
+ GLint MaxLevel; /**< max mipmap level, OpenGL 1.2 */
+ GLint ImmutableLevels; /**< ES 3.0 / ARB_texture_view */
+ GLint _MaxLevel; /**< actual max mipmap level (q in the spec) */
+ GLfloat _MaxLambda; /**< = _MaxLevel - BaseLevel (q - p in spec) */
+ GLint CropRect[4]; /**< GL_OES_draw_texture */
+ GLenum Swizzle[4]; /**< GL_EXT_texture_swizzle */
+ GLuint _Swizzle; /**< same as Swizzle, but SWIZZLE_* format */
+ GLboolean GenerateMipmap; /**< GL_SGIS_generate_mipmap */
+ GLboolean _BaseComplete; /**< Is the base texture level valid? */
+ GLboolean _MipmapComplete; /**< Is the whole mipmap valid? */
+ GLboolean _IsIntegerFormat; /**< Does the texture store integer values? */
+ GLboolean _RenderToTexture; /**< Any rendering to this texture? */
+ GLboolean Purgeable; /**< Is the buffer purgeable under memory
+ pressure? */
+ GLboolean Immutable; /**< GL_ARB_texture_storage */
/** Actual texture images, indexed by [cube face] and [mipmap level] */
struct gl_texture_image *Image[MAX_FACES][MAX_TEXTURE_LEVELS];
@@ -1851,7 +1852,7 @@ struct gl_program
GLuint Id;
GLubyte *String; /**< Null-terminated program text */
GLint RefCount;
- GLenum Target; /**< GL_VERTEX/FRAGMENT_PROGRAM_ARB */
+ GLenum Target; /**< GL_VERTEX/FRAGMENT_PROGRAM_ARB, GL_GEOMETRY_PROGRAM_NV */
GLenum Format; /**< String encoding format */
struct prog_instruction *Instructions;
@@ -1918,6 +1919,7 @@ struct gl_geometry_program
{
struct gl_program Base; /**< base class */
+ GLint VerticesIn;
GLint VerticesOut;
GLenum InputType; /**< GL_POINTS, GL_LINES, GL_LINES_ADJACENCY_ARB,
GL_TRIANGLES, or GL_TRIANGLES_ADJACENCY_ARB */
@@ -2169,6 +2171,24 @@ struct gl_shader
/** Shaders containing built-in functions that are used for linking. */
struct gl_shader *builtins_to_link[16];
unsigned num_builtins_to_link;
+
+ /**
+ * Geometry shader state from GLSL 1.50 layout qualifiers.
+ */
+ struct {
+ GLint VerticesOut;
+ /**
+ * GL_POINTS, GL_LINES, GL_LINES_ADJACENCY, GL_TRIANGLES, or
+ * GL_TRIANGLES_ADJACENCY, or PRIM_UNKNOWN if it's not set in this
+ * shader.
+ */
+ GLenum InputType;
+ /**
+ * GL_POINTS, GL_LINE_STRIP or GL_TRIANGLE_STRIP, or PRIM_UNKNOWN if
+ * it's not set in this shader.
+ */
+ GLenum OutputType;
+ } Geom;
};
@@ -2318,17 +2338,25 @@ struct gl_shader_program
/** Post-link gl_FragDepth layout for ARB_conservative_depth. */
enum gl_frag_depth_layout FragDepthLayout;
- /** Geometry shader state - copied into gl_geometry_program at link time */
+ /**
+ * Geometry shader state - copied into gl_geometry_program by
+ * _mesa_copy_linked_program_data().
+ */
struct {
+ GLint VerticesIn;
GLint VerticesOut;
GLenum InputType; /**< GL_POINTS, GL_LINES, GL_LINES_ADJACENCY_ARB,
GL_TRIANGLES, or GL_TRIANGLES_ADJACENCY_ARB */
GLenum OutputType; /**< GL_POINTS, GL_LINE_STRIP or GL_TRIANGLE_STRIP */
} Geom;
- /** Vertex shader state - copied into gl_vertex_program at link time */
+ /** Vertex shader state */
struct {
- GLboolean UsesClipDistance; /**< True if gl_ClipDistance is written to. */
+ /**
+ * True if gl_ClipDistance is written to. Copied into gl_vertex_program
+ * by _mesa_copy_linked_program_data().
+ */
+ GLboolean UsesClipDistance;
GLuint ClipDistanceArraySize; /**< Size of the gl_ClipDistance array, or
0 if not present. */
} Vert;
diff --git a/mesalib/src/mesa/main/shaderapi.c b/mesalib/src/mesa/main/shaderapi.c
index c349b0cb5..d184b114c 100644
--- a/mesalib/src/mesa/main/shaderapi.c
+++ b/mesalib/src/mesa/main/shaderapi.c
@@ -179,7 +179,7 @@ validate_shader_target(const struct gl_context *ctx, GLenum type)
case GL_VERTEX_SHADER:
return ctx->Extensions.ARB_vertex_shader;
case GL_GEOMETRY_SHADER_ARB:
- return _mesa_is_desktop_gl(ctx) && ctx->Extensions.ARB_geometry_shader4;
+ return _mesa_has_geometry_shaders(ctx);
default:
return false;
}
@@ -478,8 +478,7 @@ get_programiv(struct gl_context *ctx, GLuint program, GLenum pname, GLint *param
/* Are geometry shaders available in this context?
*/
- const bool has_gs =
- _mesa_is_desktop_gl(ctx) && ctx->Extensions.ARB_geometry_shader4;
+ const bool has_gs = _mesa_has_geometry_shaders(ctx);
/* Are uniform buffer objects available in this context?
*/
@@ -743,6 +742,12 @@ compile_shader(struct gl_context *ctx, GLuint shaderObj)
if (!sh)
return;
+ /* Geometry shaders are not yet fully supported, so issue a warning message
+ * if we're compiling one.
+ */
+ if (sh->Type == GL_GEOMETRY_SHADER)
+ printf("WARNING: Geometry shader support is currently experimental.\n");
+
options = &ctx->ShaderCompilerOptions[_mesa_shader_type_to_index(sh->Type)];
/* set default pragma state for shader */
@@ -1635,10 +1640,10 @@ _mesa_ProgramParameteri(GLuint program, GLenum pname, GLint value)
if (!_mesa_is_desktop_gl(ctx) || !ctx->Extensions.ARB_geometry_shader4)
break;
- if (value < 1 ||
+ if (value < 0 ||
(unsigned) value > ctx->Const.MaxGeometryOutputVertices) {
_mesa_error(ctx, GL_INVALID_VALUE,
- "glProgramParameteri(GL_GEOMETRY_VERTICES_OUT_ARB=%d",
+ "glProgramParameteri(GL_GEOMETRY_VERTICES_OUT_ARB=%d)",
value);
return;
}
@@ -1658,7 +1663,7 @@ _mesa_ProgramParameteri(GLuint program, GLenum pname, GLint value)
break;
default:
_mesa_error(ctx, GL_INVALID_VALUE,
- "glProgramParameteri(geometry input type = %s",
+ "glProgramParameteri(geometry input type = %s)",
_mesa_lookup_enum_by_nr(value));
return;
}
@@ -1675,7 +1680,7 @@ _mesa_ProgramParameteri(GLuint program, GLenum pname, GLint value)
break;
default:
_mesa_error(ctx, GL_INVALID_VALUE,
- "glProgramParameteri(geometry output type = %s",
+ "glProgramParameteri(geometry output type = %s)",
_mesa_lookup_enum_by_nr(value));
return;
}
@@ -1843,3 +1848,32 @@ _mesa_CreateShaderProgramEXT(GLenum type, const GLchar *string)
return program;
}
+
+
+/**
+ * Copy program-specific data generated by linking from the gl_shader_program
+ * object to a specific gl_program object.
+ */
+void
+_mesa_copy_linked_program_data(gl_shader_type type,
+ const struct gl_shader_program *src,
+ struct gl_program *dst)
+{
+ switch (type) {
+ case MESA_SHADER_VERTEX: {
+ struct gl_vertex_program *dst_vp = (struct gl_vertex_program *) dst;
+ dst_vp->UsesClipDistance = src->Vert.UsesClipDistance;
+ }
+ break;
+ case MESA_SHADER_GEOMETRY: {
+ struct gl_geometry_program *dst_gp = (struct gl_geometry_program *) dst;
+ dst_gp->VerticesIn = src->Geom.VerticesIn;
+ dst_gp->VerticesOut = src->Geom.VerticesOut;
+ dst_gp->InputType = src->Geom.InputType;
+ dst_gp->OutputType = src->Geom.OutputType;
+ }
+ break;
+ default:
+ break;
+ }
+}
diff --git a/mesalib/src/mesa/main/shaderapi.h b/mesalib/src/mesa/main/shaderapi.h
index 1cd4ffcea..fe58e7de9 100644
--- a/mesalib/src/mesa/main/shaderapi.h
+++ b/mesalib/src/mesa/main/shaderapi.h
@@ -210,6 +210,11 @@ _mesa_ActiveProgramEXT(GLuint program);
extern GLuint GLAPIENTRY
_mesa_CreateShaderProgramEXT(GLenum type, const GLchar *string);
+extern void
+_mesa_copy_linked_program_data(gl_shader_type type,
+ const struct gl_shader_program *src,
+ struct gl_program *dst);
+
#ifdef __cplusplus
}
diff --git a/mesalib/src/mesa/main/shared.c b/mesalib/src/mesa/main/shared.c
index 5ef88098f..2f73cf3ca 100644
--- a/mesalib/src/mesa/main/shared.c
+++ b/mesalib/src/mesa/main/shared.c
@@ -218,7 +218,8 @@ delete_shader_cb(GLuint id, void *data, void *userData)
{
struct gl_context *ctx = (struct gl_context *) userData;
struct gl_shader *sh = (struct gl_shader *) data;
- if (sh->Type == GL_FRAGMENT_SHADER || sh->Type == GL_VERTEX_SHADER) {
+ if (sh->Type == GL_FRAGMENT_SHADER || sh->Type == GL_VERTEX_SHADER ||
+ sh->Type == GL_GEOMETRY_SHADER) {
ctx->Driver.DeleteShader(ctx, sh);
}
else {
diff --git a/mesalib/src/mesa/main/texobj.c b/mesalib/src/mesa/main/texobj.c
index 334dee77b..7c8f04db9 100644
--- a/mesalib/src/mesa/main/texobj.c
+++ b/mesalib/src/mesa/main/texobj.c
@@ -548,12 +548,13 @@ _mesa_test_texobj_completeness( const struct gl_context *ctx,
ASSERT(maxLevels > 0);
- t->_MaxLevel =
- baseLevel + baseImage->MaxNumLevels - 1; /* 'p' in the GL spec */
- t->_MaxLevel = MIN2(t->_MaxLevel, t->MaxLevel);
- t->_MaxLevel = MIN2(t->_MaxLevel, maxLevels - 1); /* 'q' in the GL spec */
+ t->_MaxLevel = MIN3(t->MaxLevel,
+ /* 'p' in the GL spec */
+ baseLevel + baseImage->MaxNumLevels - 1,
+ /* 'q' in the GL spec */
+ maxLevels - 1);
- /* Compute _MaxLambda = q - b (see the 1.2 spec) used during mipmapping */
+ /* Compute _MaxLambda = q - p in the spec used during mipmapping */
t->_MaxLambda = (GLfloat) (t->_MaxLevel - baseLevel);
if (t->Immutable) {
@@ -1040,23 +1041,35 @@ static void
unbind_texobj_from_fbo(struct gl_context *ctx,
struct gl_texture_object *texObj)
{
- const GLuint n = (ctx->DrawBuffer == ctx->ReadBuffer) ? 1 : 2;
- GLuint i;
+ bool progress = false;
- for (i = 0; i < n; i++) {
- struct gl_framebuffer *fb = (i == 0) ? ctx->DrawBuffer : ctx->ReadBuffer;
- if (_mesa_is_user_fbo(fb)) {
- GLuint j;
- for (j = 0; j < BUFFER_COUNT; j++) {
- if (fb->Attachment[j].Type == GL_TEXTURE &&
- fb->Attachment[j].Texture == texObj) {
- /* Vertices are already flushed by _mesa_DeleteTextures */
- ctx->NewState |= _NEW_BUFFERS;
- _mesa_remove_attachment(ctx, fb->Attachment + j);
- }
- }
- }
+ /* Section 4.4.2 (Attaching Images to Framebuffer Objects), subsection
+ * "Attaching Texture Images to a Framebuffer," of the OpenGL 3.1 spec
+ * says:
+ *
+ * "If a texture object is deleted while its image is attached to one
+ * or more attachment points in the currently bound framebuffer, then
+ * it is as if FramebufferTexture* had been called, with a texture of
+ * zero, for each attachment point to which this image was attached in
+ * the currently bound framebuffer. In other words, this texture image
+ * is first detached from all attachment points in the currently bound
+ * framebuffer. Note that the texture image is specifically not
+ * detached from any other framebuffer objects. Detaching the texture
+ * image from any other framebuffer objects is the responsibility of
+ * the application."
+ */
+ if (_mesa_is_user_fbo(ctx->DrawBuffer)) {
+ progress = _mesa_detach_renderbuffer(ctx, ctx->DrawBuffer, texObj);
}
+ if (_mesa_is_user_fbo(ctx->ReadBuffer)
+ && ctx->ReadBuffer != ctx->DrawBuffer) {
+ progress = _mesa_detach_renderbuffer(ctx, ctx->ReadBuffer, texObj)
+ || progress;
+ }
+
+ if (progress)
+ /* Vertices are already flushed by _mesa_DeleteTextures */
+ ctx->NewState |= _NEW_BUFFERS;
}
diff --git a/mesalib/src/mesa/main/texparam.c b/mesalib/src/mesa/main/texparam.c
index 32109951c..757ae80ec 100644
--- a/mesalib/src/mesa/main/texparam.c
+++ b/mesalib/src/mesa/main/texparam.c
@@ -386,7 +386,13 @@ set_tex_parameteri(struct gl_context *ctx,
return GL_FALSE;
}
incomplete(ctx, texObj);
- texObj->BaseLevel = params[0];
+
+ /** See note about ARB_texture_storage below */
+ if (texObj->Immutable)
+ texObj->BaseLevel = MIN2(texObj->ImmutableLevels - 1, params[0]);
+ else
+ texObj->BaseLevel = params[0];
+
return GL_TRUE;
case GL_TEXTURE_MAX_LEVEL:
@@ -399,7 +405,19 @@ set_tex_parameteri(struct gl_context *ctx,
return GL_FALSE;
}
incomplete(ctx, texObj);
- texObj->MaxLevel = params[0];
+
+ /** From ARB_texture_storage:
+ * However, if TEXTURE_IMMUTABLE_FORMAT is TRUE, then level_base is
+ * clamped to the range [0, <levels> - 1] and level_max is then clamped to
+ * the range [level_base, <levels> - 1], where <levels> is the parameter
+ * passed the call to TexStorage* for the texture object.
+ */
+ if (texObj->Immutable)
+ texObj->MaxLevel = CLAMP(params[0], texObj->BaseLevel,
+ texObj->ImmutableLevels - 1);
+ else
+ texObj->MaxLevel = params[0];
+
return GL_TRUE;
case GL_GENERATE_MIPMAP_SGIS:
diff --git a/mesalib/src/mesa/main/texstate.c b/mesalib/src/mesa/main/texstate.c
index afff01359..dad69a8f6 100644
--- a/mesalib/src/mesa/main/texstate.c
+++ b/mesalib/src/mesa/main/texstate.c
@@ -528,6 +528,7 @@ update_texture_state( struct gl_context *ctx )
GLuint unit;
struct gl_program *fprog = NULL;
struct gl_program *vprog = NULL;
+ struct gl_program *gprog = NULL;
GLbitfield enabledFragUnits = 0x0;
if (ctx->Shader.CurrentVertexProgram &&
@@ -535,6 +536,11 @@ update_texture_state( struct gl_context *ctx )
vprog = ctx->Shader.CurrentVertexProgram->_LinkedShaders[MESA_SHADER_VERTEX]->Program;
}
+ if (ctx->Shader.CurrentGeometryProgram &&
+ ctx->Shader.CurrentGeometryProgram->LinkStatus) {
+ gprog = ctx->Shader.CurrentGeometryProgram->_LinkedShaders[MESA_SHADER_GEOMETRY]->Program;
+ }
+
if (ctx->Shader.CurrentFragmentProgram &&
ctx->Shader.CurrentFragmentProgram->LinkStatus) {
fprog = ctx->Shader.CurrentFragmentProgram->_LinkedShaders[MESA_SHADER_FRAGMENT]->Program;
@@ -543,10 +549,6 @@ update_texture_state( struct gl_context *ctx )
fprog = &ctx->FragmentProgram.Current->Base;
}
- /* FINISHME: Geometry shader texture accesses should also be considered
- * FINISHME: here.
- */
-
/* TODO: only set this if there are actual changes */
ctx->NewState |= _NEW_TEXTURE;
@@ -562,6 +564,7 @@ update_texture_state( struct gl_context *ctx )
struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
GLbitfield enabledVertTargets = 0x0;
GLbitfield enabledFragTargets = 0x0;
+ GLbitfield enabledGeomTargets = 0x0;
GLbitfield enabledTargets = 0x0;
GLuint texIndex;
@@ -575,6 +578,10 @@ update_texture_state( struct gl_context *ctx )
enabledVertTargets |= vprog->TexturesUsed[unit];
}
+ if (gprog) {
+ enabledGeomTargets |= gprog->TexturesUsed[unit];
+ }
+
if (fprog) {
enabledFragTargets |= fprog->TexturesUsed[unit];
}
@@ -583,7 +590,8 @@ update_texture_state( struct gl_context *ctx )
enabledFragTargets |= texUnit->Enabled;
}
- enabledTargets = enabledVertTargets | enabledFragTargets;
+ enabledTargets = enabledVertTargets | enabledFragTargets |
+ enabledGeomTargets;
texUnit->_ReallyEnabled = 0x0;
diff --git a/mesalib/src/mesa/main/varray.c b/mesalib/src/mesa/main/varray.c
index 529d93324..dee476abb 100644
--- a/mesalib/src/mesa/main/varray.c
+++ b/mesalib/src/mesa/main/varray.c
@@ -196,6 +196,16 @@ update_array(struct gl_context *ctx,
if (ctx->Extensions.EXT_vertex_array_bgra &&
sizeMax == BGRA_OR_4 &&
size == GL_BGRA) {
+ /* Page 298 of the PDF of the OpenGL 4.3 (Core Profile) spec says:
+ *
+ * "An INVALID_OPERATION error is generated under any of the following
+ * conditions:
+ * ...
+ * • size is BGRA and type is not UNSIGNED_BYTE, INT_2_10_10_10_REV
+ * or UNSIGNED_INT_2_10_10_10_REV;
+ * ...
+ * • size is BGRA and normalized is FALSE;"
+ */
GLboolean bgra_error = GL_FALSE;
if (ctx->Extensions.ARB_vertex_type_2_10_10_10_rev) {
@@ -207,9 +217,17 @@ update_array(struct gl_context *ctx,
bgra_error = GL_TRUE;
if (bgra_error) {
- _mesa_error(ctx, GL_INVALID_VALUE, "%s(GL_BGRA/GLubyte)", func);
+ _mesa_error(ctx, GL_INVALID_OPERATION, "%s(size=GL_BGRA and type=%s)",
+ func, _mesa_lookup_enum_by_nr(type));
return;
}
+
+ if (!normalized) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "%s(size=GL_BGRA and normalized=GL_FALSE)", func);
+ return;
+ }
+
format = GL_BGRA;
size = 4;
}
diff --git a/mesalib/src/mesa/main/version.c b/mesalib/src/mesa/main/version.c
index abcf90eec..ee77947b4 100644
--- a/mesalib/src/mesa/main/version.c
+++ b/mesalib/src/mesa/main/version.c
@@ -262,7 +262,6 @@ compute_version(struct gl_context *ctx)
ctx->Extensions.ARB_depth_clamp &&
ctx->Extensions.ARB_draw_elements_base_vertex &&
ctx->Extensions.ARB_fragment_coord_conventions &&
- ctx->Extensions.ARB_geometry_shader4 &&
ctx->Extensions.EXT_provoking_vertex &&
ctx->Extensions.ARB_seamless_cube_map &&
ctx->Extensions.ARB_sync &&
diff --git a/mesalib/src/mesa/program/ir_to_mesa.cpp b/mesalib/src/mesa/program/ir_to_mesa.cpp
index f0fc1b9b1..f612f41ba 100644
--- a/mesalib/src/mesa/program/ir_to_mesa.cpp
+++ b/mesalib/src/mesa/program/ir_to_mesa.cpp
@@ -265,6 +265,8 @@ public:
virtual void visit(ir_discard *);
virtual void visit(ir_texture *);
virtual void visit(ir_if *);
+ virtual void visit(ir_emit_vertex *);
+ virtual void visit(ir_end_primitive *);
/*@}*/
src_reg result;
@@ -2252,6 +2254,18 @@ ir_to_mesa_visitor::visit(ir_if *ir)
if_inst = emit(ir->condition, OPCODE_ENDIF);
}
+void
+ir_to_mesa_visitor::visit(ir_emit_vertex *ir)
+{
+ assert(!"Geometry shaders not supported.");
+}
+
+void
+ir_to_mesa_visitor::visit(ir_end_primitive *ir)
+{
+ assert(!"Geometry shaders not supported.");
+}
+
ir_to_mesa_visitor::ir_to_mesa_visitor()
{
result.file = PROGRAM_UNDEFINED;
@@ -2961,7 +2975,7 @@ get_mesa_program(struct gl_context *ctx,
*/
mesa_instructions = NULL;
- do_set_program_inouts(shader->ir, prog, shader->Type == GL_FRAGMENT_SHADER);
+ do_set_program_inouts(shader->ir, prog, shader->Type);
prog->SamplersUsed = shader->active_samplers;
prog->ShadowSamplers = shader->shadow_samplers;
@@ -3073,10 +3087,7 @@ _mesa_ir_link_shader(struct gl_context *ctx, struct gl_shader_program *prog)
linked_prog = get_mesa_program(ctx, prog, prog->_LinkedShaders[i]);
if (linked_prog) {
- if (i == MESA_SHADER_VERTEX) {
- ((struct gl_vertex_program *)linked_prog)->UsesClipDistance
- = prog->Vert.UsesClipDistance;
- }
+ _mesa_copy_linked_program_data((gl_shader_type) i, prog, linked_prog);
_mesa_reference_program(ctx, &prog->_LinkedShaders[i]->Program,
linked_prog);
diff --git a/mesalib/src/mesa/state_tracker/st_glsl_to_tgsi.cpp b/mesalib/src/mesa/state_tracker/st_glsl_to_tgsi.cpp
index 3dfd5e5b3..4e29e4500 100644
--- a/mesalib/src/mesa/state_tracker/st_glsl_to_tgsi.cpp
+++ b/mesalib/src/mesa/state_tracker/st_glsl_to_tgsi.cpp
@@ -369,6 +369,8 @@ public:
virtual void visit(ir_discard *);
virtual void visit(ir_texture *);
virtual void visit(ir_if *);
+ virtual void visit(ir_emit_vertex *);
+ virtual void visit(ir_end_primitive *);
/*@}*/
st_src_reg result;
@@ -418,8 +420,6 @@ public:
void emit_scalar(ir_instruction *ir, unsigned op,
st_dst_reg dst, st_src_reg src0, st_src_reg src1);
- void try_emit_float_set(ir_instruction *ir, unsigned op, st_dst_reg dst);
-
void emit_arl(ir_instruction *ir, st_dst_reg dst, st_src_reg src0);
void emit_scs(ir_instruction *ir, unsigned op,
@@ -592,9 +592,6 @@ glsl_to_tgsi_visitor::emit(ir_instruction *ir, unsigned op,
this->instructions.push_tail(inst);
- if (native_integers)
- try_emit_float_set(ir, op, dst);
-
return inst;
}
@@ -620,25 +617,6 @@ glsl_to_tgsi_visitor::emit(ir_instruction *ir, unsigned op)
return emit(ir, op, undef_dst, undef_src, undef_src, undef_src);
}
- /**
- * Emits the code to convert the result of float SET instructions to integers.
- */
-void
-glsl_to_tgsi_visitor::try_emit_float_set(ir_instruction *ir, unsigned op,
- st_dst_reg dst)
-{
- if ((op == TGSI_OPCODE_SEQ ||
- op == TGSI_OPCODE_SNE ||
- op == TGSI_OPCODE_SGE ||
- op == TGSI_OPCODE_SLT))
- {
- st_src_reg src = st_src_reg(dst);
- src.negate = ~src.negate;
- dst.type = GLSL_TYPE_FLOAT;
- emit(ir, TGSI_OPCODE_F2I, dst, src);
- }
-}
-
/**
* Determines whether to use an integer, unsigned integer, or float opcode
* based on the operands and input opcode, then emits the result.
@@ -662,14 +640,30 @@ glsl_to_tgsi_visitor::get_opcode(ir_instruction *ir, unsigned op,
#define case4(c, f, i, u) \
case TGSI_OPCODE_##c: \
- if (type == GLSL_TYPE_INT) op = TGSI_OPCODE_##i; \
- else if (type == GLSL_TYPE_UINT) op = TGSI_OPCODE_##u; \
- else op = TGSI_OPCODE_##f; \
+ if (type == GLSL_TYPE_INT) \
+ op = TGSI_OPCODE_##i; \
+ else if (type == GLSL_TYPE_UINT) \
+ op = TGSI_OPCODE_##u; \
+ else \
+ op = TGSI_OPCODE_##f; \
break;
+
#define case3(f, i, u) case4(f, f, i, u)
#define case2fi(f, i) case4(f, f, i, i)
#define case2iu(i, u) case4(i, LAST, i, u)
-
+
+#define casecomp(c, f, i, u) \
+ case TGSI_OPCODE_##c: \
+ if (type == GLSL_TYPE_INT) \
+ op = TGSI_OPCODE_##i; \
+ else if (type == GLSL_TYPE_UINT) \
+ op = TGSI_OPCODE_##u; \
+ else if (native_integers) \
+ op = TGSI_OPCODE_##f; \
+ else \
+ op = TGSI_OPCODE_##c; \
+ break;
+
switch(op) {
case2fi(ADD, UADD);
case2fi(MUL, UMUL);
@@ -678,12 +672,12 @@ glsl_to_tgsi_visitor::get_opcode(ir_instruction *ir, unsigned op,
case3(MAX, IMAX, UMAX);
case3(MIN, IMIN, UMIN);
case2iu(MOD, UMOD);
-
- case2fi(SEQ, USEQ);
- case2fi(SNE, USNE);
- case3(SGE, ISGE, USGE);
- case3(SLT, ISLT, USLT);
-
+
+ casecomp(SEQ, FSEQ, USEQ, USEQ);
+ casecomp(SNE, FSNE, USNE, USNE);
+ casecomp(SGE, FSGE, ISGE, USGE);
+ casecomp(SLT, FSLT, ISLT, USLT);
+
case2iu(ISHR, USHR);
case2fi(SSG, ISSG);
@@ -3015,6 +3009,18 @@ glsl_to_tgsi_visitor::visit(ir_if *ir)
if_inst = emit(ir->condition, TGSI_OPCODE_ENDIF);
}
+void
+glsl_to_tgsi_visitor::visit(ir_emit_vertex *ir)
+{
+ assert(!"Geometry shaders not supported.");
+}
+
+void
+glsl_to_tgsi_visitor::visit(ir_end_primitive *ir)
+{
+ assert(!"Geometry shaders not supported.");
+}
+
glsl_to_tgsi_visitor::glsl_to_tgsi_visitor()
{
result.file = PROGRAM_UNDEFINED;
@@ -5121,7 +5127,7 @@ get_mesa_program(struct gl_context *ctx,
prog->Instructions = NULL;
prog->NumInstructions = 0;
- do_set_program_inouts(shader->ir, prog, shader->Type == GL_FRAGMENT_SHADER);
+ do_set_program_inouts(shader->ir, prog, shader->Type);
count_resources(v, prog);
_mesa_reference_program(ctx, &shader->Program, prog);
diff --git a/mesalib/src/mesa/vbo/vbo_exec_array.c b/mesalib/src/mesa/vbo/vbo_exec_array.c
index 75831faf9..bd05cd0c3 100644
--- a/mesalib/src/mesa/vbo/vbo_exec_array.c
+++ b/mesalib/src/mesa/vbo/vbo_exec_array.c
@@ -442,41 +442,77 @@ recalculate_input_bindings(struct gl_context *ctx)
break;
case VP_ARB:
- /* GL_ARB_vertex_program or GLSL vertex shader - Only the generic[0]
+ /* There are no shaders in OpenGL ES 1.x, so this code path should be
+ * impossible to reach. The meta code is careful to not use shaders in
+ * ES1.
+ */
+ assert(ctx->API != API_OPENGLES);
+
+ /* In the compatibility profile of desktop OpenGL, the generic[0]
* attribute array aliases and overrides the legacy position array.
- *
* Otherwise, legacy attributes available in the legacy slots,
* generic attributes in the generic slots and materials are not
* available as per-vertex attributes.
+ *
+ * In all other APIs, only the generic attributes exist, and none of the
+ * slots are considered "magic."
*/
- if (vertexAttrib[VERT_ATTRIB_GENERIC0].Enabled)
- inputs[0] = &vertexAttrib[VERT_ATTRIB_GENERIC0];
- else if (vertexAttrib[VERT_ATTRIB_POS].Enabled)
- inputs[0] = &vertexAttrib[VERT_ATTRIB_POS];
- else {
- inputs[0] = &vbo->currval[VBO_ATTRIB_POS];
- const_inputs |= VERT_BIT_POS;
- }
+ if (ctx->API == API_OPENGL_COMPAT) {
+ if (vertexAttrib[VERT_ATTRIB_GENERIC0].Enabled)
+ inputs[0] = &vertexAttrib[VERT_ATTRIB_GENERIC0];
+ else if (vertexAttrib[VERT_ATTRIB_POS].Enabled)
+ inputs[0] = &vertexAttrib[VERT_ATTRIB_POS];
+ else {
+ inputs[0] = &vbo->currval[VBO_ATTRIB_POS];
+ const_inputs |= VERT_BIT_POS;
+ }
- for (i = 1; i < VERT_ATTRIB_FF_MAX; i++) {
- if (vertexAttrib[VERT_ATTRIB_FF(i)].Enabled)
- inputs[i] = &vertexAttrib[VERT_ATTRIB_FF(i)];
- else {
- inputs[i] = &vbo->currval[VBO_ATTRIB_POS+i];
+ for (i = 1; i < VERT_ATTRIB_FF_MAX; i++) {
+ if (vertexAttrib[VERT_ATTRIB_FF(i)].Enabled)
+ inputs[i] = &vertexAttrib[VERT_ATTRIB_FF(i)];
+ else {
+ inputs[i] = &vbo->currval[VBO_ATTRIB_POS+i];
+ const_inputs |= VERT_BIT_FF(i);
+ }
+ }
+
+ for (i = 1; i < VERT_ATTRIB_GENERIC_MAX; i++) {
+ if (vertexAttrib[VERT_ATTRIB_GENERIC(i)].Enabled)
+ inputs[VERT_ATTRIB_GENERIC(i)] =
+ &vertexAttrib[VERT_ATTRIB_GENERIC(i)];
+ else {
+ inputs[VERT_ATTRIB_GENERIC(i)] =
+ &vbo->currval[VBO_ATTRIB_GENERIC0+i];
+ const_inputs |= VERT_BIT_GENERIC(i);
+ }
+ }
+
+ inputs[VERT_ATTRIB_GENERIC0] = inputs[0];
+ } else {
+ /* Other parts of the code assume that inputs[0] through
+ * inputs[VERT_ATTRIB_FF_MAX] will be non-NULL. However, in OpenGL
+ * ES 2.0+ or OpenGL core profile, none of these arrays should ever
+ * be enabled.
+ */
+ for (i = 0; i < VERT_ATTRIB_FF_MAX; i++) {
+ assert(!vertexAttrib[VERT_ATTRIB_FF(i)].Enabled);
+
+ inputs[i] = &vbo->currval[VBO_ATTRIB_POS+i];
const_inputs |= VERT_BIT_FF(i);
}
- }
- for (i = 1; i < VERT_ATTRIB_GENERIC_MAX; i++) {
- if (vertexAttrib[VERT_ATTRIB_GENERIC(i)].Enabled)
- inputs[VERT_ATTRIB_GENERIC(i)] = &vertexAttrib[VERT_ATTRIB_GENERIC(i)];
- else {
- inputs[VERT_ATTRIB_GENERIC(i)] = &vbo->currval[VBO_ATTRIB_GENERIC0+i];
- const_inputs |= VERT_BIT_GENERIC(i);
+ for (i = 0; i < VERT_ATTRIB_GENERIC_MAX; i++) {
+ if (vertexAttrib[VERT_ATTRIB_GENERIC(i)].Enabled)
+ inputs[VERT_ATTRIB_GENERIC(i)] =
+ &vertexAttrib[VERT_ATTRIB_GENERIC(i)];
+ else {
+ inputs[VERT_ATTRIB_GENERIC(i)] =
+ &vbo->currval[VBO_ATTRIB_GENERIC0+i];
+ const_inputs |= VERT_BIT_GENERIC(i);
+ }
}
}
- inputs[VERT_ATTRIB_GENERIC0] = inputs[0];
break;
}