aboutsummaryrefslogtreecommitdiff
path: root/mesalib/src
diff options
context:
space:
mode:
Diffstat (limited to 'mesalib/src')
-rw-r--r--mesalib/src/gallium/Automake.inc13
-rw-r--r--mesalib/src/gallium/auxiliary/util/u_debug_flush.c5
-rw-r--r--mesalib/src/gallium/auxiliary/util/u_math.h5
-rw-r--r--mesalib/src/glsl/Makefile.am11
-rw-r--r--mesalib/src/glsl/ast_to_hir.cpp80
-rw-r--r--mesalib/src/glsl/builtin_types.cpp2
-rw-r--r--mesalib/src/glsl/builtin_variables.cpp63
-rw-r--r--mesalib/src/glsl/glcpp/glcpp-parse.y5
-rw-r--r--mesalib/src/glsl/glsl_parser.yy15
-rw-r--r--mesalib/src/glsl/glsl_parser_extras.cpp82
-rw-r--r--mesalib/src/glsl/glsl_parser_extras.h116
-rw-r--r--mesalib/src/glsl/ir.cpp2
-rw-r--r--mesalib/src/glsl/ir_optimization.h4
-rw-r--r--mesalib/src/glsl/link_varyings.cpp368
-rw-r--r--mesalib/src/glsl/linker.cpp190
-rw-r--r--mesalib/src/glsl/lower_instructions.cpp58
-rw-r--r--mesalib/src/glsl/lower_packed_varyings.cpp39
-rw-r--r--mesalib/src/glsl/main.cpp6
-rw-r--r--mesalib/src/glsl/opt_dead_builtin_varyings.cpp7
-rw-r--r--mesalib/src/mapi/glapi/gen/ARB_multi_bind.xml53
-rw-r--r--mesalib/src/mapi/glapi/gen/EXT_separate_shader_objects.xml279
-rw-r--r--mesalib/src/mapi/glapi/gen/INTEL_performance_query.xml93
-rw-r--r--mesalib/src/mapi/glapi/gen/Makefile.am2
-rw-r--r--mesalib/src/mapi/glapi/gen/gl_API.xml6
-rw-r--r--mesalib/src/mesa/drivers/common/meta.c328
-rw-r--r--mesalib/src/mesa/drivers/common/meta.h5
-rw-r--r--mesalib/src/mesa/drivers/common/meta_blit.c2
-rw-r--r--mesalib/src/mesa/drivers/common/meta_generate_mipmap.c2
-rw-r--r--mesalib/src/mesa/main/bufferobj.c923
-rw-r--r--mesalib/src/mesa/main/bufferobj.h21
-rw-r--r--mesalib/src/mesa/main/config.h8
-rw-r--r--mesalib/src/mesa/main/dd.h6
-rw-r--r--mesalib/src/mesa/main/dlist.c920
-rw-r--r--mesalib/src/mesa/main/errors.c6
-rw-r--r--mesalib/src/mesa/main/errors.h3
-rw-r--r--mesalib/src/mesa/main/extensions.c7
-rw-r--r--mesalib/src/mesa/main/ff_fragment_shader.cpp2
-rw-r--r--mesalib/src/mesa/main/format_unpack.c105
-rw-r--r--mesalib/src/mesa/main/format_unpack.h10
-rw-r--r--mesalib/src/mesa/main/get.c2
-rw-r--r--mesalib/src/mesa/main/get_hash_params.py8
-rw-r--r--mesalib/src/mesa/main/hash.c89
-rw-r--r--mesalib/src/mesa/main/hash.h9
-rw-r--r--mesalib/src/mesa/main/imports.h4
-rw-r--r--mesalib/src/mesa/main/mtypes.h38
-rw-r--r--mesalib/src/mesa/main/performance_monitor.c614
-rw-r--r--mesalib/src/mesa/main/performance_monitor.h43
-rw-r--r--mesalib/src/mesa/main/pipelineobj.c13
-rw-r--r--mesalib/src/mesa/main/pipelineobj.h4
-rw-r--r--mesalib/src/mesa/main/samplerobj.c121
-rw-r--r--mesalib/src/mesa/main/samplerobj.h2
-rw-r--r--mesalib/src/mesa/main/shader_query.cpp71
-rw-r--r--mesalib/src/mesa/main/shaderapi.c152
-rw-r--r--mesalib/src/mesa/main/shaderimage.c143
-rw-r--r--mesalib/src/mesa/main/shaderimage.h3
-rw-r--r--mesalib/src/mesa/main/texgetimage.c18
-rw-r--r--mesalib/src/mesa/main/texobj.c175
-rw-r--r--mesalib/src/mesa/main/texobj.h13
-rw-r--r--mesalib/src/mesa/main/texstate.c3
-rw-r--r--mesalib/src/mesa/main/texstore.c174
-rw-r--r--mesalib/src/mesa/main/transformfeedback.c10
-rw-r--r--mesalib/src/mesa/main/transformfeedback.h14
-rw-r--r--mesalib/src/mesa/main/uniforms.h2
-rw-r--r--mesalib/src/mesa/main/varray.c128
-rw-r--r--mesalib/src/mesa/main/varray.h20
-rw-r--r--mesalib/src/mesa/state_tracker/st_atom_texture.c4
-rw-r--r--mesalib/src/mesa/state_tracker/st_extensions.c12
-rw-r--r--mesalib/src/mesa/state_tracker/st_glsl_to_tgsi.cpp2
-rw-r--r--mesalib/src/mesa/tnl/t_vertex.c14
-rw-r--r--mesalib/src/mesa/vbo/vbo_attrib_tmp.h45
-rw-r--r--mesalib/src/mesa/vbo/vbo_rebase.c23
71 files changed, 5033 insertions, 792 deletions
diff --git a/mesalib/src/gallium/Automake.inc b/mesalib/src/gallium/Automake.inc
index 1f5d532e4..4519c161c 100644
--- a/mesalib/src/gallium/Automake.inc
+++ b/mesalib/src/gallium/Automake.inc
@@ -51,22 +51,20 @@ GALLIUM_VIDEO_CFLAGS = \
$(VISIBILITY_CFLAGS)
-DRI_VERSION_SCRIPT ?= $(top_srcdir)/src/gallium/state_trackers/dri/dri.link
-
GALLIUM_DRI_LINKER_FLAGS = \
-shared \
-shrext .so \
-module \
-avoid-version \
- $(GC_SECTIONS) \
- -Wl,--version-script=$(DRI_VERSION_SCRIPT)
+ -Wl,--version-script=$(top_srcdir)/src/gallium/targets/dri.sym \
+ $(GC_SECTIONS)
GALLIUM_VDPAU_LINKER_FLAGS = \
-shared \
-module \
-no-undefined \
-version-number $(VDPAU_MAJOR):$(VDPAU_MINOR) \
- -export-symbols-regex $(VDPAU_EXPORTS) \
+ -Wl,--version-script=$(top_srcdir)/src/gallium/targets/vdpau.sym \
$(GC_SECTIONS) \
$(LD_NO_UNDEFINED)
@@ -75,7 +73,7 @@ GALLIUM_XVMC_LINKER_FLAGS = \
-module \
-no-undefined \
-version-number $(XVMC_MAJOR):$(XVMC_MINOR) \
- -export-symbols-regex '^XvMC' \
+ -Wl,--version-script=$(top_srcdir)/src/gallium/targets/xvmc.sym \
$(GC_SECTIONS) \
$(LD_NO_UNDEFINED)
@@ -83,7 +81,8 @@ GALLIUM_OMX_LINKER_FLAGS = \
-shared \
-module \
-no-undefined \
- -export-symbols-regex $(EXPORTS) \
+ -avoid-version \
+ -Wl,--version-script=$(top_srcdir)/src/gallium/targets/omx.sym \
$(GC_SECTIONS) \
$(LD_NO_UNDEFINED)
diff --git a/mesalib/src/gallium/auxiliary/util/u_debug_flush.c b/mesalib/src/gallium/auxiliary/util/u_debug_flush.c
index 9cf70db58..fdb248c23 100644
--- a/mesalib/src/gallium/auxiliary/util/u_debug_flush.c
+++ b/mesalib/src/gallium/auxiliary/util/u_debug_flush.c
@@ -46,6 +46,7 @@
#include "util/u_hash_table.h"
#include "util/u_double_list.h"
#include "util/u_inlines.h"
+#include "util/u_string.h"
#include "os/os_thread.h"
#include <stdio.h>
@@ -320,8 +321,8 @@ debug_flush_might_flush_cb(void *key, void *value, void *data)
const char *reason = (const char *) data;
char message[80];
- snprintf(message, sizeof(message),
- "%s referenced mapped buffer detected.", reason);
+ util_snprintf(message, sizeof(message),
+ "%s referenced mapped buffer detected.", reason);
pipe_mutex_lock(fbuf->mutex);
if (fbuf->mapped_sync) {
diff --git a/mesalib/src/gallium/auxiliary/util/u_math.h b/mesalib/src/gallium/auxiliary/util/u_math.h
index a60e1830a..2ade64af4 100644
--- a/mesalib/src/gallium/auxiliary/util/u_math.h
+++ b/mesalib/src/gallium/auxiliary/util/u_math.h
@@ -138,8 +138,13 @@ roundf(float x)
}
#endif
+#ifndef INFINITY
#define INFINITY (DBL_MAX + DBL_MAX)
+#endif
+
+#ifndef NAN
#define NAN (INFINITY - INFINITY)
+#endif
#endif /* _MSC_VER */
diff --git a/mesalib/src/glsl/Makefile.am b/mesalib/src/glsl/Makefile.am
index 534eaa385..fd0e837d1 100644
--- a/mesalib/src/glsl/Makefile.am
+++ b/mesalib/src/glsl/Makefile.am
@@ -61,7 +61,9 @@ tests_general_ir_test_SOURCES = \
$(GLSL_SRCDIR)/standalone_scaffolding.cpp \
tests/builtin_variable_test.cpp \
tests/invalidate_locations_test.cpp \
- tests/general_ir_test.cpp
+ tests/general_ir_test.cpp \
+ tests/varyings_test.cpp \
+ tests/common.c
tests_general_ir_test_CFLAGS = \
$(PTHREAD_CFLAGS)
tests_general_ir_test_LDADD = \
@@ -76,7 +78,8 @@ tests_uniform_initializer_test_SOURCES = \
$(top_srcdir)/src/mesa/program/symbol_table.c \
tests/copy_constant_to_storage_tests.cpp \
tests/set_uniform_initializer_tests.cpp \
- tests/uniform_initializer_utils.cpp
+ tests/uniform_initializer_utils.cpp \
+ tests/common.c
tests_uniform_initializer_test_CFLAGS = \
$(PTHREAD_CFLAGS)
tests_uniform_initializer_test_LDADD = \
@@ -95,7 +98,8 @@ tests_ralloc_test_LDADD = \
tests_sampler_types_test_SOURCES = \
$(top_srcdir)/src/mesa/program/prog_hash_table.c\
$(top_srcdir)/src/mesa/program/symbol_table.c \
- tests/sampler_types_test.cpp
+ tests/sampler_types_test.cpp \
+ tests/common.c
tests_sampler_types_test_CFLAGS = \
$(PTHREAD_CFLAGS)
tests_sampler_types_test_LDADD = \
@@ -138,6 +142,7 @@ glsl_test_SOURCES = \
$(top_srcdir)/src/mesa/program/prog_hash_table.c \
$(top_srcdir)/src/mesa/program/symbol_table.c \
$(GLSL_SRCDIR)/standalone_scaffolding.cpp \
+ tests/common.c \
test.cpp \
test_optpass.cpp
diff --git a/mesalib/src/glsl/ast_to_hir.cpp b/mesalib/src/glsl/ast_to_hir.cpp
index 0411befa9..7516c33e1 100644
--- a/mesalib/src/glsl/ast_to_hir.cpp
+++ b/mesalib/src/glsl/ast_to_hir.cpp
@@ -123,6 +123,11 @@ _mesa_ast_to_hir(exec_list *instructions, struct _mesa_glsl_parse_state *state)
instructions->push_head(var);
}
+ /* Figure out if gl_FragCoord is actually used in fragment shader */
+ ir_variable *const var = state->symbols->get_variable("gl_FragCoord");
+ if (var != NULL)
+ state->fs_uses_gl_fragcoord = var->data.used;
+
/* From section 7.1 (Built-In Language Variables) of the GLSL 4.10 spec:
*
* If multiple shaders using members of a built-in block belonging to
@@ -2341,6 +2346,34 @@ apply_image_qualifier_to_variable(const struct ast_type_qualifier *qual,
}
}
+static inline const char*
+get_layout_qualifier_string(bool origin_upper_left, bool pixel_center_integer)
+{
+ if (origin_upper_left && pixel_center_integer)
+ return "origin_upper_left, pixel_center_integer";
+ else if (origin_upper_left)
+ return "origin_upper_left";
+ else if (pixel_center_integer)
+ return "pixel_center_integer";
+ else
+ return " ";
+}
+
+static inline bool
+is_conflicting_fragcoord_redeclaration(struct _mesa_glsl_parse_state *state,
+ const struct ast_type_qualifier *qual)
+{
+ /* If gl_FragCoord was previously declared, and the qualifiers were
+ * different in any way, return true.
+ */
+ if (state->fs_redeclares_gl_fragcoord) {
+ return (state->fs_pixel_center_integer != qual->flags.q.pixel_center_integer
+ || state->fs_origin_upper_left != qual->flags.q.origin_upper_left);
+ }
+
+ return false;
+}
+
static void
apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual,
ir_variable *var,
@@ -2505,6 +2538,53 @@ apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual,
qual_string);
}
+ if (var->name != NULL && strcmp(var->name, "gl_FragCoord") == 0) {
+
+ /* Section 4.3.8.1, page 39 of GLSL 1.50 spec says:
+ *
+ * "Within any shader, the first redeclarations of gl_FragCoord
+ * must appear before any use of gl_FragCoord."
+ *
+ * Generate a compiler error if above condition is not met by the
+ * fragment shader.
+ */
+ ir_variable *earlier = state->symbols->get_variable("gl_FragCoord");
+ if (earlier != NULL &&
+ earlier->data.used &&
+ !state->fs_redeclares_gl_fragcoord) {
+ _mesa_glsl_error(loc, state,
+ "gl_FragCoord used before its first redeclaration "
+ "in fragment shader");
+ }
+
+ /* Make sure all gl_FragCoord redeclarations specify the same layout
+ * qualifiers.
+ */
+ if (is_conflicting_fragcoord_redeclaration(state, qual)) {
+ const char *const qual_string =
+ get_layout_qualifier_string(qual->flags.q.origin_upper_left,
+ qual->flags.q.pixel_center_integer);
+
+ const char *const state_string =
+ get_layout_qualifier_string(state->fs_origin_upper_left,
+ state->fs_pixel_center_integer);
+
+ _mesa_glsl_error(loc, state,
+ "gl_FragCoord redeclared with different layout "
+ "qualifiers (%s) and (%s) ",
+ state_string,
+ qual_string);
+ }
+ state->fs_origin_upper_left = qual->flags.q.origin_upper_left;
+ state->fs_pixel_center_integer = qual->flags.q.pixel_center_integer;
+ state->fs_redeclares_gl_fragcoord_with_no_layout_qualifiers =
+ !qual->flags.q.origin_upper_left && !qual->flags.q.pixel_center_integer;
+ state->fs_redeclares_gl_fragcoord =
+ state->fs_origin_upper_left ||
+ state->fs_pixel_center_integer ||
+ state->fs_redeclares_gl_fragcoord_with_no_layout_qualifiers;
+ }
+
if (qual->flags.q.explicit_location) {
validate_explicit_location(qual, var, state, loc);
} else if (qual->flags.q.explicit_index) {
diff --git a/mesalib/src/glsl/builtin_types.cpp b/mesalib/src/glsl/builtin_types.cpp
index dd42ecb05..0a0fa8cd3 100644
--- a/mesalib/src/glsl/builtin_types.cpp
+++ b/mesalib/src/glsl/builtin_types.cpp
@@ -241,7 +241,7 @@ const static struct builtin_type_versions {
T(atomic_uint, 420, 999)
};
-const glsl_type *const deprecated_types[] = {
+static const glsl_type *const deprecated_types[] = {
glsl_type::struct_gl_PointParameters_type,
glsl_type::struct_gl_MaterialParameters_type,
glsl_type::struct_gl_LightSourceParameters_type,
diff --git a/mesalib/src/glsl/builtin_variables.cpp b/mesalib/src/glsl/builtin_variables.cpp
index 4176ae6e6..9b35850ee 100644
--- a/mesalib/src/glsl/builtin_variables.cpp
+++ b/mesalib/src/glsl/builtin_variables.cpp
@@ -30,21 +30,21 @@
#include "program/prog_statevars.h"
#include "program/prog_instruction.h"
-static struct gl_builtin_uniform_element gl_NumSamples_elements[] = {
+static const struct gl_builtin_uniform_element gl_NumSamples_elements[] = {
{NULL, {STATE_NUM_SAMPLES, 0, 0}, SWIZZLE_XXXX}
};
-static struct gl_builtin_uniform_element gl_DepthRange_elements[] = {
+static const struct gl_builtin_uniform_element gl_DepthRange_elements[] = {
{"near", {STATE_DEPTH_RANGE, 0, 0}, SWIZZLE_XXXX},
{"far", {STATE_DEPTH_RANGE, 0, 0}, SWIZZLE_YYYY},
{"diff", {STATE_DEPTH_RANGE, 0, 0}, SWIZZLE_ZZZZ},
};
-static struct gl_builtin_uniform_element gl_ClipPlane_elements[] = {
+static const struct gl_builtin_uniform_element gl_ClipPlane_elements[] = {
{NULL, {STATE_CLIPPLANE, 0, 0}, SWIZZLE_XYZW}
};
-static struct gl_builtin_uniform_element gl_Point_elements[] = {
+static const struct gl_builtin_uniform_element gl_Point_elements[] = {
{"size", {STATE_POINT_SIZE}, SWIZZLE_XXXX},
{"sizeMin", {STATE_POINT_SIZE}, SWIZZLE_YYYY},
{"sizeMax", {STATE_POINT_SIZE}, SWIZZLE_ZZZZ},
@@ -54,7 +54,7 @@ static struct gl_builtin_uniform_element gl_Point_elements[] = {
{"distanceQuadraticAttenuation", {STATE_POINT_ATTENUATION}, SWIZZLE_ZZZZ},
};
-static struct gl_builtin_uniform_element gl_FrontMaterial_elements[] = {
+static const struct gl_builtin_uniform_element gl_FrontMaterial_elements[] = {
{"emission", {STATE_MATERIAL, 0, STATE_EMISSION}, SWIZZLE_XYZW},
{"ambient", {STATE_MATERIAL, 0, STATE_AMBIENT}, SWIZZLE_XYZW},
{"diffuse", {STATE_MATERIAL, 0, STATE_DIFFUSE}, SWIZZLE_XYZW},
@@ -62,7 +62,7 @@ static struct gl_builtin_uniform_element gl_FrontMaterial_elements[] = {
{"shininess", {STATE_MATERIAL, 0, STATE_SHININESS}, SWIZZLE_XXXX},
};
-static struct gl_builtin_uniform_element gl_BackMaterial_elements[] = {
+static const struct gl_builtin_uniform_element gl_BackMaterial_elements[] = {
{"emission", {STATE_MATERIAL, 1, STATE_EMISSION}, SWIZZLE_XYZW},
{"ambient", {STATE_MATERIAL, 1, STATE_AMBIENT}, SWIZZLE_XYZW},
{"diffuse", {STATE_MATERIAL, 1, STATE_DIFFUSE}, SWIZZLE_XYZW},
@@ -70,7 +70,7 @@ static struct gl_builtin_uniform_element gl_BackMaterial_elements[] = {
{"shininess", {STATE_MATERIAL, 1, STATE_SHININESS}, SWIZZLE_XXXX},
};
-static struct gl_builtin_uniform_element gl_LightSource_elements[] = {
+static const struct gl_builtin_uniform_element gl_LightSource_elements[] = {
{"ambient", {STATE_LIGHT, 0, STATE_AMBIENT}, SWIZZLE_XYZW},
{"diffuse", {STATE_LIGHT, 0, STATE_DIFFUSE}, SWIZZLE_XYZW},
{"specular", {STATE_LIGHT, 0, STATE_SPECULAR}, SWIZZLE_XYZW},
@@ -89,67 +89,67 @@ static struct gl_builtin_uniform_element gl_LightSource_elements[] = {
{"quadraticAttenuation", {STATE_LIGHT, 0, STATE_ATTENUATION}, SWIZZLE_ZZZZ},
};
-static struct gl_builtin_uniform_element gl_LightModel_elements[] = {
+static const struct gl_builtin_uniform_element gl_LightModel_elements[] = {
{"ambient", {STATE_LIGHTMODEL_AMBIENT, 0}, SWIZZLE_XYZW},
};
-static struct gl_builtin_uniform_element gl_FrontLightModelProduct_elements[] = {
+static const struct gl_builtin_uniform_element gl_FrontLightModelProduct_elements[] = {
{"sceneColor", {STATE_LIGHTMODEL_SCENECOLOR, 0}, SWIZZLE_XYZW},
};
-static struct gl_builtin_uniform_element gl_BackLightModelProduct_elements[] = {
+static const struct gl_builtin_uniform_element gl_BackLightModelProduct_elements[] = {
{"sceneColor", {STATE_LIGHTMODEL_SCENECOLOR, 1}, SWIZZLE_XYZW},
};
-static struct gl_builtin_uniform_element gl_FrontLightProduct_elements[] = {
+static const struct gl_builtin_uniform_element gl_FrontLightProduct_elements[] = {
{"ambient", {STATE_LIGHTPROD, 0, 0, STATE_AMBIENT}, SWIZZLE_XYZW},
{"diffuse", {STATE_LIGHTPROD, 0, 0, STATE_DIFFUSE}, SWIZZLE_XYZW},
{"specular", {STATE_LIGHTPROD, 0, 0, STATE_SPECULAR}, SWIZZLE_XYZW},
};
-static struct gl_builtin_uniform_element gl_BackLightProduct_elements[] = {
+static const struct gl_builtin_uniform_element gl_BackLightProduct_elements[] = {
{"ambient", {STATE_LIGHTPROD, 0, 1, STATE_AMBIENT}, SWIZZLE_XYZW},
{"diffuse", {STATE_LIGHTPROD, 0, 1, STATE_DIFFUSE}, SWIZZLE_XYZW},
{"specular", {STATE_LIGHTPROD, 0, 1, STATE_SPECULAR}, SWIZZLE_XYZW},
};
-static struct gl_builtin_uniform_element gl_TextureEnvColor_elements[] = {
+static const struct gl_builtin_uniform_element gl_TextureEnvColor_elements[] = {
{NULL, {STATE_TEXENV_COLOR, 0}, SWIZZLE_XYZW},
};
-static struct gl_builtin_uniform_element gl_EyePlaneS_elements[] = {
+static const struct gl_builtin_uniform_element gl_EyePlaneS_elements[] = {
{NULL, {STATE_TEXGEN, 0, STATE_TEXGEN_EYE_S}, SWIZZLE_XYZW},
};
-static struct gl_builtin_uniform_element gl_EyePlaneT_elements[] = {
+static const struct gl_builtin_uniform_element gl_EyePlaneT_elements[] = {
{NULL, {STATE_TEXGEN, 0, STATE_TEXGEN_EYE_T}, SWIZZLE_XYZW},
};
-static struct gl_builtin_uniform_element gl_EyePlaneR_elements[] = {
+static const struct gl_builtin_uniform_element gl_EyePlaneR_elements[] = {
{NULL, {STATE_TEXGEN, 0, STATE_TEXGEN_EYE_R}, SWIZZLE_XYZW},
};
-static struct gl_builtin_uniform_element gl_EyePlaneQ_elements[] = {
+static const struct gl_builtin_uniform_element gl_EyePlaneQ_elements[] = {
{NULL, {STATE_TEXGEN, 0, STATE_TEXGEN_EYE_Q}, SWIZZLE_XYZW},
};
-static struct gl_builtin_uniform_element gl_ObjectPlaneS_elements[] = {
+static const struct gl_builtin_uniform_element gl_ObjectPlaneS_elements[] = {
{NULL, {STATE_TEXGEN, 0, STATE_TEXGEN_OBJECT_S}, SWIZZLE_XYZW},
};
-static struct gl_builtin_uniform_element gl_ObjectPlaneT_elements[] = {
+static const struct gl_builtin_uniform_element gl_ObjectPlaneT_elements[] = {
{NULL, {STATE_TEXGEN, 0, STATE_TEXGEN_OBJECT_T}, SWIZZLE_XYZW},
};
-static struct gl_builtin_uniform_element gl_ObjectPlaneR_elements[] = {
+static const struct gl_builtin_uniform_element gl_ObjectPlaneR_elements[] = {
{NULL, {STATE_TEXGEN, 0, STATE_TEXGEN_OBJECT_R}, SWIZZLE_XYZW},
};
-static struct gl_builtin_uniform_element gl_ObjectPlaneQ_elements[] = {
+static const struct gl_builtin_uniform_element gl_ObjectPlaneQ_elements[] = {
{NULL, {STATE_TEXGEN, 0, STATE_TEXGEN_OBJECT_Q}, SWIZZLE_XYZW},
};
-static struct gl_builtin_uniform_element gl_Fog_elements[] = {
+static const struct gl_builtin_uniform_element gl_Fog_elements[] = {
{"color", {STATE_FOG_COLOR}, SWIZZLE_XYZW},
{"density", {STATE_FOG_PARAMS}, SWIZZLE_XXXX},
{"start", {STATE_FOG_PARAMS}, SWIZZLE_YYYY},
@@ -157,32 +157,32 @@ static struct gl_builtin_uniform_element gl_Fog_elements[] = {
{"scale", {STATE_FOG_PARAMS}, SWIZZLE_WWWW},
};
-static struct gl_builtin_uniform_element gl_NormalScale_elements[] = {
+static const struct gl_builtin_uniform_element gl_NormalScale_elements[] = {
{NULL, {STATE_NORMAL_SCALE}, SWIZZLE_XXXX},
};
-static struct gl_builtin_uniform_element gl_BumpRotMatrix0MESA_elements[] = {
+static const struct gl_builtin_uniform_element gl_BumpRotMatrix0MESA_elements[] = {
{NULL, {STATE_INTERNAL, STATE_ROT_MATRIX_0}, SWIZZLE_XYZW},
};
-static struct gl_builtin_uniform_element gl_BumpRotMatrix1MESA_elements[] = {
+static const struct gl_builtin_uniform_element gl_BumpRotMatrix1MESA_elements[] = {
{NULL, {STATE_INTERNAL, STATE_ROT_MATRIX_1}, SWIZZLE_XYZW},
};
-static struct gl_builtin_uniform_element gl_FogParamsOptimizedMESA_elements[] = {
+static const struct gl_builtin_uniform_element gl_FogParamsOptimizedMESA_elements[] = {
{NULL, {STATE_INTERNAL, STATE_FOG_PARAMS_OPTIMIZED}, SWIZZLE_XYZW},
};
-static struct gl_builtin_uniform_element gl_CurrentAttribVertMESA_elements[] = {
+static const struct gl_builtin_uniform_element gl_CurrentAttribVertMESA_elements[] = {
{NULL, {STATE_INTERNAL, STATE_CURRENT_ATTRIB, 0}, SWIZZLE_XYZW},
};
-static struct gl_builtin_uniform_element gl_CurrentAttribFragMESA_elements[] = {
+static const struct gl_builtin_uniform_element gl_CurrentAttribFragMESA_elements[] = {
{NULL, {STATE_INTERNAL, STATE_CURRENT_ATTRIB_MAYBE_VP_CLAMPED, 0}, SWIZZLE_XYZW},
};
#define MATRIX(name, statevar, modifier) \
- static struct gl_builtin_uniform_element name ## _elements[] = { \
+ static const struct gl_builtin_uniform_element name ## _elements[] = { \
{ NULL, { statevar, 0, 0, 0, modifier}, SWIZZLE_XYZW }, \
{ NULL, { statevar, 0, 1, 1, modifier}, SWIZZLE_XYZW }, \
{ NULL, { statevar, 0, 2, 2, modifier}, SWIZZLE_XYZW }, \
@@ -225,7 +225,7 @@ MATRIX(gl_TextureMatrixTranspose,
MATRIX(gl_TextureMatrixInverseTranspose,
STATE_TEXTURE_MATRIX, STATE_MATRIX_INVERSE);
-static struct gl_builtin_uniform_element gl_NormalMatrix_elements[] = {
+static const struct gl_builtin_uniform_element gl_NormalMatrix_elements[] = {
{ NULL, { STATE_MODELVIEW_MATRIX, 0, 0, 0, STATE_MATRIX_INVERSE},
MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_Z) },
{ NULL, { STATE_MODELVIEW_MATRIX, 0, 1, 1, STATE_MATRIX_INVERSE},
@@ -498,7 +498,8 @@ builtin_variable_generator::add_uniform(const glsl_type *type,
for (unsigned a = 0; a < array_count; a++) {
for (unsigned j = 0; j < statevar->num_elements; j++) {
- struct gl_builtin_uniform_element *element = &statevar->elements[j];
+ const struct gl_builtin_uniform_element *element =
+ &statevar->elements[j];
memcpy(slots->tokens, element->tokens, sizeof(element->tokens));
if (type->is_array()) {
diff --git a/mesalib/src/glsl/glcpp/glcpp-parse.y b/mesalib/src/glsl/glcpp/glcpp-parse.y
index f28d8531e..98875837c 100644
--- a/mesalib/src/glsl/glcpp/glcpp-parse.y
+++ b/mesalib/src/glsl/glcpp/glcpp-parse.y
@@ -2062,6 +2062,7 @@ _glcpp_parser_handle_version_declaration(glcpp_parser_t *parser, intmax_t versio
/* Add pre-defined macros. */
if (parser->is_gles) {
add_builtin_define(parser, "GL_ES", 1);
+ add_builtin_define(parser, "GL_EXT_separate_shader_objects", 1);
if (extensions != NULL) {
if (extensions->OES_EGL_image_external)
@@ -2069,6 +2070,7 @@ _glcpp_parser_handle_version_declaration(glcpp_parser_t *parser, intmax_t versio
}
} else {
add_builtin_define(parser, "GL_ARB_draw_buffers", 1);
+ add_builtin_define(parser, "GL_ARB_separate_shader_objects", 1);
add_builtin_define(parser, "GL_ARB_texture_rectangle", 1);
add_builtin_define(parser, "GL_AMD_shader_trinary_minmax", 1);
@@ -2134,9 +2136,6 @@ _glcpp_parser_handle_version_declaration(glcpp_parser_t *parser, intmax_t versio
if (extensions->ARB_texture_gather)
add_builtin_define(parser, "GL_ARB_texture_gather", 1);
- if (extensions->ARB_separate_shader_objects)
- add_builtin_define(parser, "GL_ARB_separate_shader_objects", 1);
-
if (extensions->ARB_shader_atomic_counters)
add_builtin_define(parser, "GL_ARB_shader_atomic_counters", 1);
diff --git a/mesalib/src/glsl/glsl_parser.yy b/mesalib/src/glsl/glsl_parser.yy
index 2d0e7be54..b09d6e536 100644
--- a/mesalib/src/glsl/glsl_parser.yy
+++ b/mesalib/src/glsl/glsl_parser.yy
@@ -1214,7 +1214,7 @@ layout_qualifier_id:
/* Layout qualifiers for GLSL 1.50 geometry shaders. */
if (!$$.flags.i) {
- struct {
+ static const struct {
const char *s;
GLenum e;
} map[] = {
@@ -1319,6 +1319,13 @@ layout_qualifier_id:
if (match_layout_qualifier("location", $1, state) == 0) {
$$.flags.q.explicit_location = 1;
+ if ($$.flags.q.attribute == 1 &&
+ state->ARB_explicit_attrib_location_warn) {
+ _mesa_glsl_warning(& @1, state,
+ "GL_ARB_explicit_attrib_location layout "
+ "identifier `%s' used", $1);
+ }
+
if ($3 >= 0) {
$$.location = $3;
} else {
@@ -1368,7 +1375,7 @@ layout_qualifier_id:
}
}
- static const char *local_size_qualifiers[3] = {
+ static const char * const local_size_qualifiers[3] = {
"local_size_x",
"local_size_y",
"local_size_z",
@@ -1426,10 +1433,6 @@ layout_qualifier_id:
_mesa_glsl_error(& @1, state, "unrecognized layout identifier "
"`%s'", $1);
YYERROR;
- } else if (state->ARB_explicit_attrib_location_warn) {
- _mesa_glsl_warning(& @1, state,
- "GL_ARB_explicit_attrib_location layout "
- "identifier `%s' used", $1);
}
}
| interface_block_layout_qualifier
diff --git a/mesalib/src/glsl/glsl_parser_extras.cpp b/mesalib/src/glsl/glsl_parser_extras.cpp
index 03c2a972a..d3339e779 100644
--- a/mesalib/src/glsl/glsl_parser_extras.cpp
+++ b/mesalib/src/glsl/glsl_parser_extras.cpp
@@ -49,7 +49,7 @@ glsl_compute_version_string(void *mem_ctx, bool is_es, unsigned version)
}
-static unsigned known_desktop_glsl_versions[] =
+static const unsigned known_desktop_glsl_versions[] =
{ 110, 120, 130, 140, 150, 330, 400, 410, 420, 430, 440 };
@@ -197,6 +197,12 @@ _mesa_glsl_parse_state::_mesa_glsl_parse_state(struct gl_context *_ctx,
this->default_uniform_qualifier->flags.q.shared = 1;
this->default_uniform_qualifier->flags.q.column_major = 1;
+ this->fs_uses_gl_fragcoord = false;
+ this->fs_redeclares_gl_fragcoord = false;
+ this->fs_origin_upper_left = false;
+ this->fs_pixel_center_integer = false;
+ this->fs_redeclares_gl_fragcoord_with_no_layout_qualifiers = false;
+
this->gs_input_prim_type_specified = false;
this->gs_input_size = 0;
this->in_qualifier = new(this) ast_type_qualifier();
@@ -500,40 +506,53 @@ struct _mesa_glsl_extension {
static const _mesa_glsl_extension _mesa_glsl_supported_extensions[] = {
/* API availability */
/* name GL ES supported flag */
+
+ /* ARB extensions go here, sorted alphabetically.
+ */
EXT(ARB_arrays_of_arrays, true, false, ARB_arrays_of_arrays),
+ EXT(ARB_compute_shader, true, false, ARB_compute_shader),
EXT(ARB_conservative_depth, true, false, ARB_conservative_depth),
EXT(ARB_draw_buffers, true, false, dummy_true),
EXT(ARB_draw_instanced, true, false, ARB_draw_instanced),
EXT(ARB_explicit_attrib_location, true, false, ARB_explicit_attrib_location),
EXT(ARB_fragment_coord_conventions, true, false, ARB_fragment_coord_conventions),
- EXT(ARB_texture_rectangle, true, false, dummy_true),
- EXT(EXT_texture_array, true, false, EXT_texture_array),
- EXT(ARB_separate_shader_objects, true, false, ARB_separate_shader_objects),
- EXT(ARB_shader_texture_lod, true, false, ARB_shader_texture_lod),
- EXT(ARB_shader_stencil_export, true, false, ARB_shader_stencil_export),
- EXT(AMD_conservative_depth, true, false, ARB_conservative_depth),
- EXT(AMD_shader_stencil_export, true, false, ARB_shader_stencil_export),
- EXT(OES_texture_3D, false, true, EXT_texture3D),
- EXT(OES_EGL_image_external, false, true, OES_EGL_image_external),
+ EXT(ARB_gpu_shader5, true, false, ARB_gpu_shader5),
+ EXT(ARB_sample_shading, true, false, ARB_sample_shading),
+ EXT(ARB_separate_shader_objects, true, false, dummy_true),
+ EXT(ARB_shader_atomic_counters, true, false, ARB_shader_atomic_counters),
EXT(ARB_shader_bit_encoding, true, false, ARB_shader_bit_encoding),
- EXT(ARB_uniform_buffer_object, true, false, ARB_uniform_buffer_object),
- EXT(OES_standard_derivatives, false, true, OES_standard_derivatives),
- EXT(ARB_texture_cube_map_array, true, false, ARB_texture_cube_map_array),
- EXT(ARB_shading_language_packing, true, false, ARB_shading_language_packing),
+ EXT(ARB_shader_image_load_store, true, false, ARB_shader_image_load_store),
+ EXT(ARB_shader_stencil_export, true, false, ARB_shader_stencil_export),
+ EXT(ARB_shader_texture_lod, true, false, ARB_shader_texture_lod),
EXT(ARB_shading_language_420pack, true, false, ARB_shading_language_420pack),
+ EXT(ARB_shading_language_packing, true, false, ARB_shading_language_packing),
+ EXT(ARB_texture_cube_map_array, true, false, ARB_texture_cube_map_array),
+ EXT(ARB_texture_gather, true, false, ARB_texture_gather),
EXT(ARB_texture_multisample, true, false, ARB_texture_multisample),
EXT(ARB_texture_query_levels, true, false, ARB_texture_query_levels),
EXT(ARB_texture_query_lod, true, false, ARB_texture_query_lod),
- EXT(ARB_gpu_shader5, true, false, ARB_gpu_shader5),
+ EXT(ARB_texture_rectangle, true, false, dummy_true),
+ EXT(ARB_uniform_buffer_object, true, false, ARB_uniform_buffer_object),
+ EXT(ARB_viewport_array, true, false, ARB_viewport_array),
+
+ /* KHR extensions go here, sorted alphabetically.
+ */
+
+ /* OES extensions go here, sorted alphabetically.
+ */
+ EXT(OES_EGL_image_external, false, true, OES_EGL_image_external),
+ EXT(OES_standard_derivatives, false, true, OES_standard_derivatives),
+ EXT(OES_texture_3D, false, true, EXT_texture3D),
+
+ /* All other extensions go here, sorted alphabetically.
+ */
+ EXT(AMD_conservative_depth, true, false, ARB_conservative_depth),
+ EXT(AMD_shader_stencil_export, true, false, ARB_shader_stencil_export),
+ EXT(AMD_shader_trinary_minmax, true, false, dummy_true),
EXT(AMD_vertex_shader_layer, true, false, AMD_vertex_shader_layer),
+ EXT(EXT_separate_shader_objects, false, true, dummy_true),
EXT(EXT_shader_integer_mix, true, true, EXT_shader_integer_mix),
- EXT(ARB_texture_gather, true, false, ARB_texture_gather),
- EXT(ARB_shader_atomic_counters, true, false, ARB_shader_atomic_counters),
- EXT(ARB_sample_shading, true, false, ARB_sample_shading),
- EXT(AMD_shader_trinary_minmax, true, false, dummy_true),
- EXT(ARB_viewport_array, true, false, ARB_viewport_array),
- EXT(ARB_compute_shader, true, false, ARB_compute_shader),
- EXT(ARB_shader_image_load_store, true, false, ARB_shader_image_load_store),
+ EXT(EXT_texture_array, true, false, EXT_texture_array),
};
#undef EXT
@@ -637,7 +656,7 @@ _mesa_glsl_process_extension(const char *name, YYLTYPE *name_locp,
if (extension && extension->compatible_with_state(state)) {
extension->set_flags(state, behavior);
} else {
- static const char *const fmt = "extension `%s' unsupported in %s shader";
+ static const char fmt[] = "extension `%s' unsupported in %s shader";
if (behavior == extension_require) {
_mesa_glsl_error(name_locp, state, fmt,
@@ -1356,6 +1375,14 @@ set_shader_inout_layout(struct gl_shader *shader,
assert(!state->cs_input_local_size_specified);
}
+ if (shader->Stage != MESA_SHADER_FRAGMENT) {
+ /* Should have been prevented by the parser. */
+ assert(!state->fs_uses_gl_fragcoord);
+ assert(!state->fs_redeclares_gl_fragcoord);
+ assert(!state->fs_pixel_center_integer);
+ assert(!state->fs_origin_upper_left);
+ }
+
switch (shader->Stage) {
case MESA_SHADER_GEOMETRY:
shader->Geom.VerticesOut = 0;
@@ -1389,6 +1416,15 @@ set_shader_inout_layout(struct gl_shader *shader,
}
break;
+ case MESA_SHADER_FRAGMENT:
+ shader->redeclares_gl_fragcoord = state->fs_redeclares_gl_fragcoord;
+ shader->uses_gl_fragcoord = state->fs_uses_gl_fragcoord;
+ shader->pixel_center_integer = state->fs_pixel_center_integer;
+ shader->origin_upper_left = state->fs_origin_upper_left;
+ shader->ARB_fragment_coord_conventions_enable =
+ state->ARB_fragment_coord_conventions_enable;
+ break;
+
default:
/* Nothing to do. */
break;
diff --git a/mesalib/src/glsl/glsl_parser_extras.h b/mesalib/src/glsl/glsl_parser_extras.h
index 3ad205c07..0416a9c72 100644
--- a/mesalib/src/glsl/glsl_parser_extras.h
+++ b/mesalib/src/glsl/glsl_parser_extras.h
@@ -140,8 +140,7 @@ struct _mesa_glsl_parse_state {
{
if (!this->has_separate_shader_objects()) {
const char *const requirement = this->es_shader
- ? "GL_EXT_separate_shader_objects (not supported by this "
- "implementation)"
+ ? "GL_EXT_separate_shader_objects extension"
: "GL_ARB_separate_shader_objects extension or GLSL 420";
_mesa_glsl_error(locp, this, "%s explicit location requires %s",
@@ -164,7 +163,8 @@ struct _mesa_glsl_parse_state {
bool has_separate_shader_objects() const
{
- return ARB_separate_shader_objects_enable || is_version(410, 0);
+ return ARB_separate_shader_objects_enable || is_version(410, 0)
+ || EXT_separate_shader_objects_enable;
}
void process_version_directive(YYLTYPE *locp, int version,
@@ -200,6 +200,18 @@ struct _mesa_glsl_parse_state {
struct ast_type_qualifier *default_uniform_qualifier;
/**
+ * Variables to track different cases if a fragment shader redeclares
+ * built-in variable gl_FragCoord.
+ *
+ * Note: These values are computed at ast_to_hir time rather than at parse
+ * time.
+ */
+ bool fs_redeclares_gl_fragcoord;
+ bool fs_origin_upper_left;
+ bool fs_pixel_center_integer;
+ bool fs_redeclares_gl_fragcoord_with_no_layout_qualifiers;
+
+ /**
* True if a geometry shader input primitive type was specified using a
* layout directive.
*
@@ -337,8 +349,14 @@ struct _mesa_glsl_parse_state {
* \name Enable bits for GLSL extensions
*/
/*@{*/
+ /* ARB extensions go here, sorted alphabetically.
+ */
bool ARB_arrays_of_arrays_enable;
bool ARB_arrays_of_arrays_warn;
+ bool ARB_compute_shader_enable;
+ bool ARB_compute_shader_warn;
+ bool ARB_conservative_depth_enable;
+ bool ARB_conservative_depth_warn;
bool ARB_draw_buffers_enable;
bool ARB_draw_buffers_warn;
bool ARB_draw_instanced_enable;
@@ -347,70 +365,78 @@ struct _mesa_glsl_parse_state {
bool ARB_explicit_attrib_location_warn;
bool ARB_fragment_coord_conventions_enable;
bool ARB_fragment_coord_conventions_warn;
- bool ARB_texture_rectangle_enable;
- bool ARB_texture_rectangle_warn;
- bool ARB_texture_gather_enable;
- bool ARB_texture_gather_warn;
- bool EXT_texture_array_enable;
- bool EXT_texture_array_warn;
+ bool ARB_gpu_shader5_enable;
+ bool ARB_gpu_shader5_warn;
+ bool ARB_sample_shading_enable;
+ bool ARB_sample_shading_warn;
bool ARB_separate_shader_objects_enable;
bool ARB_separate_shader_objects_warn;
- bool ARB_shader_texture_lod_enable;
- bool ARB_shader_texture_lod_warn;
- bool ARB_shader_stencil_export_enable;
- bool ARB_shader_stencil_export_warn;
- bool AMD_conservative_depth_enable;
- bool AMD_conservative_depth_warn;
- bool ARB_conservative_depth_enable;
- bool ARB_conservative_depth_warn;
- bool AMD_shader_stencil_export_enable;
- bool AMD_shader_stencil_export_warn;
- bool OES_texture_3D_enable;
- bool OES_texture_3D_warn;
- bool OES_EGL_image_external_enable;
- bool OES_EGL_image_external_warn;
+ bool ARB_shader_atomic_counters_enable;
+ bool ARB_shader_atomic_counters_warn;
bool ARB_shader_bit_encoding_enable;
bool ARB_shader_bit_encoding_warn;
- bool ARB_uniform_buffer_object_enable;
- bool ARB_uniform_buffer_object_warn;
- bool OES_standard_derivatives_enable;
- bool OES_standard_derivatives_warn;
- bool ARB_texture_cube_map_array_enable;
- bool ARB_texture_cube_map_array_warn;
+ bool ARB_shader_image_load_store_enable;
+ bool ARB_shader_image_load_store_warn;
+ bool ARB_shader_stencil_export_enable;
+ bool ARB_shader_stencil_export_warn;
+ bool ARB_shader_texture_lod_enable;
+ bool ARB_shader_texture_lod_warn;
+ bool ARB_shading_language_420pack_enable;
+ bool ARB_shading_language_420pack_warn;
bool ARB_shading_language_packing_enable;
bool ARB_shading_language_packing_warn;
+ bool ARB_texture_cube_map_array_enable;
+ bool ARB_texture_cube_map_array_warn;
+ bool ARB_texture_gather_enable;
+ bool ARB_texture_gather_warn;
bool ARB_texture_multisample_enable;
bool ARB_texture_multisample_warn;
bool ARB_texture_query_levels_enable;
bool ARB_texture_query_levels_warn;
bool ARB_texture_query_lod_enable;
bool ARB_texture_query_lod_warn;
- bool ARB_gpu_shader5_enable;
- bool ARB_gpu_shader5_warn;
+ bool ARB_texture_rectangle_enable;
+ bool ARB_texture_rectangle_warn;
+ bool ARB_uniform_buffer_object_enable;
+ bool ARB_uniform_buffer_object_warn;
+ bool ARB_viewport_array_enable;
+ bool ARB_viewport_array_warn;
+
+ /* KHR extensions go here, sorted alphabetically.
+ */
+
+ /* OES extensions go here, sorted alphabetically.
+ */
+ bool OES_EGL_image_external_enable;
+ bool OES_EGL_image_external_warn;
+ bool OES_standard_derivatives_enable;
+ bool OES_standard_derivatives_warn;
+ bool OES_texture_3D_enable;
+ bool OES_texture_3D_warn;
+
+ /* All other extensions go here, sorted alphabetically.
+ */
+ bool AMD_conservative_depth_enable;
+ bool AMD_conservative_depth_warn;
+ bool AMD_shader_stencil_export_enable;
+ bool AMD_shader_stencil_export_warn;
+ bool AMD_shader_trinary_minmax_enable;
+ bool AMD_shader_trinary_minmax_warn;
bool AMD_vertex_shader_layer_enable;
bool AMD_vertex_shader_layer_warn;
- bool ARB_shading_language_420pack_enable;
- bool ARB_shading_language_420pack_warn;
- bool ARB_sample_shading_enable;
- bool ARB_sample_shading_warn;
+ bool EXT_separate_shader_objects_enable;
+ bool EXT_separate_shader_objects_warn;
bool EXT_shader_integer_mix_enable;
bool EXT_shader_integer_mix_warn;
- bool ARB_shader_atomic_counters_enable;
- bool ARB_shader_atomic_counters_warn;
- bool AMD_shader_trinary_minmax_enable;
- bool AMD_shader_trinary_minmax_warn;
- bool ARB_viewport_array_enable;
- bool ARB_viewport_array_warn;
- bool ARB_compute_shader_enable;
- bool ARB_compute_shader_warn;
- bool ARB_shader_image_load_store_enable;
- bool ARB_shader_image_load_store_warn;
+ bool EXT_texture_array_enable;
+ bool EXT_texture_array_warn;
/*@}*/
/** Extensions supported by the OpenGL implementation. */
const struct gl_extensions *extensions;
bool uses_builtin_functions;
+ bool fs_uses_gl_fragcoord;
/**
* For geometry shaders, size of the most recently seen input declaration
diff --git a/mesalib/src/glsl/ir.cpp b/mesalib/src/glsl/ir.cpp
index 1a18b47f7..ba8a8394f 100644
--- a/mesalib/src/glsl/ir.cpp
+++ b/mesalib/src/glsl/ir.cpp
@@ -1333,7 +1333,7 @@ ir_dereference::is_lvalue() const
}
-static const char *tex_opcode_strs[] = { "tex", "txb", "txl", "txd", "txf", "txf_ms", "txs", "lod", "tg4", "query_levels" };
+static const char * const tex_opcode_strs[] = { "tex", "txb", "txl", "txd", "txf", "txf_ms", "txs", "lod", "tg4", "query_levels" };
const char *ir_texture::opcode_string()
{
diff --git a/mesalib/src/glsl/ir_optimization.h b/mesalib/src/glsl/ir_optimization.h
index 40bb61392..c63921c26 100644
--- a/mesalib/src/glsl/ir_optimization.h
+++ b/mesalib/src/glsl/ir_optimization.h
@@ -38,6 +38,8 @@
#define INT_DIV_TO_MUL_RCP 0x40
#define BITFIELD_INSERT_TO_BFM_BFI 0x80
#define LDEXP_TO_ARITH 0x100
+#define CARRY_TO_ARITH 0x200
+#define BORROW_TO_ARITH 0x400
/**
* \see class lower_packing_builtins_visitor
@@ -112,7 +114,7 @@ bool lower_clip_distance(gl_shader *shader);
void lower_output_reads(exec_list *instructions);
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,
+void lower_packed_varyings(void *mem_ctx,
unsigned locations_used, ir_variable_mode mode,
unsigned gs_input_vertices, gl_shader *shader);
bool lower_vector_insert(exec_list *instructions, bool lower_nonconstant_index);
diff --git a/mesalib/src/glsl/link_varyings.cpp b/mesalib/src/glsl/link_varyings.cpp
index c925c00e3..ac38a2f31 100644
--- a/mesalib/src/glsl/link_varyings.cpp
+++ b/mesalib/src/glsl/link_varyings.cpp
@@ -172,6 +172,7 @@ cross_validate_outputs_to_inputs(struct gl_shader_program *prog,
gl_shader *producer, gl_shader *consumer)
{
glsl_symbol_table parameters;
+ ir_variable *explicit_locations[MAX_VARYING] = { NULL, };
/* Find all shader outputs in the "producer" stage.
*/
@@ -181,7 +182,26 @@ cross_validate_outputs_to_inputs(struct gl_shader_program *prog,
if ((var == NULL) || (var->data.mode != ir_var_shader_out))
continue;
- parameters.add_variable(var);
+ if (!var->data.explicit_location
+ || var->data.location < VARYING_SLOT_VAR0)
+ parameters.add_variable(var);
+ else {
+ /* User-defined varyings with explicit locations are handled
+ * differently because they do not need to have matching names.
+ */
+ const unsigned idx = var->data.location - VARYING_SLOT_VAR0;
+
+ if (explicit_locations[idx] != NULL) {
+ linker_error(prog,
+ "%s shader has multiple outputs explicitly "
+ "assigned to location %d\n",
+ _mesa_shader_stage_to_string(producer->Stage),
+ idx);
+ return;
+ }
+
+ explicit_locations[idx] = var;
+ }
}
@@ -220,7 +240,27 @@ cross_validate_outputs_to_inputs(struct gl_shader_program *prog,
front_color, back_color,
consumer->Stage, producer->Stage);
} else {
- ir_variable *const output = parameters.get_variable(input->name);
+ /* The rules for connecting inputs and outputs change in the presence
+ * of explicit locations. In this case, we no longer care about the
+ * names of the variables. Instead, we care only about the
+ * explicitly assigned location.
+ */
+ ir_variable *output = NULL;
+ if (input->data.explicit_location
+ && input->data.location >= VARYING_SLOT_VAR0) {
+ output = explicit_locations[input->data.location - VARYING_SLOT_VAR0];
+
+ if (output == NULL) {
+ linker_error(prog,
+ "%s shader input `%s' with explicit location "
+ "has no matching output\n",
+ _mesa_shader_stage_to_string(consumer->Stage),
+ input->name);
+ }
+ } else {
+ output = parameters.get_variable(input->name);
+ }
+
if (output != NULL) {
cross_validate_types_and_qualifiers(prog, input, output,
consumer->Stage, producer->Stage);
@@ -622,7 +662,7 @@ public:
~varying_matches();
void record(ir_variable *producer_var, ir_variable *consumer_var);
unsigned assign_locations();
- void store_locations(unsigned producer_base, unsigned consumer_base) const;
+ void store_locations() const;
private:
/**
@@ -648,8 +688,8 @@ private:
PACKING_ORDER_VEC3,
};
- static unsigned compute_packing_class(ir_variable *var);
- static packing_order_enum compute_packing_order(ir_variable *var);
+ static unsigned compute_packing_class(const ir_variable *var);
+ static packing_order_enum compute_packing_order(const ir_variable *var);
static int match_comparator(const void *x_generic, const void *y_generic);
/**
@@ -746,7 +786,10 @@ varying_matches::~varying_matches()
void
varying_matches::record(ir_variable *producer_var, ir_variable *consumer_var)
{
- if (!producer_var->data.is_unmatched_generic_inout) {
+ assert(producer_var != NULL || consumer_var != NULL);
+
+ if ((producer_var && !producer_var->data.is_unmatched_generic_inout)
+ || (consumer_var && !consumer_var->data.is_unmatched_generic_inout)) {
/* Either a location already exists for this variable (since it is part
* of fixed functionality), or it has already been recorded as part of a
* previous match.
@@ -781,24 +824,28 @@ varying_matches::record(ir_variable *producer_var, ir_variable *consumer_var)
realloc(this->matches,
sizeof(*this->matches) * this->matches_capacity);
}
+
+ const ir_variable *const var = (producer_var != NULL)
+ ? producer_var : consumer_var;
+
this->matches[this->num_matches].packing_class
- = this->compute_packing_class(producer_var);
+ = this->compute_packing_class(var);
this->matches[this->num_matches].packing_order
- = this->compute_packing_order(producer_var);
+ = this->compute_packing_order(var);
if (this->disable_varying_packing) {
- unsigned slots = producer_var->type->is_array()
- ? (producer_var->type->length
- * producer_var->type->fields.array->matrix_columns)
- : producer_var->type->matrix_columns;
+ unsigned slots = var->type->is_array()
+ ? (var->type->length * var->type->fields.array->matrix_columns)
+ : var->type->matrix_columns;
this->matches[this->num_matches].num_components = 4 * slots;
} else {
this->matches[this->num_matches].num_components
- = producer_var->type->component_slots();
+ = var->type->component_slots();
}
this->matches[this->num_matches].producer_var = producer_var;
this->matches[this->num_matches].consumer_var = consumer_var;
this->num_matches++;
- producer_var->data.is_unmatched_generic_inout = 0;
+ if (producer_var)
+ producer_var->data.is_unmatched_generic_inout = 0;
if (consumer_var)
consumer_var->data.is_unmatched_generic_inout = 0;
}
@@ -842,8 +889,7 @@ varying_matches::assign_locations()
* assignments that were made by varying_matches::assign_locations().
*/
void
-varying_matches::store_locations(unsigned producer_base,
- unsigned consumer_base) const
+varying_matches::store_locations() const
{
for (unsigned i = 0; i < this->num_matches; i++) {
ir_variable *producer_var = this->matches[i].producer_var;
@@ -852,11 +898,14 @@ varying_matches::store_locations(unsigned producer_base,
unsigned slot = generic_location / 4;
unsigned offset = generic_location % 4;
- producer_var->data.location = producer_base + slot;
- producer_var->data.location_frac = offset;
+ if (producer_var) {
+ producer_var->data.location = VARYING_SLOT_VAR0 + slot;
+ producer_var->data.location_frac = offset;
+ }
+
if (consumer_var) {
assert(consumer_var->data.location == -1);
- consumer_var->data.location = consumer_base + slot;
+ consumer_var->data.location = VARYING_SLOT_VAR0 + slot;
consumer_var->data.location_frac = offset;
}
}
@@ -869,7 +918,7 @@ varying_matches::store_locations(unsigned producer_base,
* be safely backed into the same vec4.
*/
unsigned
-varying_matches::compute_packing_class(ir_variable *var)
+varying_matches::compute_packing_class(const ir_variable *var)
{
/* Without help from the back-end, there is no way to pack together
* variables with different interpolation types, because
@@ -900,7 +949,7 @@ varying_matches::compute_packing_class(ir_variable *var)
* other varyings in the same packing class.
*/
varying_matches::packing_order_enum
-varying_matches::compute_packing_order(ir_variable *var)
+varying_matches::compute_packing_order(const ir_variable *var)
{
const glsl_type *element_type = var->type;
@@ -1037,6 +1086,157 @@ private:
};
+namespace linker {
+
+bool
+populate_consumer_input_sets(void *mem_ctx, exec_list *ir,
+ hash_table *consumer_inputs,
+ hash_table *consumer_interface_inputs,
+ ir_variable *consumer_inputs_with_locations[VARYING_SLOT_MAX])
+{
+ memset(consumer_inputs_with_locations,
+ 0,
+ sizeof(consumer_inputs_with_locations[0]) * VARYING_SLOT_MAX);
+
+ foreach_list(node, ir) {
+ ir_variable *const input_var = ((ir_instruction *) node)->as_variable();
+
+ if ((input_var != NULL) && (input_var->data.mode == ir_var_shader_in)) {
+ if (input_var->type->is_interface())
+ return false;
+
+ if (input_var->data.explicit_location) {
+ /* assign_varying_locations only cares about finding the
+ * ir_variable at the start of a contiguous location block.
+ *
+ * - For !producer, consumer_inputs_with_locations isn't used.
+ *
+ * - For !consumer, consumer_inputs_with_locations is empty.
+ *
+ * For consumer && producer, if you were trying to set some
+ * ir_variable to the middle of a location block on the other side
+ * of producer/consumer, cross_validate_outputs_to_inputs() should
+ * be link-erroring due to either type mismatch or location
+ * overlaps. If the variables do match up, then they've got a
+ * matching data.location and you only looked at
+ * consumer_inputs_with_locations[var->data.location], not any
+ * following entries for the array/structure.
+ */
+ consumer_inputs_with_locations[input_var->data.location] =
+ input_var;
+ } else if (input_var->get_interface_type() != NULL) {
+ char *const iface_field_name =
+ ralloc_asprintf(mem_ctx, "%s.%s",
+ input_var->get_interface_type()->name,
+ input_var->name);
+ hash_table_insert(consumer_interface_inputs, input_var,
+ iface_field_name);
+ } else {
+ hash_table_insert(consumer_inputs, input_var,
+ ralloc_strdup(mem_ctx, input_var->name));
+ }
+ }
+ }
+
+ return true;
+}
+
+/**
+ * Find a variable from the consumer that "matches" the specified variable
+ *
+ * This function only finds inputs with names that match. There is no
+ * validation (here) that the types, etc. are compatible.
+ */
+ir_variable *
+get_matching_input(void *mem_ctx,
+ const ir_variable *output_var,
+ hash_table *consumer_inputs,
+ hash_table *consumer_interface_inputs,
+ ir_variable *consumer_inputs_with_locations[VARYING_SLOT_MAX])
+{
+ ir_variable *input_var;
+
+ if (output_var->data.explicit_location) {
+ input_var = consumer_inputs_with_locations[output_var->data.location];
+ } else if (output_var->get_interface_type() != NULL) {
+ char *const iface_field_name =
+ ralloc_asprintf(mem_ctx, "%s.%s",
+ output_var->get_interface_type()->name,
+ output_var->name);
+ input_var =
+ (ir_variable *) hash_table_find(consumer_interface_inputs,
+ iface_field_name);
+ } else {
+ input_var =
+ (ir_variable *) hash_table_find(consumer_inputs, output_var->name);
+ }
+
+ return (input_var == NULL || input_var->data.mode != ir_var_shader_in)
+ ? NULL : input_var;
+}
+
+}
+
+static int
+io_variable_cmp(const void *_a, const void *_b)
+{
+ const ir_variable *const a = *(const ir_variable **) _a;
+ const ir_variable *const b = *(const ir_variable **) _b;
+
+ if (a->data.explicit_location && b->data.explicit_location)
+ return b->data.location - a->data.location;
+
+ if (a->data.explicit_location && !b->data.explicit_location)
+ return 1;
+
+ if (!a->data.explicit_location && b->data.explicit_location)
+ return -1;
+
+ return -strcmp(a->name, b->name);
+}
+
+/**
+ * Sort the shader IO variables into canonical order
+ */
+static void
+canonicalize_shader_io(exec_list *ir, enum ir_variable_mode io_mode)
+{
+ ir_variable *var_table[MAX_PROGRAM_OUTPUTS * 4];
+ unsigned num_variables = 0;
+
+ foreach_list(node, ir) {
+ ir_variable *const var = ((ir_instruction *) node)->as_variable();
+
+ if (var == NULL || var->data.mode != io_mode)
+ continue;
+
+ /* If we have already encountered more I/O variables that could
+ * successfully link, bail.
+ */
+ if (num_variables == ARRAY_SIZE(var_table))
+ return;
+
+ var_table[num_variables++] = var;
+ }
+
+ if (num_variables == 0)
+ return;
+
+ /* Sort the list in reverse order (io_variable_cmp handles this). Later
+ * we're going to push the variables on to the IR list as a stack, so we
+ * want the last variable (in canonical order) to be first in the list.
+ */
+ qsort(var_table, num_variables, sizeof(var_table[0]), io_variable_cmp);
+
+ /* Remove the variable from it's current location in the IR, and put it at
+ * the front.
+ */
+ for (unsigned i = 0; i < num_variables; i++) {
+ var_table[i]->remove();
+ ir->push_head(var_table[i]);
+ }
+}
+
/**
* Assign locations for all variables that are produced in one pipeline stage
* (the "producer") and consumed in the next stage (the "consumer").
@@ -1069,8 +1269,6 @@ assign_varying_locations(struct gl_context *ctx,
tfeedback_decl *tfeedback_decls,
unsigned gs_input_vertices)
{
- const unsigned producer_base = VARYING_SLOT_VAR0;
- const unsigned consumer_base = VARYING_SLOT_VAR0;
varying_matches matches(ctx->Const.DisableVaryingPacking,
consumer && consumer->Stage == MESA_SHADER_FRAGMENT);
hash_table *tfeedback_candidates
@@ -1079,67 +1277,85 @@ assign_varying_locations(struct gl_context *ctx,
= hash_table_ctor(0, hash_table_string_hash, hash_table_string_compare);
hash_table *consumer_interface_inputs
= hash_table_ctor(0, hash_table_string_hash, hash_table_string_compare);
+ ir_variable *consumer_inputs_with_locations[VARYING_SLOT_MAX] = {
+ NULL,
+ };
- /* Operate in a total of three passes.
+ /* Operate in a total of four passes.
+ *
+ * 1. Sort inputs / outputs into a canonical order. This is necessary so
+ * that inputs / outputs of separable shaders will be assigned
+ * predictable locations regardless of the order in which declarations
+ * appeared in the shader source.
*
- * 1. Assign locations for any matching inputs and outputs.
+ * 2. Assign locations for any matching inputs and outputs.
*
- * 2. Mark output variables in the producer that do not have locations as
+ * 3. Mark output variables in the producer that do not have locations as
* not being outputs. This lets the optimizer eliminate them.
*
- * 3. Mark input variables in the consumer that do not have locations as
+ * 4. Mark input variables in the consumer that do not have locations as
* not being inputs. This lets the optimizer eliminate them.
*/
+ if (consumer)
+ canonicalize_shader_io(consumer->ir, ir_var_shader_in);
+
+ if (producer)
+ canonicalize_shader_io(producer->ir, ir_var_shader_out);
+
+ if (consumer
+ && !linker::populate_consumer_input_sets(mem_ctx,
+ consumer->ir,
+ consumer_inputs,
+ consumer_interface_inputs,
+ consumer_inputs_with_locations)) {
+ assert(!"populate_consumer_input_sets failed");
+ hash_table_dtor(tfeedback_candidates);
+ hash_table_dtor(consumer_inputs);
+ hash_table_dtor(consumer_interface_inputs);
+ return false;
+ }
- if (consumer) {
- foreach_list(node, consumer->ir) {
- ir_variable *const input_var =
+ if (producer) {
+ foreach_list(node, producer->ir) {
+ ir_variable *const output_var =
((ir_instruction *) node)->as_variable();
- if ((input_var != NULL) && (input_var->data.mode == ir_var_shader_in)) {
- if (input_var->get_interface_type() != NULL) {
- char *const iface_field_name =
- ralloc_asprintf(mem_ctx, "%s.%s",
- input_var->get_interface_type()->name,
- input_var->name);
- hash_table_insert(consumer_interface_inputs, input_var,
- iface_field_name);
- } else {
- hash_table_insert(consumer_inputs, input_var,
- ralloc_strdup(mem_ctx, input_var->name));
- }
- }
- }
- }
-
- foreach_list(node, producer->ir) {
- ir_variable *const output_var = ((ir_instruction *) node)->as_variable();
+ if ((output_var == NULL) ||
+ (output_var->data.mode != ir_var_shader_out))
+ continue;
- if ((output_var == NULL) || (output_var->data.mode != ir_var_shader_out))
- continue;
+ tfeedback_candidate_generator g(mem_ctx, tfeedback_candidates);
+ g.process(output_var);
- tfeedback_candidate_generator g(mem_ctx, tfeedback_candidates);
- g.process(output_var);
-
- ir_variable *input_var;
- if (output_var->get_interface_type() != NULL) {
- char *const iface_field_name =
- ralloc_asprintf(mem_ctx, "%s.%s",
- output_var->get_interface_type()->name,
- output_var->name);
- input_var =
- (ir_variable *) hash_table_find(consumer_interface_inputs,
- iface_field_name);
- } else {
- input_var =
- (ir_variable *) hash_table_find(consumer_inputs, output_var->name);
+ ir_variable *const input_var =
+ linker::get_matching_input(mem_ctx, output_var, consumer_inputs,
+ consumer_interface_inputs,
+ consumer_inputs_with_locations);
+
+ /* If a matching input variable was found, add this ouptut (and the
+ * input) to the set. If this is a separable program and there is no
+ * consumer stage, add the output.
+ */
+ if (input_var || (prog->SeparateShader && consumer == NULL)) {
+ matches.record(output_var, input_var);
+ }
}
+ } else {
+ /* If there's no producer stage, then this must be a separable program.
+ * For example, we may have a program that has just a fragment shader.
+ * Later this program will be used with some arbitrary vertex (or
+ * geometry) shader program. This means that locations must be assigned
+ * for all the inputs.
+ */
+ foreach_list(node, consumer->ir) {
+ ir_variable *const input_var =
+ ((ir_instruction *) node)->as_variable();
- if (input_var && input_var->data.mode != ir_var_shader_in)
- input_var = NULL;
+ if ((input_var == NULL) ||
+ (input_var->data.mode != ir_var_shader_in))
+ continue;
- if (input_var) {
- matches.record(output_var, input_var);
+ matches.record(NULL, input_var);
}
}
@@ -1162,7 +1378,7 @@ assign_varying_locations(struct gl_context *ctx,
}
const unsigned slots_used = matches.assign_locations();
- matches.store_locations(producer_base, consumer_base);
+ matches.store_locations();
for (unsigned i = 0; i < num_tfeedback_decls; ++i) {
if (!tfeedback_decls[i].is_varying())
@@ -1187,15 +1403,17 @@ 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, 0, producer);
+ if (producer) {
+ lower_packed_varyings(mem_ctx, slots_used, ir_var_shader_out,
+ 0, producer);
+ }
if (consumer) {
- lower_packed_varyings(mem_ctx, consumer_base, slots_used,
- ir_var_shader_in, gs_input_vertices, consumer);
+ lower_packed_varyings(mem_ctx, slots_used, ir_var_shader_in,
+ gs_input_vertices, consumer);
}
}
- if (consumer) {
+ if (consumer && producer) {
foreach_list(node, consumer->ir) {
ir_variable *const var = ((ir_instruction *) node)->as_variable();
diff --git a/mesalib/src/glsl/linker.cpp b/mesalib/src/glsl/linker.cpp
index c2f7f4863..a43d23082 100644
--- a/mesalib/src/glsl/linker.cpp
+++ b/mesalib/src/glsl/linker.cpp
@@ -1195,6 +1195,83 @@ private:
};
/**
+ * Performs the cross-validation of layout qualifiers specified in
+ * redeclaration of gl_FragCoord for the attached fragment shaders,
+ * and propagates them to the linked FS and linked shader program.
+ */
+static void
+link_fs_input_layout_qualifiers(struct gl_shader_program *prog,
+ struct gl_shader *linked_shader,
+ struct gl_shader **shader_list,
+ unsigned num_shaders)
+{
+ linked_shader->redeclares_gl_fragcoord = false;
+ linked_shader->uses_gl_fragcoord = false;
+ linked_shader->origin_upper_left = false;
+ linked_shader->pixel_center_integer = false;
+
+ if (linked_shader->Stage != MESA_SHADER_FRAGMENT ||
+ (prog->Version < 150 && !prog->ARB_fragment_coord_conventions_enable))
+ return;
+
+ for (unsigned i = 0; i < num_shaders; i++) {
+ struct gl_shader *shader = shader_list[i];
+ /* From the GLSL 1.50 spec, page 39:
+ *
+ * "If gl_FragCoord is redeclared in any fragment shader in a program,
+ * it must be redeclared in all the fragment shaders in that program
+ * that have a static use gl_FragCoord."
+ *
+ * Exclude the case when one of the 'linked_shader' or 'shader' redeclares
+ * gl_FragCoord with no layout qualifiers but the other one doesn't
+ * redeclare it. If we strictly follow GLSL 1.50 spec's language, it
+ * should be a link error. But, generating link error for this case will
+ * be a wrong behaviour which spec didn't intend to do and it could also
+ * break some applications.
+ */
+ if ((linked_shader->redeclares_gl_fragcoord
+ && !shader->redeclares_gl_fragcoord
+ && shader->uses_gl_fragcoord
+ && (linked_shader->origin_upper_left
+ || linked_shader->pixel_center_integer))
+ || (shader->redeclares_gl_fragcoord
+ && !linked_shader->redeclares_gl_fragcoord
+ && linked_shader->uses_gl_fragcoord
+ && (shader->origin_upper_left
+ || shader->pixel_center_integer))) {
+ linker_error(prog, "fragment shader defined with conflicting "
+ "layout qualifiers for gl_FragCoord\n");
+ }
+
+ /* From the GLSL 1.50 spec, page 39:
+ *
+ * "All redeclarations of gl_FragCoord in all fragment shaders in a
+ * single program must have the same set of qualifiers."
+ */
+ if (linked_shader->redeclares_gl_fragcoord && shader->redeclares_gl_fragcoord
+ && (shader->origin_upper_left != linked_shader->origin_upper_left
+ || shader->pixel_center_integer != linked_shader->pixel_center_integer)) {
+ linker_error(prog, "fragment shader defined with conflicting "
+ "layout qualifiers for gl_FragCoord\n");
+ }
+
+ /* Update the linked shader state.  Note that uses_gl_fragcoord should
+ * accumulate the results.  The other values should replace.  If there
+ * are multiple redeclarations, all the fields except uses_gl_fragcoord
+ * are already known to be the same.
+ */
+ if (shader->redeclares_gl_fragcoord || shader->uses_gl_fragcoord) {
+ linked_shader->redeclares_gl_fragcoord =
+ shader->redeclares_gl_fragcoord;
+ linked_shader->uses_gl_fragcoord = linked_shader->uses_gl_fragcoord
+ || shader->uses_gl_fragcoord;
+ linked_shader->origin_upper_left = shader->origin_upper_left;
+ linked_shader->pixel_center_integer = shader->pixel_center_integer;
+ }
+ }
+}
+
+/**
* 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.
@@ -1471,6 +1548,7 @@ link_intrastage_shaders(void *mem_ctx,
linked->NumUniformBlocks = num_uniform_blocks;
ralloc_steal(linked, linked->UniformBlocks);
+ link_fs_input_layout_qualifiers(prog, linked, shader_list, num_shaders);
link_gs_inout_layout_qualifiers(prog, linked, shader_list, num_shaders);
link_cs_input_layout_qualifiers(prog, linked, shader_list, num_shaders);
@@ -1798,10 +1876,12 @@ assign_attribute_or_color_locations(gl_shader_program *prog,
* active attribute array, both of which require multiple
* contiguous generic attributes."
*
- * Previous versions of the spec contain similar language but omit
- * the bit about attribute arrays.
+ * I think above text prohibits the aliasing of explicit and
+ * automatic assignments. But, aliasing is allowed in manual
+ * assignments of attribute locations. See below comments for
+ * the details.
*
- * Page 61 of the OpenGL 4.0 spec also says:
+ * From OpenGL 4.0 spec, page 61:
*
* "It is possible for an application to bind more than one
* attribute name to the same location. This is referred to as
@@ -1814,29 +1894,84 @@ assign_attribute_or_color_locations(gl_shader_program *prog,
* but implementations are not required to generate an error
* in this case."
*
- * These two paragraphs are either somewhat contradictory, or I
- * don't fully understand one or both of them.
- */
- /* FINISHME: The code as currently written does not support
- * FINISHME: attribute location aliasing (see comment above).
+ * From GLSL 4.30 spec, page 54:
+ *
+ * "A program will fail to link if any two non-vertex shader
+ * input variables are assigned to the same location. For
+ * vertex shaders, multiple input variables may be assigned
+ * to the same location using either layout qualifiers or via
+ * the OpenGL API. However, such aliasing is intended only to
+ * support vertex shaders where each execution path accesses
+ * at most one input per each location. Implementations are
+ * permitted, but not required, to generate link-time errors
+ * if they detect that every path through the vertex shader
+ * executable accesses multiple inputs assigned to any single
+ * location. For all shader types, a program will fail to link
+ * if explicit location assignments leave the linker unable
+ * to find space for other variables without explicit
+ * assignments."
+ *
+ * From OpenGL ES 3.0 spec, page 56:
+ *
+ * "Binding more than one attribute name to the same location
+ * is referred to as aliasing, and is not permitted in OpenGL
+ * ES Shading Language 3.00 vertex shaders. LinkProgram will
+ * fail when this condition exists. However, aliasing is
+ * possible in OpenGL ES Shading Language 1.00 vertex shaders.
+ * This will only work if only one of the aliased attributes
+ * is active in the executable program, or if no path through
+ * the shader consumes more than one attribute of a set of
+ * attributes aliased to the same location. A link error can
+ * occur if the linker determines that every path through the
+ * shader consumes multiple aliased attributes, but implemen-
+ * tations are not required to generate an error in this case."
+ *
+ * After looking at above references from OpenGL, OpenGL ES and
+ * GLSL specifications, we allow aliasing of vertex input variables
+ * in: OpenGL 2.0 (and above) and OpenGL ES 2.0.
+ *
+ * NOTE: This is not required by the spec but its worth mentioning
+ * here that we're not doing anything to make sure that no path
+ * through the vertex shader executable accesses multiple inputs
+ * assigned to any single location.
*/
+
/* Mask representing the contiguous slots that will be used by
* this attribute.
*/
const unsigned attr = var->data.location - generic_base;
const unsigned use_mask = (1 << slots) - 1;
+ const char *const string = (target_index == MESA_SHADER_VERTEX)
+ ? "vertex shader input" : "fragment shader output";
+
+ /* Generate a link error if the requested locations for this
+ * attribute exceed the maximum allowed attribute location.
+ */
+ if (attr + slots > max_index) {
+ linker_error(prog,
+ "insufficient contiguous locations "
+ "available for %s `%s' %d %d %d", string,
+ var->name, used_locations, use_mask, attr);
+ return false;
+ }
/* Generate a link error if the set of bits requested for this
* attribute overlaps any previously allocated bits.
*/
if ((~(use_mask << attr) & used_locations) != used_locations) {
- const char *const string = (target_index == MESA_SHADER_VERTEX)
- ? "vertex shader input" : "fragment shader output";
- linker_error(prog,
- "insufficient contiguous locations "
- "available for %s `%s' %d %d %d", string,
- var->name, used_locations, use_mask, attr);
- return false;
+ if (target_index == MESA_SHADER_FRAGMENT ||
+ (prog->IsES && prog->Version >= 300)) {
+ linker_error(prog,
+ "overlapping location is assigned "
+ "to %s `%s' %d %d %d\n", string,
+ var->name, used_locations, use_mask, attr);
+ return false;
+ } else {
+ linker_warning(prog,
+ "overlapping location is assigned "
+ "to %s `%s' %d %d %d\n", string,
+ var->name, used_locations, use_mask, attr);
+ }
}
used_locations |= (use_mask << attr);
@@ -2115,6 +2250,7 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
ralloc_free(prog->AtomicBuffers);
prog->AtomicBuffers = NULL;
prog->NumAtomicBuffers = 0;
+ prog->ARB_fragment_coord_conventions_enable = false;
/* Separate the shaders into groups based on their type.
*/
@@ -2141,6 +2277,9 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
goto done;
}
+ prog->ARB_fragment_coord_conventions_enable |=
+ prog->Shaders[i]->ARB_fragment_coord_conventions_enable;
+
gl_shader_stage shader_type = prog->Shaders[i]->Stage;
shader_list[shader_type][num_shaders[shader_type]] = prog->Shaders[i];
num_shaders[shader_type]++;
@@ -2161,7 +2300,8 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
/* Geometry shaders have to be linked with vertex shaders.
*/
if (num_shaders[MESA_SHADER_GEOMETRY] > 0 &&
- num_shaders[MESA_SHADER_VERTEX] == 0) {
+ num_shaders[MESA_SHADER_VERTEX] == 0 &&
+ !prog->SeparateShader) {
linker_error(prog, "Geometry shader must be linked with "
"vertex shader\n");
goto done;
@@ -2363,7 +2503,7 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
if (last >= 0 && last < MESA_SHADER_FRAGMENT) {
gl_shader *const sh = prog->_LinkedShaders[last];
- if (num_tfeedback_decls != 0) {
+ if (num_tfeedback_decls != 0 || prog->SeparateShader) {
/* There was no fragment shader, but we still have to assign varying
* locations for use by transform feedback.
*/
@@ -2377,7 +2517,8 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
do_dead_builtin_varyings(ctx, sh, NULL,
num_tfeedback_decls, tfeedback_decls);
- demote_shader_inputs_and_outputs(sh, ir_var_shader_out);
+ if (!prog->SeparateShader)
+ demote_shader_inputs_and_outputs(sh, ir_var_shader_out);
/* Eliminate code that is now dead due to unused outputs being demoted.
*/
@@ -2392,7 +2533,16 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
do_dead_builtin_varyings(ctx, NULL, sh,
num_tfeedback_decls, tfeedback_decls);
- demote_shader_inputs_and_outputs(sh, ir_var_shader_in);
+ if (prog->SeparateShader) {
+ if (!assign_varying_locations(ctx, mem_ctx, prog,
+ NULL /* producer */,
+ sh /* consumer */,
+ 0 /* num_tfeedback_decls */,
+ NULL /* tfeedback_decls */,
+ 0 /* gs_input_vertices */))
+ goto done;
+ } else
+ demote_shader_inputs_and_outputs(sh, ir_var_shader_in);
while (do_dead_code(sh->ir, false))
;
@@ -2457,7 +2607,7 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
* fragment shader) is absent. So, the extension shouldn't change the
* behavior specified in GLSL specification.
*/
- if (!prog->InternalSeparateShader && ctx->API == API_OPENGLES2) {
+ if (!prog->SeparateShader && ctx->API == API_OPENGLES2) {
if (prog->_LinkedShaders[MESA_SHADER_VERTEX] == NULL) {
linker_error(prog, "program lacks a vertex shader\n");
} else if (prog->_LinkedShaders[MESA_SHADER_FRAGMENT] == NULL) {
diff --git a/mesalib/src/glsl/lower_instructions.cpp b/mesalib/src/glsl/lower_instructions.cpp
index 49316d002..176070c87 100644
--- a/mesalib/src/glsl/lower_instructions.cpp
+++ b/mesalib/src/glsl/lower_instructions.cpp
@@ -39,6 +39,8 @@
* - MOD_TO_FRACT
* - LDEXP_TO_ARITH
* - BITFIELD_INSERT_TO_BFM_BFI
+ * - CARRY_TO_ARITH
+ * - BORROW_TO_ARITH
*
* SUB_TO_ADD_NEG:
* ---------------
@@ -94,6 +96,14 @@
* Many GPUs implement the bitfieldInsert() built-in from ARB_gpu_shader_5
* with a pair of instructions.
*
+ * CARRY_TO_ARITH:
+ * ---------------
+ * Converts ir_carry into (x + y) < x.
+ *
+ * BORROW_TO_ARITH:
+ * ----------------
+ * Converts ir_borrow into (x < y).
+ *
*/
#include "main/core.h" /* for M_LOG2E */
@@ -127,6 +137,8 @@ private:
void log_to_log2(ir_expression *);
void bitfield_insert_to_bfm_bfi(ir_expression *);
void ldexp_to_arith(ir_expression *);
+ void carry_to_arith(ir_expression *);
+ void borrow_to_arith(ir_expression *);
};
} /* anonymous namespace */
@@ -436,6 +448,42 @@ lower_instructions_visitor::ldexp_to_arith(ir_expression *ir)
this->progress = true;
}
+void
+lower_instructions_visitor::carry_to_arith(ir_expression *ir)
+{
+ /* Translates
+ * ir_binop_carry x y
+ * into
+ * sum = ir_binop_add x y
+ * bcarry = ir_binop_less sum x
+ * carry = ir_unop_b2i bcarry
+ */
+
+ ir_rvalue *x_clone = ir->operands[0]->clone(ir, NULL);
+ ir->operation = ir_unop_i2u;
+ ir->operands[0] = b2i(less(add(ir->operands[0], ir->operands[1]), x_clone));
+ ir->operands[1] = NULL;
+
+ this->progress = true;
+}
+
+void
+lower_instructions_visitor::borrow_to_arith(ir_expression *ir)
+{
+ /* Translates
+ * ir_binop_borrow x y
+ * into
+ * bcarry = ir_binop_less x y
+ * carry = ir_unop_b2i bcarry
+ */
+
+ ir->operation = ir_unop_i2u;
+ ir->operands[0] = b2i(less(ir->operands[0], ir->operands[1]));
+ ir->operands[1] = NULL;
+
+ this->progress = true;
+}
+
ir_visitor_status
lower_instructions_visitor::visit_leave(ir_expression *ir)
{
@@ -482,6 +530,16 @@ lower_instructions_visitor::visit_leave(ir_expression *ir)
ldexp_to_arith(ir);
break;
+ case ir_binop_carry:
+ if (lowering(CARRY_TO_ARITH))
+ carry_to_arith(ir);
+ break;
+
+ case ir_binop_borrow:
+ if (lowering(BORROW_TO_ARITH))
+ borrow_to_arith(ir);
+ break;
+
default:
return visit_continue;
}
diff --git a/mesalib/src/glsl/lower_packed_varyings.cpp b/mesalib/src/glsl/lower_packed_varyings.cpp
index 8c1b8850b..e8654748f 100644
--- a/mesalib/src/glsl/lower_packed_varyings.cpp
+++ b/mesalib/src/glsl/lower_packed_varyings.cpp
@@ -160,8 +160,7 @@ namespace {
class lower_packed_varyings_visitor
{
public:
- lower_packed_varyings_visitor(void *mem_ctx, unsigned location_base,
- unsigned locations_used,
+ lower_packed_varyings_visitor(void *mem_ctx, unsigned locations_used,
ir_variable_mode mode,
unsigned gs_input_vertices,
exec_list *out_instructions);
@@ -190,18 +189,10 @@ private:
void * const mem_ctx;
/**
- * Location representing the first generic varying slot for this shader
- * stage (e.g. VARYING_SLOT_VAR0 if we are packing vertex shader outputs).
- * Varyings whose location is less than this value are assumed to
- * correspond to special fixed function hardware, so they are not lowered.
- */
- const unsigned location_base;
-
- /**
* Number of generic varying slots which are used by this shader. This is
* used to allocate temporary intermediate data structures. If any varying
* used by this shader has a location greater than or equal to
- * location_base + locations_used, an assertion will fire.
+ * VARYING_SLOT_VAR0 + locations_used, an assertion will fire.
*/
const unsigned locations_used;
@@ -235,11 +226,9 @@ private:
} /* anonymous namespace */
lower_packed_varyings_visitor::lower_packed_varyings_visitor(
- void *mem_ctx, unsigned location_base, unsigned locations_used,
- ir_variable_mode mode, unsigned gs_input_vertices,
- exec_list *out_instructions)
+ void *mem_ctx, unsigned locations_used, ir_variable_mode mode,
+ unsigned gs_input_vertices, exec_list *out_instructions)
: mem_ctx(mem_ctx),
- location_base(location_base),
locations_used(locations_used),
packed_varyings((ir_variable **)
rzalloc_array_size(mem_ctx, sizeof(*packed_varyings),
@@ -259,7 +248,7 @@ lower_packed_varyings_visitor::run(exec_list *instructions)
continue;
if (var->data.mode != this->mode ||
- var->data.location < (int) this->location_base ||
+ var->data.location < VARYING_SLOT_VAR0 ||
!this->needs_lowering(var))
continue;
@@ -542,7 +531,7 @@ 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;
+ unsigned slot = location - VARYING_SLOT_VAR0;
assert(slot < locations_used);
if (this->packed_varyings[slot] == NULL) {
char *packed_name = ralloc_asprintf(this->mem_ctx, "packed:%s", name);
@@ -595,7 +584,12 @@ lower_packed_varyings_visitor::get_packed_varying_deref(
bool
lower_packed_varyings_visitor::needs_lowering(ir_variable *var)
{
- /* Things composed of vec4's don't need lowering. Everything else does. */
+ /* Things composed of vec4's and varyings with explicitly assigned
+ * locations don't need lowering. Everything else does.
+ */
+ if (var->data.explicit_location)
+ return false;
+
const glsl_type *type = var->type;
if (this->gs_input_vertices != 0) {
assert(type->is_array());
@@ -654,9 +648,9 @@ lower_packed_varyings_gs_splicer::visit(ir_emit_vertex *ev)
void
-lower_packed_varyings(void *mem_ctx, unsigned location_base,
- unsigned locations_used, ir_variable_mode mode,
- unsigned gs_input_vertices, gl_shader *shader)
+lower_packed_varyings(void *mem_ctx, unsigned locations_used,
+ ir_variable_mode mode, unsigned gs_input_vertices,
+ gl_shader *shader)
{
exec_list *instructions = shader->ir;
ir_function *main_func = shader->symbols->get_function("main");
@@ -664,8 +658,7 @@ lower_packed_varyings(void *mem_ctx, unsigned location_base,
ir_function_signature *main_func_sig
= main_func->matching_signature(NULL, &void_parameters);
exec_list new_instructions;
- lower_packed_varyings_visitor visitor(mem_ctx, location_base,
- locations_used, mode,
+ lower_packed_varyings_visitor visitor(mem_ctx, locations_used, mode,
gs_input_vertices, &new_instructions);
visitor.run(instructions);
if (mode == ir_var_shader_out) {
diff --git a/mesalib/src/glsl/main.cpp b/mesalib/src/glsl/main.cpp
index 4ae8f0987..a4452e023 100644
--- a/mesalib/src/glsl/main.cpp
+++ b/mesalib/src/glsl/main.cpp
@@ -40,6 +40,12 @@
static int glsl_version = 330;
+extern "C" void
+_mesa_error_no_memory(const char *caller)
+{
+ fprintf(stderr, "Mesa error: out of memory in %s", caller);
+}
+
static void
initialize_context(struct gl_context *ctx, gl_api api)
{
diff --git a/mesalib/src/glsl/opt_dead_builtin_varyings.cpp b/mesalib/src/glsl/opt_dead_builtin_varyings.cpp
index c2a306e7b..6612592aa 100644
--- a/mesalib/src/glsl/opt_dead_builtin_varyings.cpp
+++ b/mesalib/src/glsl/opt_dead_builtin_varyings.cpp
@@ -518,14 +518,9 @@ do_dead_builtin_varyings(struct gl_context *ctx,
/* Lowering of built-in varyings has no effect with the core context and
* GLES2, because they are not available there.
- *
- * EXT_separate_shader_objects doesn't allow this optimization,
- * because a program object can be bound partially (e.g. only one
- * stage of a program object can be bound).
*/
if (ctx->API == API_OPENGL_CORE ||
- ctx->API == API_OPENGLES2 ||
- ctx->Extensions.EXT_separate_shader_objects) {
+ ctx->API == API_OPENGLES2) {
return;
}
diff --git a/mesalib/src/mapi/glapi/gen/ARB_multi_bind.xml b/mesalib/src/mapi/glapi/gen/ARB_multi_bind.xml
new file mode 100644
index 000000000..4f2f2a259
--- /dev/null
+++ b/mesalib/src/mapi/glapi/gen/ARB_multi_bind.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0"?>
+<!DOCTYPE OpenGLAPI SYSTEM "gl_API.dtd">
+
+<!-- Note: no GLX protocol info yet. -->
+
+<OpenGLAPI>
+
+<category name="GL_ARB_multi_bind" number="147">
+
+ <function name="BindBuffersBase" offset="assign">
+ <param name="target" type="GLenum"/>
+ <param name="first" type="GLuint"/>
+ <param name="count" type="GLsizei"/>
+ <param name="buffers" type="const GLuint *"/>
+ </function>
+
+ <function name="BindBuffersRange" offset="assign">
+ <param name="target" type="GLenum"/>
+ <param name="first" type="GLuint"/>
+ <param name="count" type="GLsizei"/>
+ <param name="buffers" type="const GLuint *"/>
+ <param name="offsets" type="const GLintptr *"/>
+ <param name="sizes" type="const GLsizeiptr *"/>
+ </function>
+
+ <function name="BindTextures" offset="assign">
+ <param name="first" type="GLuint"/>
+ <param name="count" type="GLsizei"/>
+ <param name="textures" type="const GLuint *"/>
+ </function>
+
+ <function name="BindSamplers" offset="assign">
+ <param name="first" type="GLuint"/>
+ <param name="count" type="GLsizei"/>
+ <param name="samplers" type="const GLuint *"/>
+ </function>
+
+ <function name="BindImageTextures" offset="assign">
+ <param name="first" type="GLuint"/>
+ <param name="count" type="GLsizei"/>
+ <param name="textures" type="const GLuint *"/>
+ </function>
+
+ <function name="BindVertexBuffers" offset="assign">
+ <param name="first" type="GLuint"/>
+ <param name="count" type="GLsizei"/>
+ <param name="buffers" type="const GLuint *"/>
+ <param name="offsets" type="const GLintptr *"/>
+ <param name="strides" type="const GLsizei *"/>
+ </function>
+
+</category>
+</OpenGLAPI>
diff --git a/mesalib/src/mapi/glapi/gen/EXT_separate_shader_objects.xml b/mesalib/src/mapi/glapi/gen/EXT_separate_shader_objects.xml
index 03f90a1b1..c6163a193 100644
--- a/mesalib/src/mapi/glapi/gen/EXT_separate_shader_objects.xml
+++ b/mesalib/src/mapi/glapi/gen/EXT_separate_shader_objects.xml
@@ -6,21 +6,292 @@
<OpenGLAPI>
<category name="GL_EXT_separate_shader_objects" number="377">
<!-- Alias of CURRENT_PROGRAM -->
- <enum name="ACTIVE_PROGRAM_EXT" value="0x8B8D"/>
+<!-- <enum name="ACTIVE_PROGRAM_EXT" value="0x8B8D"/> -->
- <function name="UseShaderProgramEXT" deprecated="3.1" offset="assign">
+ <function name="UseShaderProgramEXT" deprecated="3.1" offset="assign" exec="skip">
<param name="type" type="GLenum"/>
<param name="program" type="GLuint"/>
</function>
- <function name="ActiveProgramEXT" deprecated="3.1" offset="assign">
+ <function name="ActiveProgramEXT" deprecated="3.1" offset="assign" exec="skip">
<param name="program" type="GLuint"/>
</function>
- <function name="CreateShaderProgramEXT" deprecated="3.1" offset="assign">
+ <function name="CreateShaderProgramEXT" deprecated="3.1" offset="assign" exec="skip">
<param name="type" type="GLenum"/>
<param name="string" type="const GLchar *"/>
<return type="GLuint"/>
</function>
+
+
+ <enum name="ACTIVE_PROGRAM_EXT" value="0x8259"/>
+ <enum name="PROGRAM_PIPELINE_BINDING_EXT" value="0x825A"/>
+ <enum name="VERTEX_SHADER_BIT_EXT" value="0x00000001"/>
+ <enum name="FRAGMENT_SHADER_BIT_EXT" value="0x00000002"/>
+ <enum name="ALL_SHADER_BITS_EXT" value="0xFFFFFFFF"/>
+ <enum name="PROGRAM_SEPARABLE_EXT" value="0x8258"/>
+
+ <function name="UseProgramStagesEXT" alias="UseProgramStages" static_dispatch="false" es2="2.0">
+ <param name="pipeline" type="GLuint"/>
+ <param name="stages" type="GLbitfield"/>
+ <param name="program" type="GLuint"/>
+ </function>
+ <function name="ActiveShaderProgramEXT" alias="ActiveShaderProgram" static_dispatch="false" es2="2.0">
+ <param name="pipeline" type="GLuint"/>
+ <param name="program" type="GLuint"/>
+ </function>
+ <function name="CreateShaderProgramvEXT" alias="CreateShaderProgramv" static_dispatch="false" es2="2.0">
+ <param name="type" type="GLenum"/>
+ <param name="count" type="GLsizei"/>
+ <param name="strings" type="const GLchar * const *"/>
+ <return type="GLuint"/>
+ </function>
+ <function name="BindProgramPipelineEXT" alias="BindProgramPipeline" static_dispatch="false" es2="2.0">
+ <param name="pipeline" type="GLuint"/>
+ </function>
+ <function name="DeleteProgramPipelinesEXT" alias="DeleteProgramPipelines" static_dispatch="false" es2="2.0">
+ <param name="n" type="GLsizei"/>
+ <param name="pipelines" type="const GLuint *"/>
+ </function>
+ <function name="GenProgramPipelinesEXT" alias="GenProgramPipelines" static_dispatch="false" es2="2.0">
+ <param name="n" type="GLsizei"/>
+ <param name="pipelines" type="GLuint *"/>
+ </function>
+ <function name="IsProgramPipelineEXT" alias="IsProgramPipeline" static_dispatch="false" es2="2.0">
+ <param name="pipeline" type="GLuint"/>
+ <return type="GLboolean"/>
+ </function>
+ <function name="ProgramParameteriEXT" alias="ProgramParameteri" static_dispatch="false" es2="2.0">
+ <param name="program" type="GLuint"/>
+ <param name="pname" type="GLenum"/>
+ <param name="value" type="GLint"/>
+ </function>
+ <function name="GetProgramPipelineivEXT" alias="GetProgramPipelineiv" static_dispatch="false" es2="2.0">
+ <param name="pipeline" type="GLuint"/>
+ <param name="pname" type="GLenum"/>
+ <param name="params" type="GLint *"/>
+ </function>
+ <function name="ProgramUniform1iEXT" alias="ProgramUniform1i" static_dispatch="false" es2="2.0">
+ <param name="program" type="GLuint"/>
+ <param name="location" type="GLint"/>
+ <param name="x" type="GLint"/>
+ </function>
+ <function name="ProgramUniform2iEXT" alias="ProgramUniform2i" static_dispatch="false" es2="2.0">
+ <param name="program" type="GLuint"/>
+ <param name="location" type="GLint"/>
+ <param name="x" type="GLint"/>
+ <param name="y" type="GLint"/>
+ </function>
+ <function name="ProgramUniform3iEXT" alias="ProgramUniform3i" static_dispatch="false" es2="2.0">
+ <param name="program" type="GLuint"/>
+ <param name="location" type="GLint"/>
+ <param name="x" type="GLint"/>
+ <param name="y" type="GLint"/>
+ <param name="z" type="GLint"/>
+ </function>
+ <function name="ProgramUniform4iEXT" alias="ProgramUniform4i" static_dispatch="false" es2="2.0">
+ <param name="program" type="GLuint"/>
+ <param name="location" type="GLint"/>
+ <param name="x" type="GLint"/>
+ <param name="y" type="GLint"/>
+ <param name="z" type="GLint"/>
+ <param name="w" type="GLint"/>
+ </function>
+ <function name="ProgramUniform1uiEXT" alias="ProgramUniform1ui" static_dispatch="false" es2="3.0">
+ <param name="program" type="GLuint"/>
+ <param name="location" type="GLint"/>
+ <param name="x" type="GLuint"/>
+ </function>
+ <function name="ProgramUniform2uiEXT" alias="ProgramUniform2ui" static_dispatch="false" es2="3.0">
+ <param name="program" type="GLuint"/>
+ <param name="location" type="GLint"/>
+ <param name="x" type="GLuint"/>
+ <param name="y" type="GLuint"/>
+ </function>
+ <function name="ProgramUniform3uiEXT" alias="ProgramUniform3ui" static_dispatch="false" es2="3.0">
+ <param name="program" type="GLuint"/>
+ <param name="location" type="GLint"/>
+ <param name="x" type="GLuint"/>
+ <param name="y" type="GLuint"/>
+ <param name="z" type="GLuint"/>
+ </function>
+ <function name="ProgramUniform4uiEXT" alias="ProgramUniform4ui" static_dispatch="false" es2="3.0">
+ <param name="program" type="GLuint"/>
+ <param name="location" type="GLint"/>
+ <param name="x" type="GLuint"/>
+ <param name="y" type="GLuint"/>
+ <param name="z" type="GLuint"/>
+ <param name="w" type="GLuint"/>
+ </function>
+ <function name="ProgramUniform1fEXT" alias="ProgramUniform1f" static_dispatch="false" es2="2.0">
+ <param name="program" type="GLuint"/>
+ <param name="location" type="GLint"/>
+ <param name="x" type="GLfloat"/>
+ </function>
+ <function name="ProgramUniform2fEXT" alias="ProgramUniform2f" static_dispatch="false" es2="2.0">
+ <param name="program" type="GLuint"/>
+ <param name="location" type="GLint"/>
+ <param name="x" type="GLfloat"/>
+ <param name="y" type="GLfloat"/>
+ </function>
+ <function name="ProgramUniform3fEXT" alias="ProgramUniform3f" static_dispatch="false" es2="2.0">
+ <param name="program" type="GLuint"/>
+ <param name="location" type="GLint"/>
+ <param name="x" type="GLfloat"/>
+ <param name="y" type="GLfloat"/>
+ <param name="z" type="GLfloat"/>
+ </function>
+ <function name="ProgramUniform4fEXT" alias="ProgramUniform4f" static_dispatch="false" es2="2.0">
+ <param name="program" type="GLuint"/>
+ <param name="location" type="GLint"/>
+ <param name="x" type="GLfloat"/>
+ <param name="y" type="GLfloat"/>
+ <param name="z" type="GLfloat"/>
+ <param name="w" type="GLfloat"/>
+ </function>
+ <function name="ProgramUniform1ivEXT" alias="ProgramUniform1iv" static_dispatch="false" es2="2.0">
+ <param name="program" type="GLuint"/>
+ <param name="location" type="GLint"/>
+ <param name="count" type="GLsizei"/>
+ <param name="value" type="const GLint *"/>
+ </function>
+ <function name="ProgramUniform2ivEXT" alias="ProgramUniform2iv" static_dispatch="false" es2="2.0">
+ <param name="program" type="GLuint"/>
+ <param name="location" type="GLint"/>
+ <param name="count" type="GLsizei"/>
+ <param name="value" type="const GLint *"/>
+ </function>
+ <function name="ProgramUniform3ivEXT" alias="ProgramUniform3iv" static_dispatch="false" es2="2.0">
+ <param name="program" type="GLuint"/>
+ <param name="location" type="GLint"/>
+ <param name="count" type="GLsizei"/>
+ <param name="value" type="const GLint *"/>
+ </function>
+ <function name="ProgramUniform4ivEXT" alias="ProgramUniform4iv" static_dispatch="false" es2="2.0">
+ <param name="program" type="GLuint"/>
+ <param name="location" type="GLint"/>
+ <param name="count" type="GLsizei"/>
+ <param name="value" type="const GLint *"/>
+ </function>
+ <function name="ProgramUniform1uivEXT" alias="ProgramUniform1uiv" static_dispatch="false" es2="3.0">
+ <param name="program" type="GLuint"/>
+ <param name="location" type="GLint"/>
+ <param name="count" type="GLsizei"/>
+ <param name="value" type="const GLuint *"/>
+ </function>
+ <function name="ProgramUniform2uivEXT" alias="ProgramUniform2uiv" static_dispatch="false" es2="3.0">
+ <param name="program" type="GLuint"/>
+ <param name="location" type="GLint"/>
+ <param name="count" type="GLsizei"/>
+ <param name="value" type="const GLuint *"/>
+ </function>
+ <function name="ProgramUniform3uivEXT" alias="ProgramUniform3uiv" static_dispatch="false" es2="3.0">
+ <param name="program" type="GLuint"/>
+ <param name="location" type="GLint"/>
+ <param name="count" type="GLsizei"/>
+ <param name="value" type="const GLuint *"/>
+ </function>
+ <function name="ProgramUniform4uivEXT" alias="ProgramUniform4uiv" static_dispatch="false" es2="3.0">
+ <param name="program" type="GLuint"/>
+ <param name="location" type="GLint"/>
+ <param name="count" type="GLsizei"/>
+ <param name="value" type="const GLuint *"/>
+ </function>
+ <function name="ProgramUniform1fvEXT" alias="ProgramUniform1fv" static_dispatch="false" es2="2.0">
+ <param name="program" type="GLuint"/>
+ <param name="location" type="GLint"/>
+ <param name="count" type="GLsizei"/>
+ <param name="value" type="const GLfloat *"/>
+ </function>
+ <function name="ProgramUniform2fvEXT" alias="ProgramUniform2fv" static_dispatch="false" es2="2.0">
+ <param name="program" type="GLuint"/>
+ <param name="location" type="GLint"/>
+ <param name="count" type="GLsizei"/>
+ <param name="value" type="const GLfloat *"/>
+ </function>
+ <function name="ProgramUniform3fvEXT" alias="ProgramUniform3fv" static_dispatch="false" es2="2.0">
+ <param name="program" type="GLuint"/>
+ <param name="location" type="GLint"/>
+ <param name="count" type="GLsizei"/>
+ <param name="value" type="const GLfloat *"/>
+ </function>
+ <function name="ProgramUniform4fvEXT" alias="ProgramUniform4fv" static_dispatch="false" es2="2.0">
+ <param name="program" type="GLuint"/>
+ <param name="location" type="GLint"/>
+ <param name="count" type="GLsizei"/>
+ <param name="value" type="const GLfloat *"/>
+ </function>
+ <function name="ProgramUniformMatrix2fvEXT" alias="ProgramUniformMatrix2fv" static_dispatch="false" es2="2.0">
+ <param name="program" type="GLuint"/>
+ <param name="location" type="GLint"/>
+ <param name="count" type="GLsizei"/>
+ <param name="transpose" type="GLboolean"/>
+ <param name="value" type="const GLfloat *"/>
+ </function>
+ <function name="ProgramUniformMatrix3fvEXT" alias="ProgramUniformMatrix3fv" static_dispatch="false" es2="2.0">
+ <param name="program" type="GLuint"/>
+ <param name="location" type="GLint"/>
+ <param name="count" type="GLsizei"/>
+ <param name="transpose" type="GLboolean"/>
+ <param name="value" type="const GLfloat *"/>
+ </function>
+ <function name="ProgramUniformMatrix4fvEXT" alias="ProgramUniformMatrix4fv" static_dispatch="false" es2="2.0">
+ <param name="program" type="GLuint"/>
+ <param name="location" type="GLint"/>
+ <param name="count" type="GLsizei"/>
+ <param name="transpose" type="GLboolean"/>
+ <param name="value" type="const GLfloat *"/>
+ </function>
+ <function name="ProgramUniformMatrix2x3fvEXT" alias="ProgramUniformMatrix2x3fv" static_dispatch="false" es2="2.0">
+ <param name="program" type="GLuint"/>
+ <param name="location" type="GLint"/>
+ <param name="count" type="GLsizei"/>
+ <param name="transpose" type="GLboolean"/>
+ <param name="value" type="const GLfloat *"/>
+ </function>
+ <function name="ProgramUniformMatrix3x2fvEXT" alias="ProgramUniformMatrix3x2fv" static_dispatch="false" es2="2.0">
+ <param name="program" type="GLuint"/>
+ <param name="location" type="GLint"/>
+ <param name="count" type="GLsizei"/>
+ <param name="transpose" type="GLboolean"/>
+ <param name="value" type="const GLfloat *"/>
+ </function>
+ <function name="ProgramUniformMatrix2x4fvEXT" alias="ProgramUniformMatrix2x4fv" static_dispatch="false" es2="2.0">
+ <param name="program" type="GLuint"/>
+ <param name="location" type="GLint"/>
+ <param name="count" type="GLsizei"/>
+ <param name="transpose" type="GLboolean"/>
+ <param name="value" type="const GLfloat *"/>
+ </function>
+ <function name="ProgramUniformMatrix4x2fvEXT" alias="ProgramUniformMatrix4x2fv" static_dispatch="false" es2="2.0">
+ <param name="program" type="GLuint"/>
+ <param name="location" type="GLint"/>
+ <param name="count" type="GLsizei"/>
+ <param name="transpose" type="GLboolean"/>
+ <param name="value" type="const GLfloat *"/>
+ </function>
+ <function name="ProgramUniformMatrix3x4fvEXT" alias="ProgramUniformMatrix3x4fv" static_dispatch="false" es2="2.0">
+ <param name="program" type="GLuint"/>
+ <param name="location" type="GLint"/>
+ <param name="count" type="GLsizei"/>
+ <param name="transpose" type="GLboolean"/>
+ <param name="value" type="const GLfloat *"/>
+ </function>
+ <function name="ProgramUniformMatrix4x3fvEXT" alias="ProgramUniformMatrix4x3fv" static_dispatch="false" es2="2.0">
+ <param name="program" type="GLuint"/>
+ <param name="location" type="GLint"/>
+ <param name="count" type="GLsizei"/>
+ <param name="transpose" type="GLboolean"/>
+ <param name="value" type="const GLfloat *"/>
+ </function>
+ <function name="ValidateProgramPipelineEXT" alias="ValidateProgramPipeline" static_dispatch="false" es2="2.0">
+ <param name="pipeline" type="GLuint"/>
+ </function>
+ <function name="GetProgramPipelineInfoLogEXT" alias="GetProgramPipelineInfoLog" static_dispatch="false" es2="2.0">
+ <param name="pipeline" type="GLuint"/>
+ <param name="bufSize" type="GLsizei"/>
+ <param name="length" type="GLsizei *"/>
+ <param name="infoLog" type="GLchar *"/>
+ </function>
</category>
</OpenGLAPI>
diff --git a/mesalib/src/mapi/glapi/gen/INTEL_performance_query.xml b/mesalib/src/mapi/glapi/gen/INTEL_performance_query.xml
new file mode 100644
index 000000000..25cd1817f
--- /dev/null
+++ b/mesalib/src/mapi/glapi/gen/INTEL_performance_query.xml
@@ -0,0 +1,93 @@
+<?xml version="1.0"?>
+<!DOCTYPE OpenGLAPI SYSTEM "gl_API.dtd">
+
+<OpenGLAPI>
+
+<category name="GL_INTEL_performance_query" number="443">
+
+ <function name="GetFirstPerfQueryIdINTEL" offset="assign" static_dispatch="false" es2="2.0">
+ <param name="queryId" type="GLuint *"/>
+ </function>
+
+ <function name="GetNextPerfQueryIdINTEL" offset="assign" static_dispatch="false" es2="2.0">
+ <param name="queryId" type="GLuint"/>
+ <param name="nextQueryId" type="GLuint *"/>
+ </function>
+
+ <function name="GetPerfQueryIdByNameINTEL" offset="assign" static_dispatch="false" es2="2.0">
+ <param name="queryName" type="GLchar *"/>
+ <param name="queryId" type="GLuint *"/>
+ </function>
+
+ <function name="GetPerfQueryInfoINTEL" offset="assign" static_dispatch="false" es2="2.0">
+ <param name="queryId" type="GLuint"/>
+ <param name="queryNameLength" type="GLuint"/>
+ <param name="queryName" type="GLchar *"/>
+ <param name="dataSize" type="GLuint *"/>
+ <param name="noCounters" type="GLuint *"/>
+ <param name="noInstances" type="GLuint *"/>
+ <param name="capsMask" type="GLuint *"/>
+ </function>
+
+ <function name="GetPerfCounterInfoINTEL" offset="assign" static_dispatch="false" es2="2.0">
+ <param name="queryId" type="GLuint"/>
+ <param name="counterId" type="GLuint"/>
+ <param name="counterNameLength" type="GLuint"/>
+ <param name="counterName" type="GLchar *"/>
+ <param name="counterDescLength" type="GLuint"/>
+ <param name="counterDesc" type="GLchar *"/>
+ <param name="counterOffset" type="GLuint *"/>
+ <param name="counterDataSize" type="GLuint *"/>
+ <param name="counterTypeEnum" type="GLuint *"/>
+ <param name="counterDataTypeEnum" type="GLuint *"/>
+ <param name="rawCounterMaxValue" type="GLuint64 *"/>
+ </function>
+
+ <function name="CreatePerfQueryINTEL" offset="assign" static_dispatch="false" es2="2.0">
+ <param name="queryId" type="GLuint"/>
+ <param name="queryHandle" type="GLuint *"/>
+ </function>
+
+ <function name="DeletePerfQueryINTEL" offset="assign" static_dispatch="false" es2="2.0">
+ <param name="queryHandle" type="GLuint"/>
+ </function>
+
+ <function name="BeginPerfQueryINTEL" offset="assign" static_dispatch="false" es2="2.0">
+ <param name="queryHandle" type="GLuint"/>
+ </function>
+
+ <function name="EndPerfQueryINTEL" offset="assign" static_dispatch="false" es2="2.0">
+ <param name="queryHandle" type="GLuint"/>
+ </function>
+
+ <function name="GetPerfQueryDataINTEL" offset="assign" static_dispatch="false" es2="2.0">
+ <param name="queryHandle" type="GLuint"/>
+ <param name="flags" type="GLuint"/>
+ <param name="dataSize" type="GLsizei"/>
+ <param name="data" type="GLvoid *"/>
+ <param name="bytesWritten" type="GLuint *"/>
+ </function>
+
+ <enum name="PERFQUERY_SINGLE_CONTEXT_INTEL" value="0x0000"/>
+ <enum name="PERFQUERY_GLOBAL_CONTEXT_INTEL" value="0x0001"/>
+ <enum name="PERFQUERY_WAIT_INTEL" value="0x83FB"/>
+ <enum name="PERFQUERY_FLUSH_INTEL" value="0x83FA"/>
+ <enum name="PERFQUERY_DONOT_FLUSH_INTEL" value="0x83F9"/>
+ <enum name="PERFQUERY_COUNTER_EVENT_INTEL" value="0x94F0"/>
+ <enum name="PERFQUERY_COUNTER_DURATION_NORM_INTEL" value="0x94F1"/>
+ <enum name="PERFQUERY_COUNTER_DURATION_RAW_INTEL" value="0x94F2"/>
+ <enum name="PERFQUERY_COUNTER_THROUGHPUT_INTEL" value="0x94F3"/>
+ <enum name="PERFQUERY_COUNTER_RAW_INTEL" value="0x94F4"/>
+ <enum name="PERFQUERY_COUNTER_TIMESTAMP_INTEL" value="0x94F5"/>
+ <enum name="PERFQUERY_COUNTER_DATA_UINT32_INTEL" value="0x94F8"/>
+ <enum name="PERFQUERY_COUNTER_DATA_UINT64_INTEL" value="0x94F9"/>
+ <enum name="PERFQUERY_COUNTER_DATA_FLOAT_INTEL" value="0x94FA"/>
+ <enum name="PERFQUERY_COUNTER_DATA_DOUBLE_INTEL" value="0x94FB"/>
+ <enum name="PERFQUERY_COUNTER_DATA_BOOL32_INTEL" value="0x94FC"/>
+ <enum name="PERFQUERY_QUERY_NAME_LENGTH_MAX_INTEL" value="0x94FD"/>
+ <enum name="PERFQUERY_COUNTER_NAME_LENGTH_MAX_INTEL" value="0x94FE"/>
+ <enum name="PERFQUERY_COUNTER_DESC_LENGTH_MAX_INTEL" value="0x94FF"/>
+ <enum name="PERFQUERY_GPA_EXTENDED_COUNTERS_INTEL" value="0x9500"/>
+</category>
+
+</OpenGLAPI>
diff --git a/mesalib/src/mapi/glapi/gen/Makefile.am b/mesalib/src/mapi/glapi/gen/Makefile.am
index 6b932e73f..6f36989bc 100644
--- a/mesalib/src/mapi/glapi/gen/Makefile.am
+++ b/mesalib/src/mapi/glapi/gen/Makefile.am
@@ -133,6 +133,7 @@ API_XML = \
ARB_internalformat_query.xml \
ARB_invalidate_subdata.xml \
ARB_map_buffer_range.xml \
+ ARB_multi_bind.xml \
ARB_robustness.xml \
ARB_sample_shading.xml \
ARB_sampler_objects.xml \
@@ -171,6 +172,7 @@ API_XML = \
EXT_texture_array.xml \
EXT_texture_integer.xml \
EXT_transform_feedback.xml \
+ INTEL_performance_query.xml \
KHR_debug.xml \
NV_conditional_render.xml \
NV_primitive_restart.xml \
diff --git a/mesalib/src/mapi/glapi/gen/gl_API.xml b/mesalib/src/mapi/glapi/gen/gl_API.xml
index 9200cd68d..d6f9b5787 100644
--- a/mesalib/src/mapi/glapi/gen/gl_API.xml
+++ b/mesalib/src/mapi/glapi/gen/gl_API.xml
@@ -8341,6 +8341,10 @@
</function>
</category>
+<!-- ARB extensions #145...#146 -->
+
+<xi:include href="ARB_multi_bind.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/>
+
<!-- Non-ARB extensions sorted by extension number. -->
<category name="GL_EXT_blend_color" number="2">
@@ -12808,6 +12812,8 @@
<enum name="SKIP_DECODE_EXT" value="0x8A4A"/>
</category>
+<xi:include href="INTEL_performance_query.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/>
+
<!-- Unnumbered extensions sorted by name. -->
<category name="GL_ATI_blend_equation_separate">
diff --git a/mesalib/src/mesa/drivers/common/meta.c b/mesalib/src/mesa/drivers/common/meta.c
index ab86f9c96..b4c30564f 100644
--- a/mesalib/src/mesa/drivers/common/meta.c
+++ b/mesalib/src/mesa/drivers/common/meta.c
@@ -86,6 +86,9 @@
/** Return offset in bytes of the field within a vertex struct */
#define OFFSET(FIELD) ((void *) offsetof(struct vertex, FIELD))
+static void
+meta_clear(struct gl_context *ctx, GLbitfield buffers, bool glsl);
+
static struct blit_shader *
choose_blit_shader(GLenum target, struct blit_shader_table *table);
@@ -389,6 +392,24 @@ _mesa_meta_init(struct gl_context *ctx)
ctx->Meta = CALLOC_STRUCT(gl_meta_state);
}
+static GLenum
+gl_buffer_index_to_drawbuffers_enum(gl_buffer_index bufindex)
+{
+ assert(bufindex < BUFFER_COUNT);
+
+ if (bufindex >= BUFFER_COLOR0)
+ return GL_COLOR_ATTACHMENT0 + bufindex - BUFFER_COLOR0;
+ else if (bufindex == BUFFER_FRONT_LEFT)
+ return GL_FRONT_LEFT;
+ else if (bufindex == BUFFER_FRONT_RIGHT)
+ return GL_FRONT_RIGHT;
+ else if (bufindex == BUFFER_BACK_LEFT)
+ return GL_BACK_LEFT;
+ else if (bufindex == BUFFER_BACK_RIGHT)
+ return GL_BACK_RIGHT;
+
+ return GL_NONE;
+}
/**
* Free context meta-op state.
@@ -576,20 +597,21 @@ _mesa_meta_begin(struct gl_context *ctx, GLbitfield state)
_mesa_set_enable(ctx, GL_FRAGMENT_SHADER_ATI, GL_FALSE);
}
- if (ctx->Extensions.ARB_separate_shader_objects) {
- /* Warning it must be done before _mesa_UseProgram call */
- _mesa_reference_pipeline_object(ctx, &save->_Shader, ctx->_Shader);
+ if (ctx->Pipeline.Current) {
_mesa_reference_pipeline_object(ctx, &save->Pipeline,
ctx->Pipeline.Current);
_mesa_BindProgramPipeline(0);
}
- for (i = 0; i < MESA_SHADER_STAGES; i++) {
+ /* Save the shader state from ctx->Shader (instead of ctx->_Shader) so
+ * that we don't have to worry about the current pipeline state.
+ */
+ for (i = 0; i <= MESA_SHADER_FRAGMENT; i++) {
_mesa_reference_shader_program(ctx, &save->Shader[i],
- ctx->_Shader->CurrentProgram[i]);
+ ctx->Shader.CurrentProgram[i]);
}
_mesa_reference_shader_program(ctx, &save->ActiveShader,
- ctx->_Shader->ActiveProgram);
+ ctx->Shader.ActiveProgram);
_mesa_UseProgram(0);
}
@@ -774,6 +796,23 @@ _mesa_meta_begin(struct gl_context *ctx, GLbitfield state)
_mesa_set_framebuffer_srgb(ctx, GL_FALSE);
}
+ if (state & MESA_META_DRAW_BUFFERS) {
+ int buf, real_color_buffers = 0;
+ memset(save->ColorDrawBuffers, 0, sizeof(save->ColorDrawBuffers));
+
+ for (buf = 0; buf < MAX_DRAW_BUFFERS; buf++) {
+ int buf_index = ctx->DrawBuffer->_ColorDrawBufferIndexes[buf];
+ if (buf_index == -1)
+ continue;
+
+ save->ColorDrawBuffers[buf] =
+ gl_buffer_index_to_drawbuffers_enum(buf_index);
+
+ if (++real_color_buffers >= ctx->DrawBuffer->_NumColorDrawBuffers)
+ break;
+ }
+ }
+
/* misc */
{
save->Lighting = ctx->Light.Enabled;
@@ -908,6 +947,14 @@ _mesa_meta_end(struct gl_context *ctx)
}
if (state & MESA_META_SHADER) {
+ static const GLenum targets[] = {
+ GL_VERTEX_SHADER,
+ GL_GEOMETRY_SHADER,
+ GL_FRAGMENT_SHADER,
+ };
+
+ bool any_shader;
+
if (ctx->Extensions.ARB_vertex_program) {
_mesa_set_enable(ctx, GL_VERTEX_PROGRAM_ARB,
save->VertexProgramEnabled);
@@ -929,37 +976,46 @@ _mesa_meta_end(struct gl_context *ctx)
save->ATIFragmentShaderEnabled);
}
- /* Warning it must be done before _mesa_use_shader_program call */
- if (ctx->Extensions.ARB_separate_shader_objects) {
- _mesa_reference_pipeline_object(ctx, &ctx->_Shader, save->_Shader);
- _mesa_reference_pipeline_object(ctx, &ctx->Pipeline.Current,
- save->Pipeline);
- _mesa_reference_pipeline_object(ctx, &save->Pipeline, NULL);
- }
+ any_shader = false;
+ for (i = 0; i <= MESA_SHADER_FRAGMENT; i++) {
+ /* It is safe to call _mesa_use_shader_program even if the extension
+ * necessary for that program state is not supported. In that case,
+ * the saved program object must be NULL and the currently bound
+ * program object must be NULL. _mesa_use_shader_program is a no-op
+ * in that case.
+ */
+ _mesa_use_shader_program(ctx, targets[i],
+ save->Shader[i],
+ &ctx->Shader);
- if (ctx->Extensions.ARB_vertex_shader) {
- _mesa_use_shader_program(ctx, GL_VERTEX_SHADER,
- save->Shader[MESA_SHADER_VERTEX],
- ctx->_Shader);
+ /* Do this *before* killing the reference. :)
+ */
+ if (save->Shader[i] != NULL)
+ any_shader = true;
+
+ _mesa_reference_shader_program(ctx, &save->Shader[i], NULL);
}
- if (_mesa_has_geometry_shaders(ctx))
- _mesa_use_shader_program(ctx, GL_GEOMETRY_SHADER_ARB,
- save->Shader[MESA_SHADER_GEOMETRY],
- ctx->_Shader);
+ _mesa_reference_shader_program(ctx, &ctx->Shader.ActiveProgram,
+ save->ActiveShader);
+ _mesa_reference_shader_program(ctx, &save->ActiveShader, NULL);
- if (ctx->Extensions.ARB_fragment_shader)
- _mesa_use_shader_program(ctx, GL_FRAGMENT_SHADER,
- save->Shader[MESA_SHADER_FRAGMENT],
- ctx->_Shader);
+ /* If there were any stages set with programs, use ctx->Shader as the
+ * current shader state. Otherwise, use Pipeline.Default. The pipeline
+ * hasn't been restored yet, and that may modify ctx->_Shader further.
+ */
+ if (any_shader)
+ _mesa_reference_pipeline_object(ctx, &ctx->_Shader,
+ &ctx->Shader);
+ else
+ _mesa_reference_pipeline_object(ctx, &ctx->_Shader,
+ ctx->Pipeline.Default);
- _mesa_reference_shader_program(ctx, &ctx->_Shader->ActiveProgram,
- save->ActiveShader);
+ if (save->Pipeline) {
+ _mesa_bind_pipeline(ctx, save->Pipeline);
- for (i = 0; i < MESA_SHADER_STAGES; i++)
- _mesa_reference_shader_program(ctx, &save->Shader[i], NULL);
- _mesa_reference_shader_program(ctx, &save->ActiveShader, NULL);
- _mesa_reference_pipeline_object(ctx, &save->_Shader, NULL);
+ _mesa_reference_pipeline_object(ctx, &save->Pipeline, NULL);
+ }
}
if (state & MESA_META_STENCIL_TEST) {
@@ -1155,6 +1211,10 @@ _mesa_meta_end(struct gl_context *ctx)
ctx->CurrentRenderbuffer->Name != save->RenderbufferName)
_mesa_BindRenderbuffer(GL_RENDERBUFFER, save->RenderbufferName);
+ if (state & MESA_META_DRAW_BUFFERS) {
+ _mesa_DrawBuffers(MAX_DRAW_BUFFERS, save->ColorDrawBuffers);
+ }
+
ctx->Meta->SaveStackDepth--;
ctx->API = save->API;
@@ -1441,100 +1501,13 @@ _mesa_meta_setup_ff_tnl_for_blit(GLuint *VAO, GLuint *VBO,
void
_mesa_meta_Clear(struct gl_context *ctx, GLbitfield buffers)
{
- struct clear_state *clear = &ctx->Meta->Clear;
- struct vertex verts[4];
- /* save all state but scissor, pixel pack/unpack */
- GLbitfield metaSave = (MESA_META_ALL -
- MESA_META_SCISSOR -
- MESA_META_PIXEL_STORE -
- MESA_META_CONDITIONAL_RENDER -
- MESA_META_FRAMEBUFFER_SRGB);
- const GLuint stencilMax = (1 << ctx->DrawBuffer->Visual.stencilBits) - 1;
-
- if (buffers & BUFFER_BITS_COLOR) {
- /* if clearing color buffers, don't save/restore colormask */
- metaSave -= MESA_META_COLOR_MASK;
- }
-
- _mesa_meta_begin(ctx, metaSave);
-
- _mesa_meta_setup_vertex_objects(&clear->VAO, &clear->VBO, false, 3, 0, 4);
-
- /* GL_COLOR_BUFFER_BIT */
- if (buffers & BUFFER_BITS_COLOR) {
- /* leave colormask, glDrawBuffer state as-is */
-
- /* Clears never have the color clamped. */
- if (ctx->Extensions.ARB_color_buffer_float)
- _mesa_ClampColor(GL_CLAMP_FRAGMENT_COLOR, GL_FALSE);
- }
- else {
- ASSERT(metaSave & MESA_META_COLOR_MASK);
- _mesa_ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
- }
-
- /* GL_DEPTH_BUFFER_BIT */
- if (buffers & BUFFER_BIT_DEPTH) {
- _mesa_set_enable(ctx, GL_DEPTH_TEST, GL_TRUE);
- _mesa_DepthFunc(GL_ALWAYS);
- _mesa_DepthMask(GL_TRUE);
- }
- else {
- assert(!ctx->Depth.Test);
- }
-
- /* GL_STENCIL_BUFFER_BIT */
- if (buffers & BUFFER_BIT_STENCIL) {
- _mesa_set_enable(ctx, GL_STENCIL_TEST, GL_TRUE);
- _mesa_StencilOpSeparate(GL_FRONT_AND_BACK,
- GL_REPLACE, GL_REPLACE, GL_REPLACE);
- _mesa_StencilFuncSeparate(GL_FRONT_AND_BACK, GL_ALWAYS,
- ctx->Stencil.Clear & stencilMax,
- ctx->Stencil.WriteMask[0]);
- }
- else {
- assert(!ctx->Stencil.Enabled);
- }
-
- /* vertex positions/colors */
- {
- const GLfloat x0 = (GLfloat) ctx->DrawBuffer->_Xmin;
- const GLfloat y0 = (GLfloat) ctx->DrawBuffer->_Ymin;
- const GLfloat x1 = (GLfloat) ctx->DrawBuffer->_Xmax;
- const GLfloat y1 = (GLfloat) ctx->DrawBuffer->_Ymax;
- const GLfloat z = invert_z(ctx->Depth.Clear);
- GLuint i;
-
- verts[0].x = x0;
- verts[0].y = y0;
- verts[0].z = z;
- verts[1].x = x1;
- verts[1].y = y0;
- verts[1].z = z;
- verts[2].x = x1;
- verts[2].y = y1;
- verts[2].z = z;
- verts[3].x = x0;
- verts[3].y = y1;
- verts[3].z = z;
-
- /* vertex colors */
- for (i = 0; i < 4; i++) {
- verts[i].r = ctx->Color.ClearColor.f[0];
- verts[i].g = ctx->Color.ClearColor.f[1];
- verts[i].b = ctx->Color.ClearColor.f[2];
- verts[i].a = ctx->Color.ClearColor.f[3];
- }
-
- /* upload new vertex data */
- _mesa_BufferData(GL_ARRAY_BUFFER_ARB, sizeof(verts), verts,
- GL_DYNAMIC_DRAW_ARB);
- }
-
- /* draw quad */
- _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4);
+ meta_clear(ctx, buffers, false);
+}
- _mesa_meta_end(ctx);
+void
+_mesa_meta_glsl_Clear(struct gl_context *ctx, GLbitfield buffers)
+{
+ meta_clear(ctx, buffers, true);
}
static void
@@ -1682,21 +1655,60 @@ meta_glsl_clear_cleanup(struct clear_state *clear)
}
/**
+ * Given a bitfield of BUFFER_BIT_x draw buffers, call glDrawBuffers to
+ * set GL to only draw to those buffers.
+ *
+ * Since the bitfield has no associated order, the assignment of draw buffer
+ * indices to color attachment indices is rather arbitrary.
+ */
+static void
+drawbuffers_from_bitfield(GLbitfield bits)
+{
+ GLenum enums[MAX_DRAW_BUFFERS];
+ int i = 0;
+ int n;
+
+ /* This function is only legal for color buffer bitfields. */
+ assert((bits & ~BUFFER_BITS_COLOR) == 0);
+
+ /* Make sure we don't overflow any arrays. */
+ assert(_mesa_bitcount(bits) <= MAX_DRAW_BUFFERS);
+
+ enums[0] = GL_NONE;
+
+ if (bits & BUFFER_BIT_FRONT_LEFT)
+ enums[i++] = GL_FRONT_LEFT;
+
+ if (bits & BUFFER_BIT_FRONT_RIGHT)
+ enums[i++] = GL_FRONT_RIGHT;
+
+ if (bits & BUFFER_BIT_BACK_LEFT)
+ enums[i++] = GL_BACK_LEFT;
+
+ if (bits & BUFFER_BIT_BACK_RIGHT)
+ enums[i++] = GL_BACK_RIGHT;
+
+ for (n = 0; n < MAX_COLOR_ATTACHMENTS; n++) {
+ if (bits & (1 << (BUFFER_COLOR0 + n)))
+ enums[i++] = GL_COLOR_ATTACHMENT0 + n;
+ }
+
+ _mesa_DrawBuffers(i, enums);
+}
+
+/**
* Meta implementation of ctx->Driver.Clear() in terms of polygon rendering.
*/
-void
-_mesa_meta_glsl_Clear(struct gl_context *ctx, GLbitfield buffers)
+static void
+meta_clear(struct gl_context *ctx, GLbitfield buffers, bool glsl)
{
struct clear_state *clear = &ctx->Meta->Clear;
GLbitfield metaSave;
const GLuint stencilMax = (1 << ctx->DrawBuffer->Visual.stencilBits) - 1;
struct gl_framebuffer *fb = ctx->DrawBuffer;
- const float x0 = ((float)fb->_Xmin / fb->Width) * 2.0f - 1.0f;
- const float y0 = ((float)fb->_Ymin / fb->Height) * 2.0f - 1.0f;
- const float x1 = ((float)fb->_Xmax / fb->Width) * 2.0f - 1.0f;
- const float y1 = ((float)fb->_Ymax / fb->Height) * 2.0f - 1.0f;
- const float z = -invert_z(ctx->Depth.Clear);
+ float x0, y0, x1, y1, z;
struct vertex verts[4];
+ int i;
metaSave = (MESA_META_ALPHA_TEST |
MESA_META_BLEND |
@@ -1711,7 +1723,18 @@ _mesa_meta_glsl_Clear(struct gl_context *ctx, GLbitfield buffers)
MESA_META_MULTISAMPLE |
MESA_META_OCCLUSION_QUERY);
- if (!(buffers & BUFFER_BITS_COLOR)) {
+ if (!glsl) {
+ metaSave |= MESA_META_FOG |
+ MESA_META_PIXEL_TRANSFER |
+ MESA_META_TRANSFORM |
+ MESA_META_TEXTURE |
+ MESA_META_CLAMP_VERTEX_COLOR |
+ MESA_META_SELECT_FEEDBACK;
+ }
+
+ if (buffers & BUFFER_BITS_COLOR) {
+ metaSave |= MESA_META_DRAW_BUFFERS;
+ } else {
/* We'll use colormask to disable color writes. Otherwise,
* respect color mask
*/
@@ -1720,13 +1743,30 @@ _mesa_meta_glsl_Clear(struct gl_context *ctx, GLbitfield buffers)
_mesa_meta_begin(ctx, metaSave);
- meta_glsl_clear_init(ctx, clear);
+ if (glsl) {
+ meta_glsl_clear_init(ctx, clear);
+
+ x0 = ((float) fb->_Xmin / fb->Width) * 2.0f - 1.0f;
+ y0 = ((float) fb->_Ymin / fb->Height) * 2.0f - 1.0f;
+ x1 = ((float) fb->_Xmax / fb->Width) * 2.0f - 1.0f;
+ y1 = ((float) fb->_Ymax / fb->Height) * 2.0f - 1.0f;
+ z = -invert_z(ctx->Depth.Clear);
+ } else {
+ _mesa_meta_setup_vertex_objects(&clear->VAO, &clear->VBO, false, 3, 0, 4);
+
+ x0 = (float) fb->_Xmin;
+ y0 = (float) fb->_Ymin;
+ x1 = (float) fb->_Xmax;
+ y1 = (float) fb->_Ymax;
+ z = invert_z(ctx->Depth.Clear);
+ }
if (fb->_IntegerColor) {
+ assert(glsl);
_mesa_UseProgram(clear->IntegerShaderProg);
_mesa_Uniform4iv(clear->IntegerColorLocation, 1,
ctx->Color.ClearColor.i);
- } else {
+ } else if (glsl) {
_mesa_UseProgram(clear->ShaderProg);
_mesa_Uniform4fv(clear->ColorLocation, 1,
ctx->Color.ClearColor.f);
@@ -1734,7 +1774,10 @@ _mesa_meta_glsl_Clear(struct gl_context *ctx, GLbitfield buffers)
/* GL_COLOR_BUFFER_BIT */
if (buffers & BUFFER_BITS_COLOR) {
- /* leave colormask, glDrawBuffer state as-is */
+ /* Only draw to the buffers we were asked to clear. */
+ drawbuffers_from_bitfield(buffers & BUFFER_BITS_COLOR);
+
+ /* leave colormask state as-is */
/* Clears never have the color clamped. */
if (ctx->Extensions.ARB_color_buffer_float)
@@ -1782,6 +1825,15 @@ _mesa_meta_glsl_Clear(struct gl_context *ctx, GLbitfield buffers)
verts[3].y = y1;
verts[3].z = z;
+ if (!glsl) {
+ for (i = 0; i < 4; i++) {
+ verts[i].r = ctx->Color.ClearColor.f[0];
+ verts[i].g = ctx->Color.ClearColor.f[1];
+ verts[i].b = ctx->Color.ClearColor.f[2];
+ verts[i].a = ctx->Color.ClearColor.f[3];
+ }
+ }
+
/* upload new vertex data */
_mesa_BufferData(GL_ARRAY_BUFFER_ARB, sizeof(verts), verts,
GL_DYNAMIC_DRAW_ARB);
@@ -1789,6 +1841,7 @@ _mesa_meta_glsl_Clear(struct gl_context *ctx, GLbitfield buffers)
/* draw quad(s) */
if (fb->MaxNumLayers > 0) {
unsigned layer;
+ assert(glsl);
for (layer = 0; layer < fb->MaxNumLayers; layer++) {
if (fb->_IntegerColor)
_mesa_Uniform1i(clear->IntegerLayerLocation, layer);
@@ -2756,7 +2809,7 @@ copytexsubimage_using_blit_framebuffer(struct gl_context *ctx, GLuint dims,
_mesa_unlock_texture(ctx, texObj);
- _mesa_meta_begin(ctx, MESA_META_ALL);
+ _mesa_meta_begin(ctx, MESA_META_ALL & ~MESA_META_DRAW_BUFFERS);
_mesa_GenFramebuffers(1, &fbo);
_mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
@@ -2978,7 +3031,8 @@ decompress_texture_image(struct gl_context *ctx,
break;
}
- _mesa_meta_begin(ctx, MESA_META_ALL & ~MESA_META_PIXEL_STORE);
+ _mesa_meta_begin(ctx, MESA_META_ALL & ~(MESA_META_PIXEL_STORE |
+ MESA_META_DRAW_BUFFERS));
samplerSave = ctx->Texture.Unit[ctx->Texture.CurrentUnit].Sampler ?
ctx->Texture.Unit[ctx->Texture.CurrentUnit].Sampler->Name : 0;
diff --git a/mesalib/src/mesa/drivers/common/meta.h b/mesalib/src/mesa/drivers/common/meta.h
index fde4f9a7a..32b71fae7 100644
--- a/mesalib/src/mesa/drivers/common/meta.h
+++ b/mesalib/src/mesa/drivers/common/meta.h
@@ -58,6 +58,7 @@
#define MESA_META_MULTISAMPLE 0x100000
#define MESA_META_FRAMEBUFFER_SRGB 0x200000
#define MESA_META_OCCLUSION_QUERY 0x400000
+#define MESA_META_DRAW_BUFFERS 0x800000
/**\}*/
/**
@@ -121,7 +122,6 @@ struct save_state
GLboolean ATIFragmentShaderEnabled;
struct gl_shader_program *Shader[MESA_SHADER_STAGES];
struct gl_shader_program *ActiveShader;
- struct gl_pipeline_object *_Shader;
struct gl_pipeline_object *Pipeline;
/** MESA_META_STENCIL_TEST */
@@ -181,6 +181,9 @@ struct save_state
GLboolean TransformFeedbackNeedsResume;
GLuint DrawBufferName, ReadBufferName, RenderbufferName;
+
+ /** MESA_META_DRAW_BUFFERS */
+ GLenum ColorDrawBuffers[MAX_DRAW_BUFFERS];
};
/**
diff --git a/mesalib/src/mesa/drivers/common/meta_blit.c b/mesalib/src/mesa/drivers/common/meta_blit.c
index 5d72dd2ec..c3dc14614 100644
--- a/mesalib/src/mesa/drivers/common/meta_blit.c
+++ b/mesalib/src/mesa/drivers/common/meta_blit.c
@@ -659,7 +659,7 @@ _mesa_meta_BlitFramebuffer(struct gl_context *ctx,
/* Only scissor affects blit, but we're doing to set a custom scissor if
* necessary anyway, so save/clear state.
*/
- _mesa_meta_begin(ctx, MESA_META_ALL);
+ _mesa_meta_begin(ctx, MESA_META_ALL & ~MESA_META_DRAW_BUFFERS);
/* If the clipping earlier changed the destination rect at all, then
* enable the scissor to clip to it.
diff --git a/mesalib/src/mesa/drivers/common/meta_generate_mipmap.c b/mesalib/src/mesa/drivers/common/meta_generate_mipmap.c
index 3c9ac89af..d12806c3d 100644
--- a/mesalib/src/mesa/drivers/common/meta_generate_mipmap.c
+++ b/mesalib/src/mesa/drivers/common/meta_generate_mipmap.c
@@ -182,7 +182,7 @@ _mesa_meta_GenerateMipmap(struct gl_context *ctx, GLenum target,
faceTarget = target;
}
- _mesa_meta_begin(ctx, MESA_META_ALL);
+ _mesa_meta_begin(ctx, MESA_META_ALL & ~MESA_META_DRAW_BUFFERS);
/* Choose between glsl version and fixed function version of
* GenerateMipmap function.
diff --git a/mesalib/src/mesa/main/bufferobj.c b/mesalib/src/mesa/main/bufferobj.c
index 36acd64ce..7b1bba097 100644
--- a/mesalib/src/mesa/main/bufferobj.c
+++ b/mesalib/src/mesa/main/bufferobj.c
@@ -975,6 +975,78 @@ _mesa_lookup_bufferobj(struct gl_context *ctx, GLuint buffer)
}
+struct gl_buffer_object *
+_mesa_lookup_bufferobj_locked(struct gl_context *ctx, GLuint buffer)
+{
+ return (struct gl_buffer_object *)
+ _mesa_HashLookupLocked(ctx->Shared->BufferObjects, buffer);
+}
+
+
+void
+_mesa_begin_bufferobj_lookups(struct gl_context *ctx)
+{
+ _mesa_HashLockMutex(ctx->Shared->BufferObjects);
+}
+
+
+void
+_mesa_end_bufferobj_lookups(struct gl_context *ctx)
+{
+ _mesa_HashUnlockMutex(ctx->Shared->BufferObjects);
+}
+
+
+/**
+ * Look up a buffer object for a multi-bind function.
+ *
+ * Unlike _mesa_lookup_bufferobj(), this function also takes care
+ * of generating an error if the buffer ID is not zero or the name
+ * of an existing buffer object.
+ *
+ * If the buffer ID refers to an existing buffer object, a pointer
+ * to the buffer object is returned. If the ID is zero, a pointer
+ * to the shared NullBufferObj is returned. If the ID is not zero
+ * and does not refer to a valid buffer object, this function
+ * returns NULL.
+ *
+ * This function assumes that the caller has already locked the
+ * hash table mutex by calling _mesa_begin_bufferobj_lookups().
+ */
+struct gl_buffer_object *
+_mesa_multi_bind_lookup_bufferobj(struct gl_context *ctx,
+ const GLuint *buffers,
+ GLuint index, const char *caller)
+{
+ struct gl_buffer_object *bufObj;
+
+ if (buffers[index] != 0) {
+ bufObj = _mesa_lookup_bufferobj_locked(ctx, buffers[index]);
+
+ /* The multi-bind functions don't create the buffer objects
+ when they don't exist. */
+ if (bufObj == &DummyBufferObject)
+ bufObj = NULL;
+ } else
+ bufObj = ctx->Shared->NullBufferObj;
+
+ if (!bufObj) {
+ /* The ARB_multi_bind spec says:
+ *
+ * "An INVALID_OPERATION error is generated if any value
+ * in <buffers> is not zero or the name of an existing
+ * buffer object (per binding)."
+ */
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "%s(buffers[%u]=%u is not zero or the name "
+ "of an existing buffer object)",
+ caller, index, buffers[index]);
+ }
+
+ return bufObj;
+}
+
+
/**
* If *ptr points to obj, set ptr = the Null/default buffer object.
* This is a helper for buffer object deletion.
@@ -2529,17 +2601,45 @@ _mesa_GetObjectParameterivAPPLE(GLenum objectType, GLuint name, GLenum pname,
}
}
+/**
+ * Binds a buffer object to a uniform buffer binding point.
+ *
+ * The caller is responsible for flushing vertices and updating
+ * NewDriverState.
+ */
static void
set_ubo_binding(struct gl_context *ctx,
- int index,
- struct gl_buffer_object *bufObj,
- GLintptr offset,
- GLsizeiptr size,
- GLboolean autoSize)
+ struct gl_uniform_buffer_binding *binding,
+ struct gl_buffer_object *bufObj,
+ GLintptr offset,
+ GLsizeiptr size,
+ GLboolean autoSize)
+{
+ _mesa_reference_buffer_object(ctx, &binding->BufferObject, bufObj);
+
+ binding->Offset = offset;
+ binding->Size = size;
+ binding->AutomaticSize = autoSize;
+}
+
+/**
+ * Binds a buffer object to a uniform buffer binding point.
+ *
+ * Unlike set_ubo_binding(), this function also flushes vertices
+ * and updates NewDriverState. It also checks if the binding
+ * has actually changed before updating it.
+ */
+static void
+bind_uniform_buffer(struct gl_context *ctx,
+ GLuint index,
+ struct gl_buffer_object *bufObj,
+ GLintptr offset,
+ GLsizeiptr size,
+ GLboolean autoSize)
{
- struct gl_uniform_buffer_binding *binding;
+ struct gl_uniform_buffer_binding *binding =
+ &ctx->UniformBufferBindings[index];
- binding = &ctx->UniformBufferBindings[index];
if (binding->BufferObject == bufObj &&
binding->Offset == offset &&
binding->Size == size &&
@@ -2550,10 +2650,7 @@ set_ubo_binding(struct gl_context *ctx,
FLUSH_VERTICES(ctx, 0);
ctx->NewDriverState |= ctx->DriverFlags.NewUniformBuffer;
- _mesa_reference_buffer_object(ctx, &binding->BufferObject, bufObj);
- binding->Offset = offset;
- binding->Size = size;
- binding->AutomaticSize = autoSize;
+ set_ubo_binding(ctx, binding, bufObj, offset, size, autoSize);
}
/**
@@ -2588,7 +2685,7 @@ bind_buffer_range_uniform_buffer(struct gl_context *ctx,
}
_mesa_reference_buffer_object(ctx, &ctx->UniformBuffer, bufObj);
- set_ubo_binding(ctx, index, bufObj, offset, size, GL_FALSE);
+ bind_uniform_buffer(ctx, index, bufObj, offset, size, GL_FALSE);
}
@@ -2607,19 +2704,52 @@ bind_buffer_base_uniform_buffer(struct gl_context *ctx,
}
_mesa_reference_buffer_object(ctx, &ctx->UniformBuffer, bufObj);
+
if (bufObj == ctx->Shared->NullBufferObj)
- set_ubo_binding(ctx, index, bufObj, -1, -1, GL_TRUE);
+ bind_uniform_buffer(ctx, index, bufObj, -1, -1, GL_TRUE);
else
- set_ubo_binding(ctx, index, bufObj, 0, 0, GL_TRUE);
+ bind_uniform_buffer(ctx, index, bufObj, 0, 0, GL_TRUE);
}
+/**
+ * Binds a buffer object to an atomic buffer binding point.
+ *
+ * The caller is responsible for validating the offset,
+ * flushing the vertices and updating NewDriverState.
+ */
static void
set_atomic_buffer_binding(struct gl_context *ctx,
- unsigned index,
+ struct gl_atomic_buffer_binding *binding,
struct gl_buffer_object *bufObj,
GLintptr offset,
- GLsizeiptr size,
- const char *name)
+ GLsizeiptr size)
+{
+ _mesa_reference_buffer_object(ctx, &binding->BufferObject, bufObj);
+
+ if (bufObj == ctx->Shared->NullBufferObj) {
+ binding->Offset = -1;
+ binding->Size = -1;
+ } else {
+ binding->Offset = offset;
+ binding->Size = size;
+ }
+}
+
+/**
+ * Binds a buffer object to an atomic buffer binding point.
+ *
+ * Unlike set_atomic_buffer_binding(), this function also validates the
+ * index and offset, flushes vertices, and updates NewDriverState.
+ * It also checks if the binding has actually changing before
+ * updating it.
+ */
+static void
+bind_atomic_buffer(struct gl_context *ctx,
+ unsigned index,
+ struct gl_buffer_object *bufObj,
+ GLintptr offset,
+ GLsizeiptr size,
+ const char *name)
{
struct gl_atomic_buffer_binding *binding;
@@ -2647,15 +2777,704 @@ set_atomic_buffer_binding(struct gl_context *ctx,
FLUSH_VERTICES(ctx, 0);
ctx->NewDriverState |= ctx->DriverFlags.NewAtomicBuffer;
- _mesa_reference_buffer_object(ctx, &binding->BufferObject, bufObj);
+ set_atomic_buffer_binding(ctx, binding, bufObj, offset, size);
+}
- if (bufObj == ctx->Shared->NullBufferObj) {
- binding->Offset = -1;
- binding->Size = -1;
- } else {
- binding->Offset = offset;
- binding->Size = size;
+static inline bool
+bind_buffers_check_offset_and_size(struct gl_context *ctx,
+ GLuint index,
+ const GLintptr *offsets,
+ const GLsizeiptr *sizes)
+{
+ if (offsets[index] < 0) {
+ /* The ARB_multi_bind spec says:
+ *
+ * "An INVALID_VALUE error is generated by BindBuffersRange if any
+ * value in <offsets> is less than zero (per binding)."
+ */
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glBindBuffersRange(offsets[%u]=%lld < 0)",
+ index, (long long int) offsets[index]);
+ return false;
+ }
+
+ if (sizes[index] <= 0) {
+ /* The ARB_multi_bind spec says:
+ *
+ * "An INVALID_VALUE error is generated by BindBuffersRange if any
+ * value in <sizes> is less than or equal to zero (per binding)."
+ */
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glBindBuffersRange(sizes[%u]=%lld <= 0)",
+ index, (long long int) sizes[index]);
+ return false;
+ }
+
+ return true;
+}
+
+static bool
+error_check_bind_uniform_buffers(struct gl_context *ctx,
+ GLuint first, GLsizei count,
+ const char *caller)
+{
+ if (!ctx->Extensions.ARB_uniform_buffer_object) {
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "%s(target=GL_UNIFORM_BUFFER)", caller);
+ return false;
+ }
+
+ /* The ARB_multi_bind_spec says:
+ *
+ * "An INVALID_OPERATION error is generated if <first> + <count> is
+ * greater than the number of target-specific indexed binding points,
+ * as described in section 6.7.1."
+ */
+ if (first + count > ctx->Const.MaxUniformBufferBindings) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "%s(first=%u + count=%d > the value of "
+ "GL_MAX_UNIFORM_BUFFER_BINDINGS=%u)",
+ caller, first, count,
+ ctx->Const.MaxUniformBufferBindings);
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Unbind all uniform buffers in the range
+ * <first> through <first>+<count>-1
+ */
+static void
+unbind_uniform_buffers(struct gl_context *ctx, GLuint first, GLsizei count)
+{
+ struct gl_buffer_object *bufObj = ctx->Shared->NullBufferObj;
+ GLuint i;
+
+ for (i = 0; i < count; i++)
+ set_ubo_binding(ctx, &ctx->UniformBufferBindings[first + i],
+ bufObj, -1, -1, GL_TRUE);
+}
+
+static void
+bind_uniform_buffers_base(struct gl_context *ctx, GLuint first, GLsizei count,
+ const GLuint *buffers)
+{
+ GLuint i;
+
+ if (!error_check_bind_uniform_buffers(ctx, first, count, "glBindBuffersBase"))
+ return;
+
+ /* Assume that at least one binding will be changed */
+ FLUSH_VERTICES(ctx, 0);
+ ctx->NewDriverState |= ctx->DriverFlags.NewUniformBuffer;
+
+ if (!buffers) {
+ /* The ARB_multi_bind spec says:
+ *
+ * "If <buffers> is NULL, all bindings from <first> through
+ * <first>+<count>-1 are reset to their unbound (zero) state."
+ */
+ unbind_uniform_buffers(ctx, first, count);
+ return;
+ }
+
+ /* Note that the error semantics for multi-bind commands differ from
+ * those of other GL commands.
+ *
+ * The Issues section in the ARB_multi_bind spec says:
+ *
+ * "(11) Typically, OpenGL specifies that if an error is generated by a
+ * command, that command has no effect. This is somewhat
+ * unfortunate for multi-bind commands, because it would require a
+ * first pass to scan the entire list of bound objects for errors
+ * and then a second pass to actually perform the bindings.
+ * Should we have different error semantics?
+ *
+ * RESOLVED: Yes. In this specification, when the parameters for
+ * one of the <count> binding points are invalid, that binding point
+ * is not updated and an error will be generated. However, other
+ * binding points in the same command will be updated if their
+ * parameters are valid and no other error occurs."
+ */
+
+ _mesa_begin_bufferobj_lookups(ctx);
+
+ for (i = 0; i < count; i++) {
+ struct gl_uniform_buffer_binding *binding =
+ &ctx->UniformBufferBindings[first + i];
+ struct gl_buffer_object *bufObj;
+
+ if (binding->BufferObject && binding->BufferObject->Name == buffers[i])
+ bufObj = binding->BufferObject;
+ else
+ bufObj = _mesa_multi_bind_lookup_bufferobj(ctx, buffers, i,
+ "glBindBuffersBase");
+
+ if (bufObj) {
+ if (bufObj == ctx->Shared->NullBufferObj)
+ set_ubo_binding(ctx, binding, bufObj, -1, -1, GL_TRUE);
+ else
+ set_ubo_binding(ctx, binding, bufObj, 0, 0, GL_TRUE);
+ }
+ }
+
+ _mesa_end_bufferobj_lookups(ctx);
+}
+
+static void
+bind_uniform_buffers_range(struct gl_context *ctx, GLuint first, GLsizei count,
+ const GLuint *buffers,
+ const GLintptr *offsets, const GLsizeiptr *sizes)
+{
+ GLuint i;
+
+ if (!error_check_bind_uniform_buffers(ctx, first, count,
+ "glBindBuffersRange"))
+ return;
+
+ /* Assume that at least one binding will be changed */
+ FLUSH_VERTICES(ctx, 0);
+ ctx->NewDriverState |= ctx->DriverFlags.NewUniformBuffer;
+
+ if (!buffers) {
+ /* The ARB_multi_bind spec says:
+ *
+ * "If <buffers> is NULL, all bindings from <first> through
+ * <first>+<count>-1 are reset to their unbound (zero) state.
+ * In this case, the offsets and sizes associated with the
+ * binding points are set to default values, ignoring
+ * <offsets> and <sizes>."
+ */
+ unbind_uniform_buffers(ctx, first, count);
+ return;
+ }
+
+ /* Note that the error semantics for multi-bind commands differ from
+ * those of other GL commands.
+ *
+ * The Issues section in the ARB_multi_bind spec says:
+ *
+ * "(11) Typically, OpenGL specifies that if an error is generated by a
+ * command, that command has no effect. This is somewhat
+ * unfortunate for multi-bind commands, because it would require a
+ * first pass to scan the entire list of bound objects for errors
+ * and then a second pass to actually perform the bindings.
+ * Should we have different error semantics?
+ *
+ * RESOLVED: Yes. In this specification, when the parameters for
+ * one of the <count> binding points are invalid, that binding point
+ * is not updated and an error will be generated. However, other
+ * binding points in the same command will be updated if their
+ * parameters are valid and no other error occurs."
+ */
+
+ _mesa_begin_bufferobj_lookups(ctx);
+
+ for (i = 0; i < count; i++) {
+ struct gl_uniform_buffer_binding *binding =
+ &ctx->UniformBufferBindings[first + i];
+ struct gl_buffer_object *bufObj;
+
+ if (!bind_buffers_check_offset_and_size(ctx, i, offsets, sizes))
+ continue;
+
+ /* The ARB_multi_bind spec says:
+ *
+ * "An INVALID_VALUE error is generated by BindBuffersRange if any
+ * pair of values in <offsets> and <sizes> does not respectively
+ * satisfy the constraints described for those parameters for the
+ * specified target, as described in section 6.7.1 (per binding)."
+ *
+ * Section 6.7.1 refers to table 6.5, which says:
+ *
+ * "┌───────────────────────────────────────────────────────────────┐
+ * │ Uniform buffer array bindings (see sec. 7.6) │
+ * ├─────────────────────┬─────────────────────────────────────────┤
+ * │ ... │ ... │
+ * │ offset restriction │ multiple of value of UNIFORM_BUFFER_- │
+ * │ │ OFFSET_ALIGNMENT │
+ * │ ... │ ... │
+ * │ size restriction │ none │
+ * └─────────────────────┴─────────────────────────────────────────┘"
+ */
+ if (offsets[i] & (ctx->Const.UniformBufferOffsetAlignment - 1)) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glBindBuffersRange(offsets[%u]=%lld is misaligned; "
+ "it must be a multiple of the value of "
+ "GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT=%u when "
+ "target=GL_UNIFORM_BUFFER)",
+ i, (long long int) offsets[i],
+ ctx->Const.UniformBufferOffsetAlignment);
+ continue;
+ }
+
+ if (binding->BufferObject && binding->BufferObject->Name == buffers[i])
+ bufObj = binding->BufferObject;
+ else
+ bufObj = _mesa_multi_bind_lookup_bufferobj(ctx, buffers, i,
+ "glBindBuffersRange");
+
+ if (bufObj) {
+ if (bufObj == ctx->Shared->NullBufferObj)
+ set_ubo_binding(ctx, binding, bufObj, -1, -1, GL_FALSE);
+ else
+ set_ubo_binding(ctx, binding, bufObj,
+ offsets[i], sizes[i], GL_FALSE);
+ }
+ }
+
+ _mesa_end_bufferobj_lookups(ctx);
+}
+
+static bool
+error_check_bind_xfb_buffers(struct gl_context *ctx,
+ struct gl_transform_feedback_object *tfObj,
+ GLuint first, GLsizei count, const char *caller)
+{
+ if (!ctx->Extensions.EXT_transform_feedback) {
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "%s(target=GL_TRANSFORM_FEEDBACK_BUFFER)", caller);
+ return false;
}
+
+ /* Page 398 of the PDF of the OpenGL 4.4 (Core Profile) spec says:
+ *
+ * "An INVALID_OPERATION error is generated :
+ *
+ * ...
+ * • by BindBufferRange or BindBufferBase if target is TRANSFORM_-
+ * FEEDBACK_BUFFER and transform feedback is currently active."
+ *
+ * We assume that this is also meant to apply to BindBuffersRange
+ * and BindBuffersBase.
+ */
+ if (tfObj->Active) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "%s(Changing transform feedback buffers while "
+ "transform feedback is active)", caller);
+ return false;
+ }
+
+ /* The ARB_multi_bind_spec says:
+ *
+ * "An INVALID_OPERATION error is generated if <first> + <count> is
+ * greater than the number of target-specific indexed binding points,
+ * as described in section 6.7.1."
+ */
+ if (first + count > ctx->Const.MaxTransformFeedbackBuffers) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "%s(first=%u + count=%d > the value of "
+ "GL_MAX_TRANSFORM_FEEDBACK_BUFFERS=%u)",
+ caller, first, count,
+ ctx->Const.MaxTransformFeedbackBuffers);
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Unbind all transform feedback buffers in the range
+ * <first> through <first>+<count>-1
+ */
+static void
+unbind_xfb_buffers(struct gl_context *ctx,
+ struct gl_transform_feedback_object *tfObj,
+ GLuint first, GLsizei count)
+{
+ struct gl_buffer_object * const bufObj = ctx->Shared->NullBufferObj;
+ GLuint i;
+
+ for (i = 0; i < count; i++)
+ _mesa_set_transform_feedback_binding(ctx, tfObj, first + i,
+ bufObj, 0, 0);
+}
+
+static void
+bind_xfb_buffers_base(struct gl_context *ctx,
+ GLuint first, GLsizei count,
+ const GLuint *buffers)
+{
+ struct gl_transform_feedback_object *tfObj =
+ ctx->TransformFeedback.CurrentObject;
+ GLuint i;
+
+ if (!error_check_bind_xfb_buffers(ctx, tfObj, first, count,
+ "glBindBuffersBase"))
+ return;
+
+ /* Assume that at least one binding will be changed */
+ FLUSH_VERTICES(ctx, 0);
+ ctx->NewDriverState |= ctx->DriverFlags.NewTransformFeedback;
+
+ if (!buffers) {
+ /* The ARB_multi_bind spec says:
+ *
+ * "If <buffers> is NULL, all bindings from <first> through
+ * <first>+<count>-1 are reset to their unbound (zero) state."
+ */
+ unbind_xfb_buffers(ctx, tfObj, first, count);
+ return;
+ }
+
+ /* Note that the error semantics for multi-bind commands differ from
+ * those of other GL commands.
+ *
+ * The Issues section in the ARB_multi_bind spec says:
+ *
+ * "(11) Typically, OpenGL specifies that if an error is generated by a
+ * command, that command has no effect. This is somewhat
+ * unfortunate for multi-bind commands, because it would require a
+ * first pass to scan the entire list of bound objects for errors
+ * and then a second pass to actually perform the bindings.
+ * Should we have different error semantics?
+ *
+ * RESOLVED: Yes. In this specification, when the parameters for
+ * one of the <count> binding points are invalid, that binding point
+ * is not updated and an error will be generated. However, other
+ * binding points in the same command will be updated if their
+ * parameters are valid and no other error occurs."
+ */
+
+ _mesa_begin_bufferobj_lookups(ctx);
+
+ for (i = 0; i < count; i++) {
+ struct gl_buffer_object * const boundBufObj = tfObj->Buffers[first + i];
+ struct gl_buffer_object *bufObj;
+
+ if (boundBufObj && boundBufObj->Name == buffers[i])
+ bufObj = boundBufObj;
+ else
+ bufObj = _mesa_multi_bind_lookup_bufferobj(ctx, buffers, i,
+ "glBindBuffersBase");
+
+ if (bufObj)
+ _mesa_set_transform_feedback_binding(ctx, tfObj, first + i,
+ bufObj, 0, 0);
+ }
+
+ _mesa_end_bufferobj_lookups(ctx);
+}
+
+static void
+bind_xfb_buffers_range(struct gl_context *ctx,
+ GLuint first, GLsizei count,
+ const GLuint *buffers,
+ const GLintptr *offsets,
+ const GLsizeiptr *sizes)
+{
+ struct gl_transform_feedback_object *tfObj =
+ ctx->TransformFeedback.CurrentObject;
+ GLuint i;
+
+ if (!error_check_bind_xfb_buffers(ctx, tfObj, first, count,
+ "glBindBuffersRange"))
+ return;
+
+ /* Assume that at least one binding will be changed */
+ FLUSH_VERTICES(ctx, 0);
+ ctx->NewDriverState |= ctx->DriverFlags.NewTransformFeedback;
+
+ if (!buffers) {
+ /* The ARB_multi_bind spec says:
+ *
+ * "If <buffers> is NULL, all bindings from <first> through
+ * <first>+<count>-1 are reset to their unbound (zero) state.
+ * In this case, the offsets and sizes associated with the
+ * binding points are set to default values, ignoring
+ * <offsets> and <sizes>."
+ */
+ unbind_xfb_buffers(ctx, tfObj, first, count);
+ return;
+ }
+
+ /* Note that the error semantics for multi-bind commands differ from
+ * those of other GL commands.
+ *
+ * The Issues section in the ARB_multi_bind spec says:
+ *
+ * "(11) Typically, OpenGL specifies that if an error is generated by a
+ * command, that command has no effect. This is somewhat
+ * unfortunate for multi-bind commands, because it would require a
+ * first pass to scan the entire list of bound objects for errors
+ * and then a second pass to actually perform the bindings.
+ * Should we have different error semantics?
+ *
+ * RESOLVED: Yes. In this specification, when the parameters for
+ * one of the <count> binding points are invalid, that binding point
+ * is not updated and an error will be generated. However, other
+ * binding points in the same command will be updated if their
+ * parameters are valid and no other error occurs."
+ */
+
+ _mesa_begin_bufferobj_lookups(ctx);
+
+ for (i = 0; i < count; i++) {
+ const GLuint index = first + i;
+ struct gl_buffer_object * const boundBufObj = tfObj->Buffers[index];
+ struct gl_buffer_object *bufObj;
+
+ if (!bind_buffers_check_offset_and_size(ctx, i, offsets, sizes))
+ continue;
+
+ /* The ARB_multi_bind spec says:
+ *
+ * "An INVALID_VALUE error is generated by BindBuffersRange if any
+ * pair of values in <offsets> and <sizes> does not respectively
+ * satisfy the constraints described for those parameters for the
+ * specified target, as described in section 6.7.1 (per binding)."
+ *
+ * Section 6.7.1 refers to table 6.5, which says:
+ *
+ * "┌───────────────────────────────────────────────────────────────┐
+ * │ Transform feedback array bindings (see sec. 13.2.2) │
+ * ├───────────────────────┬───────────────────────────────────────┤
+ * │ ... │ ... │
+ * │ offset restriction │ multiple of 4 │
+ * │ ... │ ... │
+ * │ size restriction │ multiple of 4 │
+ * └───────────────────────┴───────────────────────────────────────┘"
+ */
+ if (offsets[i] & 0x3) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glBindBuffersRange(offsets[%u]=%lld is misaligned; "
+ "it must be a multiple of 4 when "
+ "target=GL_TRANSFORM_FEEDBACK_BUFFER)",
+ i, (long long int) offsets[i]);
+ continue;
+ }
+
+ if (sizes[i] & 0x3) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glBindBuffersRange(sizes[%u]=%lld is misaligned; "
+ "it must be a multiple of 4 when "
+ "target=GL_TRANSFORM_FEEDBACK_BUFFER)",
+ i, (long long int) sizes[i]);
+ continue;
+ }
+
+ if (boundBufObj && boundBufObj->Name == buffers[i])
+ bufObj = boundBufObj;
+ else
+ bufObj = _mesa_multi_bind_lookup_bufferobj(ctx, buffers, i,
+ "glBindBuffersRange");
+
+ if (bufObj)
+ _mesa_set_transform_feedback_binding(ctx, tfObj, index, bufObj,
+ offsets[i], sizes[i]);
+ }
+
+ _mesa_end_bufferobj_lookups(ctx);
+}
+
+static bool
+error_check_bind_atomic_buffers(struct gl_context *ctx,
+ GLuint first, GLsizei count,
+ const char *caller)
+{
+ if (!ctx->Extensions.ARB_shader_atomic_counters) {
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "%s(target=GL_ATOMIC_COUNTER_BUFFER)", caller);
+ return false;
+ }
+
+ /* The ARB_multi_bind_spec says:
+ *
+ * "An INVALID_OPERATION error is generated if <first> + <count> is
+ * greater than the number of target-specific indexed binding points,
+ * as described in section 6.7.1."
+ */
+ if (first + count > ctx->Const.MaxAtomicBufferBindings) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "%s(first=%u + count=%d > the value of "
+ "GL_MAX_ATOMIC_BUFFER_BINDINGS=%u)",
+ caller, first, count, ctx->Const.MaxAtomicBufferBindings);
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Unbind all atomic counter buffers in the range
+ * <first> through <first>+<count>-1
+ */
+static void
+unbind_atomic_buffers(struct gl_context *ctx, GLuint first, GLsizei count)
+{
+ struct gl_buffer_object * const bufObj = ctx->Shared->NullBufferObj;
+ GLuint i;
+
+ for (i = 0; i < count; i++)
+ set_atomic_buffer_binding(ctx, &ctx->AtomicBufferBindings[first + i],
+ bufObj, -1, -1);
+}
+
+static void
+bind_atomic_buffers_base(struct gl_context *ctx,
+ GLuint first,
+ GLsizei count,
+ const GLuint *buffers)
+{
+ GLuint i;
+
+ if (!error_check_bind_atomic_buffers(ctx, first, count,
+ "glBindBuffersBase"))
+ return;
+
+ /* Assume that at least one binding will be changed */
+ FLUSH_VERTICES(ctx, 0);
+ ctx->NewDriverState |= ctx->DriverFlags.NewAtomicBuffer;
+
+ if (!buffers) {
+ /* The ARB_multi_bind spec says:
+ *
+ * "If <buffers> is NULL, all bindings from <first> through
+ * <first>+<count>-1 are reset to their unbound (zero) state."
+ */
+ unbind_atomic_buffers(ctx, first, count);
+ return;
+ }
+
+ /* Note that the error semantics for multi-bind commands differ from
+ * those of other GL commands.
+ *
+ * The Issues section in the ARB_multi_bind spec says:
+ *
+ * "(11) Typically, OpenGL specifies that if an error is generated by a
+ * command, that command has no effect. This is somewhat
+ * unfortunate for multi-bind commands, because it would require a
+ * first pass to scan the entire list of bound objects for errors
+ * and then a second pass to actually perform the bindings.
+ * Should we have different error semantics?
+ *
+ * RESOLVED: Yes. In this specification, when the parameters for
+ * one of the <count> binding points are invalid, that binding point
+ * is not updated and an error will be generated. However, other
+ * binding points in the same command will be updated if their
+ * parameters are valid and no other error occurs."
+ */
+
+ _mesa_begin_bufferobj_lookups(ctx);
+
+ for (i = 0; i < count; i++) {
+ struct gl_atomic_buffer_binding *binding =
+ &ctx->AtomicBufferBindings[first + i];
+ struct gl_buffer_object *bufObj;
+
+ if (binding->BufferObject && binding->BufferObject->Name == buffers[i])
+ bufObj = binding->BufferObject;
+ else
+ bufObj = _mesa_multi_bind_lookup_bufferobj(ctx, buffers, i,
+ "glBindBuffersBase");
+
+ if (bufObj)
+ set_atomic_buffer_binding(ctx, binding, bufObj, 0, 0);
+ }
+
+ _mesa_end_bufferobj_lookups(ctx);
+}
+
+static void
+bind_atomic_buffers_range(struct gl_context *ctx,
+ GLuint first,
+ GLsizei count,
+ const GLuint *buffers,
+ const GLintptr *offsets,
+ const GLsizeiptr *sizes)
+{
+ GLuint i;
+
+ if (!error_check_bind_atomic_buffers(ctx, first, count,
+ "glBindBuffersRange"))
+ return;
+
+ /* Assume that at least one binding will be changed */
+ FLUSH_VERTICES(ctx, 0);
+ ctx->NewDriverState |= ctx->DriverFlags.NewAtomicBuffer;
+
+ if (!buffers) {
+ /* The ARB_multi_bind spec says:
+ *
+ * "If <buffers> is NULL, all bindings from <first> through
+ * <first>+<count>-1 are reset to their unbound (zero) state.
+ * In this case, the offsets and sizes associated with the
+ * binding points are set to default values, ignoring
+ * <offsets> and <sizes>."
+ */
+ unbind_atomic_buffers(ctx, first, count);
+ return;
+ }
+
+ /* Note that the error semantics for multi-bind commands differ from
+ * those of other GL commands.
+ *
+ * The Issues section in the ARB_multi_bind spec says:
+ *
+ * "(11) Typically, OpenGL specifies that if an error is generated by a
+ * command, that command has no effect. This is somewhat
+ * unfortunate for multi-bind commands, because it would require a
+ * first pass to scan the entire list of bound objects for errors
+ * and then a second pass to actually perform the bindings.
+ * Should we have different error semantics?
+ *
+ * RESOLVED: Yes. In this specification, when the parameters for
+ * one of the <count> binding points are invalid, that binding point
+ * is not updated and an error will be generated. However, other
+ * binding points in the same command will be updated if their
+ * parameters are valid and no other error occurs."
+ */
+
+ _mesa_begin_bufferobj_lookups(ctx);
+
+ for (i = 0; i < count; i++) {
+ struct gl_atomic_buffer_binding *binding =
+ &ctx->AtomicBufferBindings[first + i];
+ struct gl_buffer_object *bufObj;
+
+ if (!bind_buffers_check_offset_and_size(ctx, i, offsets, sizes))
+ continue;
+
+ /* The ARB_multi_bind spec says:
+ *
+ * "An INVALID_VALUE error is generated by BindBuffersRange if any
+ * pair of values in <offsets> and <sizes> does not respectively
+ * satisfy the constraints described for those parameters for the
+ * specified target, as described in section 6.7.1 (per binding)."
+ *
+ * Section 6.7.1 refers to table 6.5, which says:
+ *
+ * "┌───────────────────────────────────────────────────────────────┐
+ * │ Atomic counter array bindings (see sec. 7.7.2) │
+ * ├───────────────────────┬───────────────────────────────────────┤
+ * │ ... │ ... │
+ * │ offset restriction │ multiple of 4 │
+ * │ ... │ ... │
+ * │ size restriction │ none │
+ * └───────────────────────┴───────────────────────────────────────┘"
+ */
+ if (offsets[i] & (ATOMIC_COUNTER_SIZE - 1)) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glBindBuffersRange(offsets[%u]=%lld is misaligned; "
+ "it must be a multiple of %d when "
+ "target=GL_ATOMIC_COUNTER_BUFFER)",
+ i, (long long int) offsets[i], ATOMIC_COUNTER_SIZE);
+ continue;
+ }
+
+ if (binding->BufferObject && binding->BufferObject->Name == buffers[i])
+ bufObj = binding->BufferObject;
+ else
+ bufObj = _mesa_multi_bind_lookup_bufferobj(ctx, buffers, i,
+ "glBindBuffersRange");
+
+ if (bufObj)
+ set_atomic_buffer_binding(ctx, binding, bufObj, offsets[i], sizes[i]);
+ }
+
+ _mesa_end_bufferobj_lookups(ctx);
}
void GLAPIENTRY
@@ -2697,8 +3516,8 @@ _mesa_BindBufferRange(GLenum target, GLuint index,
bind_buffer_range_uniform_buffer(ctx, index, bufObj, offset, size);
return;
case GL_ATOMIC_COUNTER_BUFFER:
- set_atomic_buffer_binding(ctx, index, bufObj, offset, size,
- "glBindBufferRange");
+ bind_atomic_buffer(ctx, index, bufObj, offset, size,
+ "glBindBufferRange");
return;
default:
_mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferRange(target)");
@@ -2761,8 +3580,8 @@ _mesa_BindBufferBase(GLenum target, GLuint index, GLuint buffer)
bind_buffer_base_uniform_buffer(ctx, index, bufObj);
return;
case GL_ATOMIC_COUNTER_BUFFER:
- set_atomic_buffer_binding(ctx, index, bufObj, 0, 0,
- "glBindBufferBase");
+ bind_atomic_buffer(ctx, index, bufObj, 0, 0,
+ "glBindBufferBase");
return;
default:
_mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferBase(target)");
@@ -2771,6 +3590,54 @@ _mesa_BindBufferBase(GLenum target, GLuint index, GLuint buffer)
}
void GLAPIENTRY
+_mesa_BindBuffersRange(GLenum target, GLuint first, GLsizei count,
+ const GLuint *buffers,
+ const GLintptr *offsets, const GLsizeiptr *sizes)
+{
+ GET_CURRENT_CONTEXT(ctx);
+
+ switch (target) {
+ case GL_TRANSFORM_FEEDBACK_BUFFER:
+ bind_xfb_buffers_range(ctx, first, count, buffers, offsets, sizes);
+ return;
+ case GL_UNIFORM_BUFFER:
+ bind_uniform_buffers_range(ctx, first, count, buffers, offsets, sizes);
+ return;
+ case GL_ATOMIC_COUNTER_BUFFER:
+ bind_atomic_buffers_range(ctx, first, count, buffers,
+ offsets, sizes);
+ return;
+ default:
+ _mesa_error(ctx, GL_INVALID_ENUM, "glBindBuffersRange(target=%s)",
+ _mesa_lookup_enum_by_nr(target));
+ break;
+ }
+}
+
+void GLAPIENTRY
+_mesa_BindBuffersBase(GLenum target, GLuint first, GLsizei count,
+ const GLuint *buffers)
+{
+ GET_CURRENT_CONTEXT(ctx);
+
+ switch (target) {
+ case GL_TRANSFORM_FEEDBACK_BUFFER:
+ bind_xfb_buffers_base(ctx, first, count, buffers);
+ return;
+ case GL_UNIFORM_BUFFER:
+ bind_uniform_buffers_base(ctx, first, count, buffers);
+ return;
+ case GL_ATOMIC_COUNTER_BUFFER:
+ bind_atomic_buffers_base(ctx, first, count, buffers);
+ return;
+ default:
+ _mesa_error(ctx, GL_INVALID_ENUM, "glBindBuffersBase(target=%s)",
+ _mesa_lookup_enum_by_nr(target));
+ break;
+ }
+}
+
+void GLAPIENTRY
_mesa_InvalidateBufferSubData(GLuint buffer, GLintptr offset,
GLsizeiptr length)
{
diff --git a/mesalib/src/mesa/main/bufferobj.h b/mesalib/src/mesa/main/bufferobj.h
index c08c4fdf2..0779605c0 100644
--- a/mesalib/src/mesa/main/bufferobj.h
+++ b/mesalib/src/mesa/main/bufferobj.h
@@ -86,6 +86,20 @@ _mesa_update_default_objects_buffer_objects(struct gl_context *ctx);
extern struct gl_buffer_object *
_mesa_lookup_bufferobj(struct gl_context *ctx, GLuint buffer);
+extern struct gl_buffer_object *
+_mesa_lookup_bufferobj_locked(struct gl_context *ctx, GLuint buffer);
+
+extern void
+_mesa_begin_bufferobj_lookups(struct gl_context *ctx);
+
+extern void
+_mesa_end_bufferobj_lookups(struct gl_context *ctx);
+
+extern struct gl_buffer_object *
+_mesa_multi_bind_lookup_bufferobj(struct gl_context *ctx,
+ const GLuint *buffers,
+ GLuint index, const char *caller);
+
extern void
_mesa_initialize_buffer_object(struct gl_context *ctx,
struct gl_buffer_object *obj,
@@ -210,6 +224,13 @@ void GLAPIENTRY
_mesa_BindBufferBase(GLenum target, GLuint index, GLuint buffer);
void GLAPIENTRY
+_mesa_BindBuffersRange(GLenum target, GLuint first, GLsizei count,
+ const GLuint *buffers,
+ const GLintptr *offsets, const GLsizeiptr *sizes);
+void GLAPIENTRY
+_mesa_BindBuffersBase(GLenum target, GLuint first, GLsizei count,
+ const GLuint *buffers);
+void GLAPIENTRY
_mesa_InvalidateBufferSubData(GLuint buffer, GLintptr offset,
GLsizeiptr length);
diff --git a/mesalib/src/mesa/main/config.h b/mesalib/src/mesa/main/config.h
index 30da5d422..c96502a7f 100644
--- a/mesalib/src/mesa/main/config.h
+++ b/mesalib/src/mesa/main/config.h
@@ -281,6 +281,14 @@
#define MAX_VERTEX_STREAMS 4
/*@}*/
+/** For GL_INTEL_performance_query */
+/*@{*/
+#define MAX_PERFQUERY_QUERY_NAME_LENGTH 256
+#define MAX_PERFQUERY_COUNTER_NAME_LENGTH 256
+#define MAX_PERFQUERY_COUNTER_DESC_LENGTH 1024
+#define PERFQUERY_HAVE_GPA_EXTENDED_COUNTERS 0
+/*@}*/
+
/*
* Color channel component order
*
diff --git a/mesalib/src/mesa/main/dd.h b/mesalib/src/mesa/main/dd.h
index 971524135..633ea2c3a 100644
--- a/mesalib/src/mesa/main/dd.h
+++ b/mesalib/src/mesa/main/dd.h
@@ -314,10 +314,10 @@ struct dd_function_table {
/*@{*/
/**
- * Called by glBindTexture().
+ * Called by glBindTexture() and glBindTextures().
*/
- void (*BindTexture)( struct gl_context *ctx, GLenum target,
- struct gl_texture_object *tObj );
+ void (*BindTexture)( struct gl_context *ctx, GLuint texUnit,
+ GLenum target, struct gl_texture_object *tObj );
/**
* Called to allocate a new texture object. Drivers will usually
diff --git a/mesalib/src/mesa/main/dlist.c b/mesalib/src/mesa/main/dlist.c
index d431fd221..5874b99f0 100644
--- a/mesalib/src/mesa/main/dlist.c
+++ b/mesalib/src/mesa/main/dlist.c
@@ -364,6 +364,42 @@ typedef enum
OPCODE_UNIFORM_3UIV,
OPCODE_UNIFORM_4UIV,
+ /* OpenGL 4.2 / GL_ARB_separate_shader_objects */
+ OPCODE_USE_PROGRAM_STAGES,
+ OPCODE_PROGRAM_UNIFORM_1F,
+ OPCODE_PROGRAM_UNIFORM_2F,
+ OPCODE_PROGRAM_UNIFORM_3F,
+ OPCODE_PROGRAM_UNIFORM_4F,
+ OPCODE_PROGRAM_UNIFORM_1FV,
+ OPCODE_PROGRAM_UNIFORM_2FV,
+ OPCODE_PROGRAM_UNIFORM_3FV,
+ OPCODE_PROGRAM_UNIFORM_4FV,
+ OPCODE_PROGRAM_UNIFORM_1I,
+ OPCODE_PROGRAM_UNIFORM_2I,
+ OPCODE_PROGRAM_UNIFORM_3I,
+ OPCODE_PROGRAM_UNIFORM_4I,
+ OPCODE_PROGRAM_UNIFORM_1IV,
+ OPCODE_PROGRAM_UNIFORM_2IV,
+ OPCODE_PROGRAM_UNIFORM_3IV,
+ OPCODE_PROGRAM_UNIFORM_4IV,
+ OPCODE_PROGRAM_UNIFORM_1UI,
+ OPCODE_PROGRAM_UNIFORM_2UI,
+ OPCODE_PROGRAM_UNIFORM_3UI,
+ OPCODE_PROGRAM_UNIFORM_4UI,
+ OPCODE_PROGRAM_UNIFORM_1UIV,
+ OPCODE_PROGRAM_UNIFORM_2UIV,
+ OPCODE_PROGRAM_UNIFORM_3UIV,
+ OPCODE_PROGRAM_UNIFORM_4UIV,
+ OPCODE_PROGRAM_UNIFORM_MATRIX22F,
+ OPCODE_PROGRAM_UNIFORM_MATRIX33F,
+ OPCODE_PROGRAM_UNIFORM_MATRIX44F,
+ OPCODE_PROGRAM_UNIFORM_MATRIX23F,
+ OPCODE_PROGRAM_UNIFORM_MATRIX32F,
+ OPCODE_PROGRAM_UNIFORM_MATRIX24F,
+ OPCODE_PROGRAM_UNIFORM_MATRIX42F,
+ OPCODE_PROGRAM_UNIFORM_MATRIX34F,
+ OPCODE_PROGRAM_UNIFORM_MATRIX43F,
+
/* GL_ARB_color_buffer_float */
OPCODE_CLAMP_COLOR,
@@ -407,10 +443,6 @@ typedef enum
OPCODE_TEXPARAMETER_I,
OPCODE_TEXPARAMETER_UI,
- /* GL_EXT_separate_shader_objects */
- OPCODE_ACTIVE_PROGRAM_EXT,
- OPCODE_USE_SHADER_PROGRAM_EXT,
-
/* GL_ARB_instanced_arrays */
OPCODE_VERTEX_ATTRIB_DIVISOR,
@@ -765,6 +797,33 @@ _mesa_delete_list(struct gl_context *ctx, struct gl_display_list *dlist)
free(get_pointer(&n[4]));
n += InstSize[n[0].opcode];
break;
+ case OPCODE_PROGRAM_UNIFORM_1FV:
+ case OPCODE_PROGRAM_UNIFORM_2FV:
+ case OPCODE_PROGRAM_UNIFORM_3FV:
+ case OPCODE_PROGRAM_UNIFORM_4FV:
+ case OPCODE_PROGRAM_UNIFORM_1IV:
+ case OPCODE_PROGRAM_UNIFORM_2IV:
+ case OPCODE_PROGRAM_UNIFORM_3IV:
+ case OPCODE_PROGRAM_UNIFORM_4IV:
+ case OPCODE_PROGRAM_UNIFORM_1UIV:
+ case OPCODE_PROGRAM_UNIFORM_2UIV:
+ case OPCODE_PROGRAM_UNIFORM_3UIV:
+ case OPCODE_PROGRAM_UNIFORM_4UIV:
+ free(get_pointer(&n[4]));
+ n += InstSize[n[0].opcode];
+ break;
+ case OPCODE_PROGRAM_UNIFORM_MATRIX22F:
+ case OPCODE_PROGRAM_UNIFORM_MATRIX33F:
+ case OPCODE_PROGRAM_UNIFORM_MATRIX44F:
+ case OPCODE_PROGRAM_UNIFORM_MATRIX24F:
+ case OPCODE_PROGRAM_UNIFORM_MATRIX42F:
+ case OPCODE_PROGRAM_UNIFORM_MATRIX23F:
+ case OPCODE_PROGRAM_UNIFORM_MATRIX32F:
+ case OPCODE_PROGRAM_UNIFORM_MATRIX34F:
+ case OPCODE_PROGRAM_UNIFORM_MATRIX43F:
+ free(get_pointer(&n[5]));
+ n += InstSize[n[0].opcode];
+ break;
case OPCODE_PIXEL_MAP:
free(get_pointer(&n[3]));
n += InstSize[n[0].opcode];
@@ -6510,49 +6569,689 @@ save_UniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose,
}
static void GLAPIENTRY
-save_ClampColorARB(GLenum target, GLenum clamp)
+save_UseProgramStages(GLuint pipeline, GLbitfield stages, GLuint program)
{
GET_CURRENT_CONTEXT(ctx);
Node *n;
ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx);
- n = alloc_instruction(ctx, OPCODE_CLAMP_COLOR, 2);
+ n = alloc_instruction(ctx, OPCODE_USE_PROGRAM_STAGES, 3);
if (n) {
- n[1].e = target;
- n[2].e = clamp;
+ n[1].ui = pipeline;
+ n[2].ui = stages;
+ n[3].ui = program;
}
if (ctx->ExecuteFlag) {
- CALL_ClampColor(ctx->Exec, (target, clamp));
+ CALL_UseProgramStages(ctx->Exec, (pipeline, stages, program));
+ }
+}
+
+static void GLAPIENTRY
+save_ProgramUniform1f(GLuint program, GLint location, GLfloat x)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ Node *n;
+ ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx);
+ n = alloc_instruction(ctx, OPCODE_PROGRAM_UNIFORM_1F, 3);
+ if (n) {
+ n[1].ui = program;
+ n[2].i = location;
+ n[3].f = x;
+ }
+ if (ctx->ExecuteFlag) {
+ CALL_ProgramUniform1f(ctx->Exec, (program, location, x));
+ }
+}
+
+static void GLAPIENTRY
+save_ProgramUniform2f(GLuint program, GLint location, GLfloat x, GLfloat y)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ Node *n;
+ ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx);
+ n = alloc_instruction(ctx, OPCODE_PROGRAM_UNIFORM_2F, 4);
+ if (n) {
+ n[1].ui = program;
+ n[2].i = location;
+ n[3].f = x;
+ n[4].f = y;
+ }
+ if (ctx->ExecuteFlag) {
+ CALL_ProgramUniform2f(ctx->Exec, (program, location, x, y));
+ }
+}
+
+static void GLAPIENTRY
+save_ProgramUniform3f(GLuint program, GLint location,
+ GLfloat x, GLfloat y, GLfloat z)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ Node *n;
+ ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx);
+ n = alloc_instruction(ctx, OPCODE_PROGRAM_UNIFORM_3F, 5);
+ if (n) {
+ n[1].ui = program;
+ n[2].i = location;
+ n[3].f = x;
+ n[4].f = y;
+ n[5].f = z;
+ }
+ if (ctx->ExecuteFlag) {
+ CALL_ProgramUniform3f(ctx->Exec, (program, location, x, y, z));
+ }
+}
+
+static void GLAPIENTRY
+save_ProgramUniform4f(GLuint program, GLint location,
+ GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ Node *n;
+ ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx);
+ n = alloc_instruction(ctx, OPCODE_PROGRAM_UNIFORM_4F, 6);
+ if (n) {
+ n[1].ui = program;
+ n[2].i = location;
+ n[3].f = x;
+ n[4].f = y;
+ n[5].f = z;
+ n[6].f = w;
+ }
+ if (ctx->ExecuteFlag) {
+ CALL_ProgramUniform4f(ctx->Exec, (program, location, x, y, z, w));
+ }
+}
+
+static void GLAPIENTRY
+save_ProgramUniform1fv(GLuint program, GLint location, GLsizei count,
+ const GLfloat *v)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ Node *n;
+ ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx);
+ n = alloc_instruction(ctx, OPCODE_PROGRAM_UNIFORM_1FV, 3 + POINTER_DWORDS);
+ if (n) {
+ n[1].ui = program;
+ n[2].i = location;
+ n[3].i = count;
+ save_pointer(&n[4], memdup(v, count * 1 * sizeof(GLfloat)));
+ }
+ if (ctx->ExecuteFlag) {
+ CALL_ProgramUniform1fv(ctx->Exec, (program, location, count, v));
+ }
+}
+
+static void GLAPIENTRY
+save_ProgramUniform2fv(GLuint program, GLint location, GLsizei count,
+ const GLfloat *v)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ Node *n;
+ ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx);
+ n = alloc_instruction(ctx, OPCODE_PROGRAM_UNIFORM_2FV, 3 + POINTER_DWORDS);
+ if (n) {
+ n[1].ui = program;
+ n[2].i = location;
+ n[3].i = count;
+ save_pointer(&n[4], memdup(v, count * 2 * sizeof(GLfloat)));
+ }
+ if (ctx->ExecuteFlag) {
+ CALL_ProgramUniform2fv(ctx->Exec, (program, location, count, v));
+ }
+}
+
+static void GLAPIENTRY
+save_ProgramUniform3fv(GLuint program, GLint location, GLsizei count,
+ const GLfloat *v)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ Node *n;
+ ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx);
+ n = alloc_instruction(ctx, OPCODE_PROGRAM_UNIFORM_3FV, 3 + POINTER_DWORDS);
+ if (n) {
+ n[1].ui = program;
+ n[2].i = location;
+ n[3].i = count;
+ save_pointer(&n[4], memdup(v, count * 3 * sizeof(GLfloat)));
+ }
+ if (ctx->ExecuteFlag) {
+ CALL_ProgramUniform3fv(ctx->Exec, (program, location, count, v));
}
}
static void GLAPIENTRY
-save_UseShaderProgramEXT(GLenum type, GLuint program)
+save_ProgramUniform4fv(GLuint program, GLint location, GLsizei count,
+ const GLfloat *v)
{
GET_CURRENT_CONTEXT(ctx);
Node *n;
ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx);
- n = alloc_instruction(ctx, OPCODE_USE_SHADER_PROGRAM_EXT, 2);
+ n = alloc_instruction(ctx, OPCODE_PROGRAM_UNIFORM_4FV, 3 + POINTER_DWORDS);
if (n) {
- n[1].ui = type;
- n[2].ui = program;
+ n[1].ui = program;
+ n[2].i = location;
+ n[3].i = count;
+ save_pointer(&n[4], memdup(v, count * 4 * sizeof(GLfloat)));
}
if (ctx->ExecuteFlag) {
- CALL_UseShaderProgramEXT(ctx->Exec, (type, program));
+ CALL_ProgramUniform4fv(ctx->Exec, (program, location, count, v));
}
}
static void GLAPIENTRY
-save_ActiveProgramEXT(GLuint program)
+save_ProgramUniform1i(GLuint program, GLint location, GLint x)
{
GET_CURRENT_CONTEXT(ctx);
Node *n;
ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx);
- n = alloc_instruction(ctx, OPCODE_ACTIVE_PROGRAM_EXT, 1);
+ n = alloc_instruction(ctx, OPCODE_PROGRAM_UNIFORM_1I, 3);
if (n) {
n[1].ui = program;
+ n[2].i = location;
+ n[3].i = x;
}
if (ctx->ExecuteFlag) {
- CALL_ActiveProgramEXT(ctx->Exec, (program));
+ CALL_ProgramUniform1i(ctx->Exec, (program, location, x));
+ }
+}
+
+static void GLAPIENTRY
+save_ProgramUniform2i(GLuint program, GLint location, GLint x, GLint y)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ Node *n;
+ ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx);
+ n = alloc_instruction(ctx, OPCODE_PROGRAM_UNIFORM_2I, 4);
+ if (n) {
+ n[1].ui = program;
+ n[2].i = location;
+ n[3].i = x;
+ n[4].i = y;
+ }
+ if (ctx->ExecuteFlag) {
+ CALL_ProgramUniform2i(ctx->Exec, (program, location, x, y));
+ }
+}
+
+static void GLAPIENTRY
+save_ProgramUniform3i(GLuint program, GLint location,
+ GLint x, GLint y, GLint z)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ Node *n;
+ ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx);
+ n = alloc_instruction(ctx, OPCODE_PROGRAM_UNIFORM_3I, 5);
+ if (n) {
+ n[1].ui = program;
+ n[2].i = location;
+ n[3].i = x;
+ n[4].i = y;
+ n[5].i = z;
+ }
+ if (ctx->ExecuteFlag) {
+ CALL_ProgramUniform3i(ctx->Exec, (program, location, x, y, z));
+ }
+}
+
+static void GLAPIENTRY
+save_ProgramUniform4i(GLuint program, GLint location,
+ GLint x, GLint y, GLint z, GLint w)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ Node *n;
+ ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx);
+ n = alloc_instruction(ctx, OPCODE_PROGRAM_UNIFORM_4I, 6);
+ if (n) {
+ n[1].ui = program;
+ n[2].i = location;
+ n[3].i = x;
+ n[4].i = y;
+ n[5].i = z;
+ n[6].i = w;
+ }
+ if (ctx->ExecuteFlag) {
+ CALL_ProgramUniform4i(ctx->Exec, (program, location, x, y, z, w));
+ }
+}
+
+static void GLAPIENTRY
+save_ProgramUniform1iv(GLuint program, GLint location, GLsizei count,
+ const GLint *v)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ Node *n;
+ ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx);
+ n = alloc_instruction(ctx, OPCODE_PROGRAM_UNIFORM_1IV, 3 + POINTER_DWORDS);
+ if (n) {
+ n[1].ui = program;
+ n[2].i = location;
+ n[3].i = count;
+ save_pointer(&n[4], memdup(v, count * 1 * sizeof(GLint)));
+ }
+ if (ctx->ExecuteFlag) {
+ CALL_ProgramUniform1iv(ctx->Exec, (program, location, count, v));
+ }
+}
+
+static void GLAPIENTRY
+save_ProgramUniform2iv(GLuint program, GLint location, GLsizei count,
+ const GLint *v)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ Node *n;
+ ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx);
+ n = alloc_instruction(ctx, OPCODE_PROGRAM_UNIFORM_2IV, 3 + POINTER_DWORDS);
+ if (n) {
+ n[1].ui = program;
+ n[2].i = location;
+ n[3].i = count;
+ save_pointer(&n[4], memdup(v, count * 2 * sizeof(GLint)));
+ }
+ if (ctx->ExecuteFlag) {
+ CALL_ProgramUniform2iv(ctx->Exec, (program, location, count, v));
+ }
+}
+
+static void GLAPIENTRY
+save_ProgramUniform3iv(GLuint program, GLint location, GLsizei count,
+ const GLint *v)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ Node *n;
+ ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx);
+ n = alloc_instruction(ctx, OPCODE_PROGRAM_UNIFORM_3IV, 3 + POINTER_DWORDS);
+ if (n) {
+ n[1].ui = program;
+ n[2].i = location;
+ n[3].i = count;
+ save_pointer(&n[4], memdup(v, count * 3 * sizeof(GLint)));
+ }
+ if (ctx->ExecuteFlag) {
+ CALL_ProgramUniform3iv(ctx->Exec, (program, location, count, v));
+ }
+}
+
+static void GLAPIENTRY
+save_ProgramUniform4iv(GLuint program, GLint location, GLsizei count,
+ const GLint *v)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ Node *n;
+ ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx);
+ n = alloc_instruction(ctx, OPCODE_PROGRAM_UNIFORM_4IV, 3 + POINTER_DWORDS);
+ if (n) {
+ n[1].ui = program;
+ n[2].i = location;
+ n[3].i = count;
+ save_pointer(&n[4], memdup(v, count * 4 * sizeof(GLint)));
+ }
+ if (ctx->ExecuteFlag) {
+ CALL_ProgramUniform4iv(ctx->Exec, (program, location, count, v));
+ }
+}
+
+static void GLAPIENTRY
+save_ProgramUniform1ui(GLuint program, GLint location, GLuint x)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ Node *n;
+ ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx);
+ n = alloc_instruction(ctx, OPCODE_PROGRAM_UNIFORM_1UI, 3);
+ if (n) {
+ n[1].ui = program;
+ n[2].i = location;
+ n[3].ui = x;
+ }
+ if (ctx->ExecuteFlag) {
+ CALL_ProgramUniform1ui(ctx->Exec, (program, location, x));
+ }
+}
+
+static void GLAPIENTRY
+save_ProgramUniform2ui(GLuint program, GLint location, GLuint x, GLuint y)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ Node *n;
+ ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx);
+ n = alloc_instruction(ctx, OPCODE_PROGRAM_UNIFORM_2UI, 4);
+ if (n) {
+ n[1].ui = program;
+ n[2].i = location;
+ n[3].ui = x;
+ n[4].ui = y;
+ }
+ if (ctx->ExecuteFlag) {
+ CALL_ProgramUniform2ui(ctx->Exec, (program, location, x, y));
+ }
+}
+
+static void GLAPIENTRY
+save_ProgramUniform3ui(GLuint program, GLint location,
+ GLuint x, GLuint y, GLuint z)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ Node *n;
+ ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx);
+ n = alloc_instruction(ctx, OPCODE_PROGRAM_UNIFORM_3UI, 5);
+ if (n) {
+ n[1].ui = program;
+ n[2].i = location;
+ n[3].ui = x;
+ n[4].ui = y;
+ n[5].ui = z;
+ }
+ if (ctx->ExecuteFlag) {
+ CALL_ProgramUniform3ui(ctx->Exec, (program, location, x, y, z));
+ }
+}
+
+static void GLAPIENTRY
+save_ProgramUniform4ui(GLuint program, GLint location,
+ GLuint x, GLuint y, GLuint z, GLuint w)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ Node *n;
+ ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx);
+ n = alloc_instruction(ctx, OPCODE_PROGRAM_UNIFORM_4UI, 6);
+ if (n) {
+ n[1].ui = program;
+ n[2].i = location;
+ n[3].ui = x;
+ n[4].ui = y;
+ n[5].ui = z;
+ n[6].ui = w;
+ }
+ if (ctx->ExecuteFlag) {
+ CALL_ProgramUniform4ui(ctx->Exec, (program, location, x, y, z, w));
+ }
+}
+
+static void GLAPIENTRY
+save_ProgramUniform1uiv(GLuint program, GLint location, GLsizei count,
+ const GLuint *v)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ Node *n;
+ ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx);
+ n = alloc_instruction(ctx, OPCODE_PROGRAM_UNIFORM_1UIV, 3 + POINTER_DWORDS);
+ if (n) {
+ n[1].ui = program;
+ n[2].i = location;
+ n[3].i = count;
+ save_pointer(&n[4], memdup(v, count * 1 * sizeof(GLuint)));
+ }
+ if (ctx->ExecuteFlag) {
+ CALL_ProgramUniform1uiv(ctx->Exec, (program, location, count, v));
+ }
+}
+
+static void GLAPIENTRY
+save_ProgramUniform2uiv(GLuint program, GLint location, GLsizei count,
+ const GLuint *v)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ Node *n;
+ ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx);
+ n = alloc_instruction(ctx, OPCODE_PROGRAM_UNIFORM_2UIV, 3 + POINTER_DWORDS);
+ if (n) {
+ n[1].ui = program;
+ n[2].i = location;
+ n[3].i = count;
+ save_pointer(&n[4], memdup(v, count * 2 * sizeof(GLuint)));
+ }
+ if (ctx->ExecuteFlag) {
+ CALL_ProgramUniform2uiv(ctx->Exec, (program, location, count, v));
+ }
+}
+
+static void GLAPIENTRY
+save_ProgramUniform3uiv(GLuint program, GLint location, GLsizei count,
+ const GLuint *v)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ Node *n;
+ ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx);
+ n = alloc_instruction(ctx, OPCODE_PROGRAM_UNIFORM_3UIV, 3 + POINTER_DWORDS);
+ if (n) {
+ n[1].ui = program;
+ n[2].i = location;
+ n[3].i = count;
+ save_pointer(&n[4], memdup(v, count * 3 * sizeof(GLuint)));
+ }
+ if (ctx->ExecuteFlag) {
+ CALL_ProgramUniform3uiv(ctx->Exec, (program, location, count, v));
+ }
+}
+
+static void GLAPIENTRY
+save_ProgramUniform4uiv(GLuint program, GLint location, GLsizei count,
+ const GLuint *v)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ Node *n;
+ ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx);
+ n = alloc_instruction(ctx, OPCODE_PROGRAM_UNIFORM_4UIV, 3 + POINTER_DWORDS);
+ if (n) {
+ n[1].ui = program;
+ n[2].i = location;
+ n[3].i = count;
+ save_pointer(&n[4], memdup(v, count * 4 * sizeof(GLuint)));
+ }
+ if (ctx->ExecuteFlag) {
+ CALL_ProgramUniform4uiv(ctx->Exec, (program, location, count, v));
+ }
+}
+
+static void GLAPIENTRY
+save_ProgramUniformMatrix2fv(GLuint program, GLint location, GLsizei count,
+ GLboolean transpose, const GLfloat *v)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ Node *n;
+ ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx);
+ n = alloc_instruction(ctx, OPCODE_PROGRAM_UNIFORM_MATRIX22F,
+ 4 + POINTER_DWORDS);
+ if (n) {
+ n[1].ui = program;
+ n[2].i = location;
+ n[3].i = count;
+ n[4].b = transpose;
+ save_pointer(&n[5], memdup(v, count * 2 * 2 * sizeof(GLfloat)));
+ }
+ if (ctx->ExecuteFlag) {
+ CALL_ProgramUniformMatrix2fv(ctx->Exec,
+ (program, location, count, transpose, v));
+ }
+}
+
+static void GLAPIENTRY
+save_ProgramUniformMatrix2x3fv(GLuint program, GLint location, GLsizei count,
+ GLboolean transpose, const GLfloat *v)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ Node *n;
+ ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx);
+ n = alloc_instruction(ctx, OPCODE_PROGRAM_UNIFORM_MATRIX23F,
+ 4 + POINTER_DWORDS);
+ if (n) {
+ n[1].ui = program;
+ n[2].i = location;
+ n[3].i = count;
+ n[4].b = transpose;
+ save_pointer(&n[5], memdup(v, count * 2 * 3 * sizeof(GLfloat)));
+ }
+ if (ctx->ExecuteFlag) {
+ CALL_ProgramUniformMatrix2x3fv(ctx->Exec,
+ (program, location, count, transpose, v));
+ }
+}
+
+static void GLAPIENTRY
+save_ProgramUniformMatrix2x4fv(GLuint program, GLint location, GLsizei count,
+ GLboolean transpose, const GLfloat *v)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ Node *n;
+ ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx);
+ n = alloc_instruction(ctx, OPCODE_PROGRAM_UNIFORM_MATRIX24F,
+ 4 + POINTER_DWORDS);
+ if (n) {
+ n[1].ui = program;
+ n[2].i = location;
+ n[3].i = count;
+ n[4].b = transpose;
+ save_pointer(&n[5], memdup(v, count * 2 * 4 * sizeof(GLfloat)));
+ }
+ if (ctx->ExecuteFlag) {
+ CALL_ProgramUniformMatrix2x4fv(ctx->Exec,
+ (program, location, count, transpose, v));
+ }
+}
+
+static void GLAPIENTRY
+save_ProgramUniformMatrix3x2fv(GLuint program, GLint location, GLsizei count,
+ GLboolean transpose, const GLfloat *v)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ Node *n;
+ ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx);
+ n = alloc_instruction(ctx, OPCODE_PROGRAM_UNIFORM_MATRIX32F,
+ 4 + POINTER_DWORDS);
+ if (n) {
+ n[1].ui = program;
+ n[2].i = location;
+ n[3].i = count;
+ n[4].b = transpose;
+ save_pointer(&n[5], memdup(v, count * 3 * 2 * sizeof(GLfloat)));
+ }
+ if (ctx->ExecuteFlag) {
+ CALL_ProgramUniformMatrix3x2fv(ctx->Exec,
+ (program, location, count, transpose, v));
+ }
+}
+
+static void GLAPIENTRY
+save_ProgramUniformMatrix3fv(GLuint program, GLint location, GLsizei count,
+ GLboolean transpose, const GLfloat *v)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ Node *n;
+ ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx);
+ n = alloc_instruction(ctx, OPCODE_PROGRAM_UNIFORM_MATRIX33F,
+ 4 + POINTER_DWORDS);
+ if (n) {
+ n[1].ui = program;
+ n[2].i = location;
+ n[3].i = count;
+ n[4].b = transpose;
+ save_pointer(&n[5], memdup(v, count * 3 * 3 * sizeof(GLfloat)));
+ }
+ if (ctx->ExecuteFlag) {
+ CALL_ProgramUniformMatrix3fv(ctx->Exec,
+ (program, location, count, transpose, v));
+ }
+}
+
+static void GLAPIENTRY
+save_ProgramUniformMatrix3x4fv(GLuint program, GLint location, GLsizei count,
+ GLboolean transpose, const GLfloat *v)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ Node *n;
+ ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx);
+ n = alloc_instruction(ctx, OPCODE_PROGRAM_UNIFORM_MATRIX34F,
+ 4 + POINTER_DWORDS);
+ if (n) {
+ n[1].ui = program;
+ n[2].i = location;
+ n[3].i = count;
+ n[4].b = transpose;
+ save_pointer(&n[5], memdup(v, count * 3 * 4 * sizeof(GLfloat)));
+ }
+ if (ctx->ExecuteFlag) {
+ CALL_ProgramUniformMatrix3x4fv(ctx->Exec,
+ (program, location, count, transpose, v));
+ }
+}
+
+static void GLAPIENTRY
+save_ProgramUniformMatrix4x2fv(GLuint program, GLint location, GLsizei count,
+ GLboolean transpose, const GLfloat *v)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ Node *n;
+ ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx);
+ n = alloc_instruction(ctx, OPCODE_PROGRAM_UNIFORM_MATRIX42F,
+ 4 + POINTER_DWORDS);
+ if (n) {
+ n[1].ui = program;
+ n[2].i = location;
+ n[3].i = count;
+ n[4].b = transpose;
+ save_pointer(&n[5], memdup(v, count * 4 * 2 * sizeof(GLfloat)));
+ }
+ if (ctx->ExecuteFlag) {
+ CALL_ProgramUniformMatrix4x2fv(ctx->Exec,
+ (program, location, count, transpose, v));
+ }
+}
+
+static void GLAPIENTRY
+save_ProgramUniformMatrix4x3fv(GLuint program, GLint location, GLsizei count,
+ GLboolean transpose, const GLfloat *v)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ Node *n;
+ ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx);
+ n = alloc_instruction(ctx, OPCODE_PROGRAM_UNIFORM_MATRIX43F,
+ 4 + POINTER_DWORDS);
+ if (n) {
+ n[1].ui = program;
+ n[2].i = location;
+ n[3].i = count;
+ n[4].b = transpose;
+ save_pointer(&n[5], memdup(v, count * 4 * 3 * sizeof(GLfloat)));
+ }
+ if (ctx->ExecuteFlag) {
+ CALL_ProgramUniformMatrix4x3fv(ctx->Exec,
+ (program, location, count, transpose, v));
+ }
+}
+
+static void GLAPIENTRY
+save_ProgramUniformMatrix4fv(GLuint program, GLint location, GLsizei count,
+ GLboolean transpose, const GLfloat *v)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ Node *n;
+ ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx);
+ n = alloc_instruction(ctx, OPCODE_PROGRAM_UNIFORM_MATRIX44F,
+ 4 + POINTER_DWORDS);
+ if (n) {
+ n[1].ui = program;
+ n[2].i = location;
+ n[3].i = count;
+ n[4].b = transpose;
+ save_pointer(&n[5], memdup(v, count * 4 * 4 * sizeof(GLfloat)));
+ }
+ if (ctx->ExecuteFlag) {
+ CALL_ProgramUniformMatrix4fv(ctx->Exec,
+ (program, location, count, transpose, v));
+ }
+}
+
+static void GLAPIENTRY
+save_ClampColorARB(GLenum target, GLenum clamp)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ Node *n;
+ ASSERT_OUTSIDE_SAVE_BEGIN_END_AND_FLUSH(ctx);
+ n = alloc_instruction(ctx, OPCODE_CLAMP_COLOR, 2);
+ if (n) {
+ n[1].e = target;
+ n[2].e = clamp;
+ }
+ if (ctx->ExecuteFlag) {
+ CALL_ClampColor(ctx->Exec, (target, clamp));
}
}
@@ -7692,12 +8391,6 @@ execute_list(struct gl_context *ctx, GLuint list)
case OPCODE_USE_PROGRAM:
CALL_UseProgram(ctx->Exec, (n[1].ui));
break;
- case OPCODE_USE_SHADER_PROGRAM_EXT:
- CALL_UseShaderProgramEXT(ctx->Exec, (n[1].ui, n[2].ui));
- break;
- case OPCODE_ACTIVE_PROGRAM_EXT:
- CALL_ActiveProgramEXT(ctx->Exec, (n[1].ui));
- break;
case OPCODE_UNIFORM_1F:
CALL_Uniform1f(ctx->Exec, (n[1].i, n[2].f));
break;
@@ -7815,6 +8508,147 @@ execute_list(struct gl_context *ctx, GLuint list)
(n[1].i, n[2].i, n[3].b, get_pointer(&n[4])));
break;
+ case OPCODE_USE_PROGRAM_STAGES:
+ CALL_UseProgramStages(ctx->Exec, (n[1].ui, n[2].ui, n[3].ui));
+ break;
+ case OPCODE_PROGRAM_UNIFORM_1F:
+ CALL_ProgramUniform1f(ctx->Exec, (n[1].ui, n[2].i, n[3].f));
+ break;
+ case OPCODE_PROGRAM_UNIFORM_2F:
+ CALL_ProgramUniform2f(ctx->Exec, (n[1].ui, n[2].i, n[3].f, n[4].f));
+ break;
+ case OPCODE_PROGRAM_UNIFORM_3F:
+ CALL_ProgramUniform3f(ctx->Exec, (n[1].ui, n[2].i,
+ n[3].f, n[4].f, n[5].f));
+ break;
+ case OPCODE_PROGRAM_UNIFORM_4F:
+ CALL_ProgramUniform4f(ctx->Exec, (n[1].ui, n[2].i,
+ n[3].f, n[4].f, n[5].f, n[6].f));
+ break;
+ case OPCODE_PROGRAM_UNIFORM_1FV:
+ CALL_ProgramUniform1fv(ctx->Exec, (n[1].ui, n[2].i, n[3].i,
+ get_pointer(&n[4])));
+ break;
+ case OPCODE_PROGRAM_UNIFORM_2FV:
+ CALL_ProgramUniform2fv(ctx->Exec, (n[1].ui, n[2].i, n[3].i,
+ get_pointer(&n[4])));
+ break;
+ case OPCODE_PROGRAM_UNIFORM_3FV:
+ CALL_ProgramUniform3fv(ctx->Exec, (n[1].ui, n[2].i, n[3].i,
+ get_pointer(&n[4])));
+ break;
+ case OPCODE_PROGRAM_UNIFORM_4FV:
+ CALL_ProgramUniform4fv(ctx->Exec, (n[1].ui, n[2].i, n[3].i,
+ get_pointer(&n[4])));
+ break;
+ case OPCODE_PROGRAM_UNIFORM_1I:
+ CALL_ProgramUniform1i(ctx->Exec, (n[1].ui, n[2].i, n[3].i));
+ break;
+ case OPCODE_PROGRAM_UNIFORM_2I:
+ CALL_ProgramUniform2i(ctx->Exec, (n[1].ui, n[2].i, n[3].i, n[4].i));
+ break;
+ case OPCODE_PROGRAM_UNIFORM_3I:
+ CALL_ProgramUniform3i(ctx->Exec, (n[1].ui, n[2].i,
+ n[3].i, n[4].i, n[5].i));
+ break;
+ case OPCODE_PROGRAM_UNIFORM_4I:
+ CALL_ProgramUniform4i(ctx->Exec, (n[1].ui, n[2].i,
+ n[3].i, n[4].i, n[5].i, n[6].i));
+ break;
+ case OPCODE_PROGRAM_UNIFORM_1IV:
+ CALL_ProgramUniform1iv(ctx->Exec, (n[1].ui, n[2].i, n[3].i,
+ get_pointer(&n[4])));
+ break;
+ case OPCODE_PROGRAM_UNIFORM_2IV:
+ CALL_ProgramUniform2iv(ctx->Exec, (n[1].ui, n[2].i, n[3].i,
+ get_pointer(&n[4])));
+ break;
+ case OPCODE_PROGRAM_UNIFORM_3IV:
+ CALL_ProgramUniform3iv(ctx->Exec, (n[1].ui, n[2].i, n[3].i,
+ get_pointer(&n[4])));
+ break;
+ case OPCODE_PROGRAM_UNIFORM_4IV:
+ CALL_ProgramUniform4iv(ctx->Exec, (n[1].ui, n[2].i, n[3].i,
+ get_pointer(&n[4])));
+ break;
+ case OPCODE_PROGRAM_UNIFORM_1UI:
+ CALL_ProgramUniform1ui(ctx->Exec, (n[1].ui, n[2].i, n[3].ui));
+ break;
+ case OPCODE_PROGRAM_UNIFORM_2UI:
+ CALL_ProgramUniform2ui(ctx->Exec, (n[1].ui, n[2].i,
+ n[3].ui, n[4].ui));
+ break;
+ case OPCODE_PROGRAM_UNIFORM_3UI:
+ CALL_ProgramUniform3ui(ctx->Exec, (n[1].ui, n[2].i,
+ n[3].ui, n[4].ui, n[5].ui));
+ break;
+ case OPCODE_PROGRAM_UNIFORM_4UI:
+ CALL_ProgramUniform4ui(ctx->Exec, (n[1].ui, n[2].i,
+ n[3].ui,
+ n[4].ui, n[5].ui, n[6].ui));
+ break;
+ case OPCODE_PROGRAM_UNIFORM_1UIV:
+ CALL_ProgramUniform1uiv(ctx->Exec, (n[1].ui, n[2].i, n[3].i,
+ get_pointer(&n[4])));
+ break;
+ case OPCODE_PROGRAM_UNIFORM_2UIV:
+ CALL_ProgramUniform2uiv(ctx->Exec, (n[1].ui, n[2].i, n[3].i,
+ get_pointer(&n[4])));
+ break;
+ case OPCODE_PROGRAM_UNIFORM_3UIV:
+ CALL_ProgramUniform3uiv(ctx->Exec, (n[1].ui, n[2].i, n[3].i,
+ get_pointer(&n[4])));
+ break;
+ case OPCODE_PROGRAM_UNIFORM_4UIV:
+ CALL_ProgramUniform4uiv(ctx->Exec, (n[1].ui, n[2].i, n[3].i,
+ get_pointer(&n[4])));
+ break;
+ case OPCODE_PROGRAM_UNIFORM_MATRIX22F:
+ CALL_ProgramUniformMatrix2fv(ctx->Exec,
+ (n[1].ui, n[2].i, n[3].i, n[4].b,
+ get_pointer(&n[5])));
+ break;
+ case OPCODE_PROGRAM_UNIFORM_MATRIX23F:
+ CALL_ProgramUniformMatrix2x3fv(ctx->Exec,
+ (n[1].ui, n[2].i, n[3].i, n[4].b,
+ get_pointer(&n[5])));
+ break;
+ case OPCODE_PROGRAM_UNIFORM_MATRIX24F:
+ CALL_ProgramUniformMatrix2x4fv(ctx->Exec,
+ (n[1].ui, n[2].i, n[3].i, n[4].b,
+ get_pointer(&n[5])));
+ break;
+ case OPCODE_PROGRAM_UNIFORM_MATRIX32F:
+ CALL_ProgramUniformMatrix3x2fv(ctx->Exec,
+ (n[1].ui, n[2].i, n[3].i, n[4].b,
+ get_pointer(&n[5])));
+ break;
+ case OPCODE_PROGRAM_UNIFORM_MATRIX33F:
+ CALL_ProgramUniformMatrix3fv(ctx->Exec,
+ (n[1].ui, n[2].i, n[3].i, n[4].b,
+ get_pointer(&n[5])));
+ break;
+ case OPCODE_PROGRAM_UNIFORM_MATRIX34F:
+ CALL_ProgramUniformMatrix3x4fv(ctx->Exec,
+ (n[1].ui, n[2].i, n[3].i, n[4].b,
+ get_pointer(&n[5])));
+ break;
+ case OPCODE_PROGRAM_UNIFORM_MATRIX42F:
+ CALL_ProgramUniformMatrix4x2fv(ctx->Exec,
+ (n[1].ui, n[2].i, n[3].i, n[4].b,
+ get_pointer(&n[5])));
+ break;
+ case OPCODE_PROGRAM_UNIFORM_MATRIX43F:
+ CALL_ProgramUniformMatrix4x3fv(ctx->Exec,
+ (n[1].ui, n[2].i, n[3].i, n[4].b,
+ get_pointer(&n[5])));
+ break;
+ case OPCODE_PROGRAM_UNIFORM_MATRIX44F:
+ CALL_ProgramUniformMatrix4fv(ctx->Exec,
+ (n[1].ui, n[2].i, n[3].i, n[4].b,
+ get_pointer(&n[5])));
+ break;
+
case OPCODE_CLAMP_COLOR:
CALL_ClampColor(ctx->Exec, (n[1].e, n[2].e));
break;
@@ -8763,10 +9597,6 @@ _mesa_initialize_save_table(const struct gl_context *ctx)
SET_TexParameterIiv(table, save_TexParameterIiv);
SET_TexParameterIuiv(table, save_TexParameterIuiv);
- /* 377. GL_EXT_separate_shader_objects */
- SET_UseShaderProgramEXT(table, save_UseShaderProgramEXT);
- SET_ActiveProgramEXT(table, save_ActiveProgramEXT);
-
/* GL_ARB_color_buffer_float */
SET_ClampColor(table, save_ClampColorARB);
@@ -8856,6 +9686,42 @@ _mesa_initialize_save_table(const struct gl_context *ctx)
SET_DrawArraysInstancedBaseInstance(table, save_DrawArraysInstancedBaseInstance);
SET_DrawElementsInstancedBaseInstance(table, save_DrawElementsInstancedBaseInstance);
SET_DrawElementsInstancedBaseVertexBaseInstance(table, save_DrawElementsInstancedBaseVertexBaseInstance);
+
+ /* OpenGL 4.2 / GL_ARB_separate_shader_objects */
+ SET_UseProgramStages(table, save_UseProgramStages);
+ SET_ProgramUniform1f(table, save_ProgramUniform1f);
+ SET_ProgramUniform2f(table, save_ProgramUniform2f);
+ SET_ProgramUniform3f(table, save_ProgramUniform3f);
+ SET_ProgramUniform4f(table, save_ProgramUniform4f);
+ SET_ProgramUniform1fv(table, save_ProgramUniform1fv);
+ SET_ProgramUniform2fv(table, save_ProgramUniform2fv);
+ SET_ProgramUniform3fv(table, save_ProgramUniform3fv);
+ SET_ProgramUniform4fv(table, save_ProgramUniform4fv);
+ SET_ProgramUniform1i(table, save_ProgramUniform1i);
+ SET_ProgramUniform2i(table, save_ProgramUniform2i);
+ SET_ProgramUniform3i(table, save_ProgramUniform3i);
+ SET_ProgramUniform4i(table, save_ProgramUniform4i);
+ SET_ProgramUniform1iv(table, save_ProgramUniform1iv);
+ SET_ProgramUniform2iv(table, save_ProgramUniform2iv);
+ SET_ProgramUniform3iv(table, save_ProgramUniform3iv);
+ SET_ProgramUniform4iv(table, save_ProgramUniform4iv);
+ SET_ProgramUniform1ui(table, save_ProgramUniform1ui);
+ SET_ProgramUniform2ui(table, save_ProgramUniform2ui);
+ SET_ProgramUniform3ui(table, save_ProgramUniform3ui);
+ SET_ProgramUniform4ui(table, save_ProgramUniform4ui);
+ SET_ProgramUniform1uiv(table, save_ProgramUniform1uiv);
+ SET_ProgramUniform2uiv(table, save_ProgramUniform2uiv);
+ SET_ProgramUniform3uiv(table, save_ProgramUniform3uiv);
+ SET_ProgramUniform4uiv(table, save_ProgramUniform4uiv);
+ SET_ProgramUniformMatrix2fv(table, save_ProgramUniformMatrix2fv);
+ SET_ProgramUniformMatrix3fv(table, save_ProgramUniformMatrix3fv);
+ SET_ProgramUniformMatrix4fv(table, save_ProgramUniformMatrix4fv);
+ SET_ProgramUniformMatrix2x3fv(table, save_ProgramUniformMatrix2x3fv);
+ SET_ProgramUniformMatrix3x2fv(table, save_ProgramUniformMatrix3x2fv);
+ SET_ProgramUniformMatrix2x4fv(table, save_ProgramUniformMatrix2x4fv);
+ SET_ProgramUniformMatrix4x2fv(table, save_ProgramUniformMatrix4x2fv);
+ SET_ProgramUniformMatrix3x4fv(table, save_ProgramUniformMatrix3x4fv);
+ SET_ProgramUniformMatrix4x3fv(table, save_ProgramUniformMatrix4x3fv);
}
diff --git a/mesalib/src/mesa/main/errors.c b/mesalib/src/mesa/main/errors.c
index 30a867298..aa0ff50ac 100644
--- a/mesalib/src/mesa/main/errors.c
+++ b/mesalib/src/mesa/main/errors.c
@@ -1414,6 +1414,12 @@ _mesa_error( struct gl_context *ctx, GLenum error, const char *fmtString, ... )
_mesa_record_error(ctx, error);
}
+void
+_mesa_error_no_memory(const char *caller)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "out of memory in %s", caller);
+}
/**
* Report debug information. Print error message to stderr via fprintf().
diff --git a/mesalib/src/mesa/main/errors.h b/mesalib/src/mesa/main/errors.h
index 06d0b21fc..b388138e8 100644
--- a/mesalib/src/mesa/main/errors.h
+++ b/mesalib/src/mesa/main/errors.h
@@ -64,6 +64,9 @@ extern void
_mesa_error( struct gl_context *ctx, GLenum error, const char *fmtString, ... ) PRINTFLIKE(3, 4);
extern void
+_mesa_error_no_memory(const char *caller);
+
+extern void
_mesa_debug( const struct gl_context *ctx, const char *fmtString, ... ) PRINTFLIKE(2, 3);
extern void
diff --git a/mesalib/src/mesa/main/extensions.c b/mesalib/src/mesa/main/extensions.c
index a72284c9a..c2ff7e3b7 100644
--- a/mesalib/src/mesa/main/extensions.c
+++ b/mesalib/src/mesa/main/extensions.c
@@ -114,6 +114,7 @@ static const struct extension extension_table[] = {
{ "GL_ARB_invalidate_subdata", o(dummy_true), GL, 2012 },
{ "GL_ARB_map_buffer_alignment", o(dummy_true), GL, 2011 },
{ "GL_ARB_map_buffer_range", o(ARB_map_buffer_range), GL, 2008 },
+ { "GL_ARB_multi_bind", o(dummy_true), GL, 2013 },
{ "GL_ARB_multi_draw_indirect", o(ARB_draw_indirect), GLC, 2012 },
{ "GL_ARB_multisample", o(dummy_true), GLL, 1994 },
{ "GL_ARB_multitexture", o(dummy_true), GLL, 1998 },
@@ -127,7 +128,7 @@ static const struct extension extension_table[] = {
{ "GL_ARB_sample_shading", o(ARB_sample_shading), GL, 2009 },
{ "GL_ARB_sampler_objects", o(dummy_true), GL, 2009 },
{ "GL_ARB_seamless_cube_map", o(ARB_seamless_cube_map), GL, 2009 },
- { "GL_ARB_separate_shader_objects", o(ARB_separate_shader_objects), GL, 2010 },
+ { "GL_ARB_separate_shader_objects", o(dummy_true), GL, 2010 },
{ "GL_ARB_shader_atomic_counters", o(ARB_shader_atomic_counters), GL, 2011 },
{ "GL_ARB_shader_bit_encoding", o(ARB_shader_bit_encoding), GL, 2010 },
{ "GL_ARB_shader_image_load_store", o(ARB_shader_image_load_store), GL, 2011 },
@@ -217,7 +218,7 @@ static const struct extension extension_table[] = {
{ "GL_EXT_provoking_vertex", o(EXT_provoking_vertex), GL, 2009 },
{ "GL_EXT_rescale_normal", o(dummy_true), GLL, 1997 },
{ "GL_EXT_secondary_color", o(dummy_true), GLL, 1999 },
- { "GL_EXT_separate_shader_objects", o(EXT_separate_shader_objects), GLL, 2008 },
+ { "GL_EXT_separate_shader_objects", o(dummy_true), ES2, 2013 },
{ "GL_EXT_separate_specular_color", o(dummy_true), GLL, 1997 },
{ "GL_EXT_shader_integer_mix", o(EXT_shader_integer_mix), GL | ES3, 2013 },
{ "GL_EXT_shadow_funcs", o(ARB_shadow), GLL, 2002 },
@@ -330,6 +331,7 @@ static const struct extension extension_table[] = {
{ "GL_IBM_rasterpos_clip", o(dummy_true), GLL, 1996 },
{ "GL_IBM_texture_mirrored_repeat", o(dummy_true), GLL, 1998 },
{ "GL_INGR_blend_func_separate", o(EXT_blend_func_separate), GLL, 1999 },
+ { "GL_INTEL_performance_query", o(INTEL_performance_query), GL | ES2, 2013 },
{ "GL_MESA_pack_invert", o(MESA_pack_invert), GL, 2002 },
{ "GL_MESA_texture_signed_rgba", o(EXT_texture_snorm), GL, 2009 },
{ "GL_MESA_window_pos", o(dummy_true), GLL, 2000 },
@@ -409,7 +411,6 @@ _mesa_enable_sw_extensions(struct gl_context *ctx)
ctx->Extensions.ARB_occlusion_query = GL_TRUE;
ctx->Extensions.ARB_occlusion_query2 = GL_TRUE;
ctx->Extensions.ARB_point_sprite = GL_TRUE;
- ctx->Extensions.EXT_separate_shader_objects = GL_TRUE;
ctx->Extensions.ARB_shadow = GL_TRUE;
ctx->Extensions.ARB_texture_border_clamp = GL_TRUE;
ctx->Extensions.ARB_texture_cube_map = GL_TRUE;
diff --git a/mesalib/src/mesa/main/ff_fragment_shader.cpp b/mesalib/src/mesa/main/ff_fragment_shader.cpp
index 605f3713e..8c360970f 100644
--- a/mesalib/src/mesa/main/ff_fragment_shader.cpp
+++ b/mesalib/src/mesa/main/ff_fragment_shader.cpp
@@ -1299,7 +1299,7 @@ create_new_program(struct gl_context *ctx, struct state_key *key)
* fixed function program in a GLES2 context at all, but that's a
* big mess to clean up.
*/
- p.shader_program->InternalSeparateShader = GL_TRUE;
+ p.shader_program->SeparateShader = GL_TRUE;
state->language_version = 130;
state->es_shader = false;
diff --git a/mesalib/src/mesa/main/format_unpack.c b/mesalib/src/mesa/main/format_unpack.c
index cf96609ea..9cc8f4dba 100644
--- a/mesalib/src/mesa/main/format_unpack.c
+++ b/mesalib/src/mesa/main/format_unpack.c
@@ -4263,3 +4263,108 @@ _mesa_unpack_uint_24_8_depth_stencil_row(mesa_format format, GLuint n,
return;
}
}
+
+static void
+unpack_float_32_uint_24_8_Z24_UNORM_S8_UINT(const GLuint *src,
+ GLuint *dst, GLuint n)
+{
+ GLuint i;
+ struct z32f_x24s8 *d = (struct z32f_x24s8 *) dst;
+ const GLdouble scale = 1.0 / (GLdouble) 0xffffff;
+
+ for (i = 0; i < n; i++) {
+ const GLuint z24 = src[i] & 0xffffff;
+ d[i].z = z24 * scale;
+ d[i].x24s8 = src[i] >> 24;
+ assert(d[i].z >= 0.0f);
+ assert(d[i].z <= 1.0f);
+ }
+}
+
+static void
+unpack_float_32_uint_24_8_Z32_FLOAT_S8X24_UINT(const GLuint *src,
+ GLuint *dst, GLuint n)
+{
+ memcpy(dst, src, n * sizeof(struct z32f_x24s8));
+}
+
+static void
+unpack_float_32_uint_24_8_S8_UINT_Z24_UNORM(const GLuint *src,
+ GLuint *dst, GLuint n)
+{
+ GLuint i;
+ struct z32f_x24s8 *d = (struct z32f_x24s8 *) dst;
+ const GLdouble scale = 1.0 / (GLdouble) 0xffffff;
+
+ for (i = 0; i < n; i++) {
+ const GLuint z24 = src[i] >> 8;
+ d[i].z = z24 * scale;
+ d[i].x24s8 = src[i] & 0xff;
+ assert(d[i].z >= 0.0f);
+ assert(d[i].z <= 1.0f);
+ }
+}
+
+/**
+ * Unpack depth/stencil returning as GL_FLOAT_32_UNSIGNED_INT_24_8_REV.
+ * \param format the source data format
+ *
+ * In GL_FLOAT_32_UNSIGNED_INT_24_8_REV lower 4 bytes contain float
+ * component and higher 4 bytes contain packed 24-bit and 8-bit
+ * components.
+ *
+ * 31 30 29 28 ... 4 3 2 1 0 31 30 29 ... 9 8 7 6 5 ... 2 1 0
+ * +-------------------------+ +--------------------------------+
+ * | Float Component | | Unused | 8 bit stencil |
+ * +-------------------------+ +--------------------------------+
+ * lower 4 bytes higher 4 bytes
+ */
+void
+_mesa_unpack_float_32_uint_24_8_depth_stencil_row(mesa_format format, GLuint n,
+ const void *src, GLuint *dst)
+{
+ switch (format) {
+ case MESA_FORMAT_S8_UINT_Z24_UNORM:
+ unpack_float_32_uint_24_8_S8_UINT_Z24_UNORM(src, dst, n);
+ break;
+ case MESA_FORMAT_Z24_UNORM_S8_UINT:
+ unpack_float_32_uint_24_8_Z24_UNORM_S8_UINT(src, dst, n);
+ break;
+ case MESA_FORMAT_Z32_FLOAT_S8X24_UINT:
+ unpack_float_32_uint_24_8_Z32_FLOAT_S8X24_UINT(src, dst, n);
+ break;
+ default:
+ _mesa_problem(NULL,
+ "bad format %s in _mesa_unpack_uint_24_8_depth_stencil_row",
+ _mesa_get_format_name(format));
+ return;
+ }
+}
+
+/**
+ * Unpack depth/stencil
+ * \param format the source data format
+ * \param type the destination data type
+ */
+void
+_mesa_unpack_depth_stencil_row(mesa_format format, GLuint n,
+ const void *src, GLenum type,
+ GLuint *dst)
+{
+ assert(type == GL_UNSIGNED_INT_24_8 ||
+ type == GL_FLOAT_32_UNSIGNED_INT_24_8_REV);
+
+ switch (type) {
+ case GL_UNSIGNED_INT_24_8:
+ _mesa_unpack_uint_24_8_depth_stencil_row(format, n, src, dst);
+ break;
+ case GL_FLOAT_32_UNSIGNED_INT_24_8_REV:
+ _mesa_unpack_float_32_uint_24_8_depth_stencil_row(format, n, src, dst);
+ break;
+ default:
+ _mesa_problem(NULL,
+ "bad type 0x%x in _mesa_unpack_depth_stencil_row",
+ type);
+ return;
+ }
+}
diff --git a/mesalib/src/mesa/main/format_unpack.h b/mesalib/src/mesa/main/format_unpack.h
index 1fcfc04b3..51f97df4d 100644
--- a/mesalib/src/mesa/main/format_unpack.h
+++ b/mesalib/src/mesa/main/format_unpack.h
@@ -63,5 +63,13 @@ void
_mesa_unpack_uint_24_8_depth_stencil_row(mesa_format format, GLuint n,
const void *src, GLuint *dst);
-
+void
+_mesa_unpack_float_32_uint_24_8_depth_stencil_row(mesa_format format,
+ GLuint n,
+ const void *src,
+ GLuint *dst);
+void
+_mesa_unpack_depth_stencil_row(mesa_format format, GLuint n,
+ const void *src, GLenum type,
+ GLuint *dst);
#endif /* FORMAT_UNPACK_H */
diff --git a/mesalib/src/mesa/main/get.c b/mesalib/src/mesa/main/get.c
index fe35ff3ef..80a5839b5 100644
--- a/mesalib/src/mesa/main/get.c
+++ b/mesalib/src/mesa/main/get.c
@@ -387,7 +387,6 @@ EXTRA_EXT(ARB_texture_cube_map_array);
EXTRA_EXT(ARB_texture_buffer_range);
EXTRA_EXT(ARB_texture_multisample);
EXTRA_EXT(ARB_texture_gather);
-EXTRA_EXT(ARB_separate_shader_objects);
EXTRA_EXT(ARB_shader_atomic_counters);
EXTRA_EXT(ARB_draw_indirect);
EXTRA_EXT(ARB_shader_image_load_store);
@@ -395,6 +394,7 @@ EXTRA_EXT(ARB_viewport_array);
EXTRA_EXT(ARB_compute_shader);
EXTRA_EXT(ARB_gpu_shader5);
EXTRA_EXT2(ARB_transform_feedback3, ARB_gpu_shader5);
+EXTRA_EXT(INTEL_performance_query);
static const int
extra_ARB_color_buffer_float_or_glcore[] = {
diff --git a/mesalib/src/mesa/main/get_hash_params.py b/mesalib/src/mesa/main/get_hash_params.py
index 06d0bbacc..d40fa0778 100644
--- a/mesalib/src/mesa/main/get_hash_params.py
+++ b/mesalib/src/mesa/main/get_hash_params.py
@@ -311,6 +311,12 @@ descriptor=[
# GL_ARB_get_program_binary / GL_OES_get_program_binary
[ "NUM_PROGRAM_BINARY_FORMATS", "CONST(0), NO_EXTRA" ],
[ "PROGRAM_BINARY_FORMATS", "LOC_CUSTOM, TYPE_INVALID, 0, NO_EXTRA" ],
+
+# GL_INTEL_performance_query
+ [ "PERFQUERY_QUERY_NAME_LENGTH_MAX_INTEL", "CONST(MAX_PERFQUERY_QUERY_NAME_LENGTH), extra_INTEL_performance_query" ],
+ [ "PERFQUERY_COUNTER_NAME_LENGTH_MAX_INTEL", "CONST(MAX_PERFQUERY_COUNTER_NAME_LENGTH), extra_INTEL_performance_query" ],
+ [ "PERFQUERY_COUNTER_DESC_LENGTH_MAX_INTEL", "CONST(MAX_PERFQUERY_COUNTER_DESC_LENGTH), extra_INTEL_performance_query" ],
+ [ "PERFQUERY_GPA_EXTENDED_COUNTERS_INTEL", "CONST(PERFQUERY_HAVE_GPA_EXTENDED_COUNTERS), extra_INTEL_performance_query" ],
]},
# GLES3 is not a typo.
@@ -727,7 +733,7 @@ descriptor=[
[ "MAX_PROGRAM_TEXTURE_GATHER_COMPONENTS_ARB", "CONTEXT_INT(Const.MaxProgramTextureGatherComponents), extra_ARB_texture_gather"],
# GL_ARB_separate_shader_objects
- [ "PROGRAM_PIPELINE_BINDING", "LOC_CUSTOM, TYPE_INT, GL_PROGRAM_PIPELINE_BINDING, extra_ARB_separate_shader_objects" ],
+ [ "PROGRAM_PIPELINE_BINDING", "LOC_CUSTOM, TYPE_INT, GL_PROGRAM_PIPELINE_BINDING, NO_EXTRA" ],
# GL_ARB_shader_atomic_counters
[ "ATOMIC_COUNTER_BUFFER_BINDING", "LOC_CUSTOM, TYPE_INT, 0, extra_ARB_shader_atomic_counters" ],
diff --git a/mesalib/src/mesa/main/hash.c b/mesalib/src/mesa/main/hash.c
index 4c92005e0..23018e9da 100644
--- a/mesalib/src/mesa/main/hash.c
+++ b/mesalib/src/mesa/main/hash.c
@@ -194,15 +194,55 @@ _mesa_HashLookup(struct _mesa_HashTable *table, GLuint key)
/**
- * Insert a key/pointer pair into the hash table.
- * If an entry with this key already exists we'll replace the existing entry.
- *
+ * Lookup an entry in the hash table without locking the mutex.
+ *
+ * The hash table mutex must be locked manually by calling
+ * _mesa_HashLockMutex() before calling this function.
+ *
+ * \param table the hash table.
+ * \param key the key.
+ *
+ * \return pointer to user's data or NULL if key not in table
+ */
+void *
+_mesa_HashLookupLocked(struct _mesa_HashTable *table, GLuint key)
+{
+ return _mesa_HashLookup_unlocked(table, key);
+}
+
+
+/**
+ * Lock the hash table mutex.
+ *
+ * This function should be used when multiple objects need
+ * to be looked up in the hash table, to avoid having to lock
+ * and unlock the mutex each time.
+ *
* \param table the hash table.
- * \param key the key (not zero).
- * \param data pointer to user data.
*/
void
-_mesa_HashInsert(struct _mesa_HashTable *table, GLuint key, void *data)
+_mesa_HashLockMutex(struct _mesa_HashTable *table)
+{
+ assert(table);
+ mtx_lock(&table->Mutex);
+}
+
+
+/**
+ * Unlock the hash table mutex.
+ *
+ * \param table the hash table.
+ */
+void
+_mesa_HashUnlockMutex(struct _mesa_HashTable *table)
+{
+ assert(table);
+ mtx_unlock(&table->Mutex);
+}
+
+
+static inline void
+_mesa_HashInsert_unlocked(struct _mesa_HashTable *table, GLuint key, void *data)
{
uint32_t hash = uint_hash(key);
struct hash_entry *entry;
@@ -210,8 +250,6 @@ _mesa_HashInsert(struct _mesa_HashTable *table, GLuint key, void *data)
assert(table);
assert(key);
- mtx_lock(&table->Mutex);
-
if (key > table->MaxKey)
table->MaxKey = key;
@@ -225,11 +263,44 @@ _mesa_HashInsert(struct _mesa_HashTable *table, GLuint key, void *data)
_mesa_hash_table_insert(table->ht, hash, uint_key(key), data);
}
}
+}
- mtx_unlock(&table->Mutex);
+
+/**
+ * Insert a key/pointer pair into the hash table without locking the mutex.
+ * If an entry with this key already exists we'll replace the existing entry.
+ *
+ * The hash table mutex must be locked manually by calling
+ * _mesa_HashLockMutex() before calling this function.
+ *
+ * \param table the hash table.
+ * \param key the key (not zero).
+ * \param data pointer to user data.
+ */
+void
+_mesa_HashInsertLocked(struct _mesa_HashTable *table, GLuint key, void *data)
+{
+ _mesa_HashInsert_unlocked(table, key, data);
}
+/**
+ * Insert a key/pointer pair into the hash table.
+ * If an entry with this key already exists we'll replace the existing entry.
+ *
+ * \param table the hash table.
+ * \param key the key (not zero).
+ * \param data pointer to user data.
+ */
+void
+_mesa_HashInsert(struct _mesa_HashTable *table, GLuint key, void *data)
+{
+ assert(table);
+ mtx_lock(&table->Mutex);
+ _mesa_HashInsert_unlocked(table, key, data);
+ mtx_unlock(&table->Mutex);
+}
+
/**
* Remove an entry from the hash table.
diff --git a/mesalib/src/mesa/main/hash.h b/mesalib/src/mesa/main/hash.h
index b34f32848..e3e8f492e 100644
--- a/mesalib/src/mesa/main/hash.h
+++ b/mesalib/src/mesa/main/hash.h
@@ -45,6 +45,15 @@ extern void _mesa_HashInsert(struct _mesa_HashTable *table, GLuint key, void *da
extern void _mesa_HashRemove(struct _mesa_HashTable *table, GLuint key);
+extern void _mesa_HashLockMutex(struct _mesa_HashTable *table);
+
+extern void _mesa_HashUnlockMutex(struct _mesa_HashTable *table);
+
+extern void *_mesa_HashLookupLocked(struct _mesa_HashTable *table, GLuint key);
+
+extern void _mesa_HashInsertLocked(struct _mesa_HashTable *table,
+ GLuint key, void *data);
+
extern void
_mesa_HashDeleteAll(struct _mesa_HashTable *table,
void (*callback)(GLuint key, void *data, void *userData),
diff --git a/mesalib/src/mesa/main/imports.h b/mesalib/src/mesa/main/imports.h
index 17a9bd099..af780b249 100644
--- a/mesalib/src/mesa/main/imports.h
+++ b/mesalib/src/mesa/main/imports.h
@@ -126,7 +126,8 @@ typedef union { GLfloat f; GLint i; GLuint u; } fi_type;
#define atanhf(f) ((float) atanh(f))
#endif
-#if defined(_MSC_VER) && (_MSC_VER < 1800) /* Not req'd on VS2013 and above */
+#if defined(_MSC_VER)
+#if _MSC_VER < 1800 /* Not req'd on VS2013 and above */
static inline float truncf(float x) { return x < 0.0f ? ceilf(x) : floorf(x); }
static inline float exp2f(float x) { return powf(2.0f, x); }
static inline float log2f(float x) { return logf(x) * 1.442695041f; }
@@ -135,6 +136,7 @@ static inline float acoshf(float x) { return logf(x + sqrtf(x * x - 1.0f)); }
static inline float atanhf(float x) { return (logf(1.0f + x) - logf(1.0f - x)) / 2.0f; }
static inline int isblank(int ch) { return ch == ' ' || ch == '\t'; }
#define strtoll(p, e, b) _strtoi64(p, e, b)
+#endif /* _MSC_VER < 1800 */
#define strcasecmp(s1, s2) _stricmp(s1, s2)
#endif
/*@}*/
diff --git a/mesalib/src/mesa/main/mtypes.h b/mesalib/src/mesa/main/mtypes.h
index 5fbfffe98..917d071a2 100644
--- a/mesalib/src/mesa/main/mtypes.h
+++ b/mesalib/src/mesa/main/mtypes.h
@@ -1195,6 +1195,8 @@ struct gl_texture_object
GLuint Name; /**< the user-visible texture object ID */
GLchar *Label; /**< GL_KHR_debug */
GLenum Target; /**< GL_TEXTURE_1D, GL_TEXTURE_2D, etc. */
+ gl_texture_index TargetIndex; /**< The gl_texture_unit::CurrentTex index.
+ Only valid when Target is valid. */
struct gl_sampler_object Sampler;
@@ -1368,6 +1370,9 @@ struct gl_texture_unit
/** Points to highest priority, complete and enabled texture object */
struct gl_texture_object *_Current;
+
+ /** Texture targets that have a non-default texture bound */
+ GLbitfield _BoundTextures;
};
@@ -2432,6 +2437,15 @@ struct gl_shader
struct glsl_symbol_table *symbols;
bool uses_builtin_functions;
+ bool uses_gl_fragcoord;
+ bool redeclares_gl_fragcoord;
+ bool ARB_fragment_coord_conventions_enable;
+
+ /**
+ * Fragment shader state from GLSL 1.50 layout qualifiers.
+ */
+ bool origin_upper_left;
+ bool pixel_center_integer;
/**
* Geometry shader state from GLSL 1.50 layout qualifiers.
@@ -2594,17 +2608,6 @@ struct gl_shader_program
GLboolean BinaryRetreivableHint;
/**
- * Flags that the linker should not reject the program if it lacks
- * a vertex or fragment shader. GLES2 doesn't allow separate
- * shader objects, and would reject them. However, we internally
- * build separate shader objects for fixed function programs, which
- * we use for drivers/common/meta.c and for handling
- * _mesa_update_state with no program bound (for example in
- * glClear()).
- */
- GLboolean InternalSeparateShader;
-
- /**
* Indicates whether program can be bound for individual pipeline stages
* using UseProgramStages after it is next linked.
*/
@@ -2757,6 +2760,11 @@ struct gl_shader_program
* \c NULL.
*/
struct gl_shader *_LinkedShaders[MESA_SHADER_STAGES];
+
+ /* True if any of the fragment shaders attached to this program use:
+ * #extension ARB_fragment_coord_conventions: enable
+ */
+ GLboolean ARB_fragment_coord_conventions_enable;
};
@@ -2790,9 +2798,7 @@ struct gl_pipeline_object
/**
* Programs used for rendering
*
- * There is a separate program set for each shader stage. If
- * GL_EXT_separate_shader_objects is not supported, each of these must point
- * to \c NULL or to the same program.
+ * There is a separate program set for each shader stage.
*/
struct gl_shader_program *CurrentProgram[MESA_SHADER_STAGES];
@@ -3521,7 +3527,6 @@ struct gl_extensions
GLboolean ARB_point_sprite;
GLboolean ARB_sample_shading;
GLboolean ARB_seamless_cube_map;
- GLboolean ARB_separate_shader_objects;
GLboolean ARB_shader_atomic_counters;
GLboolean ARB_shader_bit_encoding;
GLboolean ARB_shader_image_load_store;
@@ -3547,6 +3552,7 @@ struct gl_extensions
GLboolean ARB_texture_mirror_clamp_to_edge;
GLboolean ARB_texture_multisample;
GLboolean ARB_texture_non_power_of_two;
+ GLboolean ARB_texture_stencil8;
GLboolean ARB_texture_query_levels;
GLboolean ARB_texture_query_lod;
GLboolean ARB_texture_rg;
@@ -3577,7 +3583,6 @@ struct gl_extensions
GLboolean EXT_pixel_buffer_object;
GLboolean EXT_point_parameters;
GLboolean EXT_provoking_vertex;
- GLboolean EXT_separate_shader_objects;
GLboolean EXT_shader_integer_mix;
GLboolean EXT_stencil_two_side;
GLboolean EXT_texture3D;
@@ -3608,6 +3613,7 @@ struct gl_extensions
GLboolean ATI_texture_env_combine3;
GLboolean ATI_fragment_shader;
GLboolean ATI_separate_stencil;
+ GLboolean INTEL_performance_query;
GLboolean MESA_pack_invert;
GLboolean MESA_ycbcr_texture;
GLboolean NV_conditional_render;
diff --git a/mesalib/src/mesa/main/performance_monitor.c b/mesalib/src/mesa/main/performance_monitor.c
index e62f77012..21b9423e0 100644
--- a/mesalib/src/mesa/main/performance_monitor.c
+++ b/mesalib/src/mesa/main/performance_monitor.c
@@ -137,6 +137,46 @@ get_counter(const struct gl_perf_monitor_group *group_obj, GLuint id)
return &group_obj->Counters[id];
}
+/* For INTEL_performance_query, query id 0 is reserved to be invalid. We use
+ * index to Groups array + 1 as the query id. Same applies to counter id.
+ */
+static inline GLuint
+queryid_to_index(GLuint queryid)
+{
+ return queryid - 1;
+}
+
+static inline GLuint
+index_to_queryid(GLuint index)
+{
+ return index + 1;
+}
+
+static inline bool
+queryid_valid(const struct gl_context *ctx, GLuint queryid)
+{
+ return get_group(ctx, queryid_to_index(queryid)) != NULL;
+}
+
+static inline GLuint
+counterid_to_index(GLuint counterid)
+{
+ return counterid - 1;
+}
+
+static inline GLuint
+index_to_counterid(GLuint index)
+{
+ return index + 1;
+}
+
+static inline bool
+counterid_valid(const struct gl_perf_monitor_group *group_obj,
+ GLuint counterid)
+{
+ return get_counter(group_obj, counterid_to_index(counterid)) != NULL;
+}
+
/*****************************************************************************/
void GLAPIENTRY
@@ -639,3 +679,577 @@ _mesa_perf_monitor_counter_size(const struct gl_perf_monitor_counter *c)
return 0;
}
}
+
+extern void GLAPIENTRY
+_mesa_GetFirstPerfQueryIdINTEL(GLuint *queryId)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ unsigned numGroups;
+
+ /* The GL_INTEL_performance_query spec says:
+ *
+ * "If queryId pointer is equal to 0, INVALID_VALUE error is generated."
+ */
+ if (!queryId) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glGetFirstPerfQueryIdINTEL(queryId == NULL)");
+ return;
+ }
+
+ numGroups = ctx->PerfMonitor.NumGroups;
+
+ /* The GL_INTEL_performance_query spec says:
+ *
+ * "If the given hardware platform doesn't support any performance
+ * queries, then the value of 0 is returned and INVALID_OPERATION error
+ * is raised."
+ */
+ if (numGroups == 0) {
+ *queryId = 0;
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glGetFirstPerfQueryIdINTEL(no queries supported)");
+ return;
+ }
+
+ *queryId = index_to_queryid(0);
+}
+
+extern void GLAPIENTRY
+_mesa_GetNextPerfQueryIdINTEL(GLuint queryId, GLuint *nextQueryId)
+{
+ GET_CURRENT_CONTEXT(ctx);
+
+ /* The GL_INTEL_performance_query spec says:
+ *
+ * "The result is passed in location pointed by nextQueryId. If query
+ * identified by queryId is the last query available the value of 0 is
+ * returned. If the specified performance query identifier is invalid
+ * then INVALID_VALUE error is generated. If nextQueryId pointer is
+ * equal to 0, an INVALID_VALUE error is generated. Whenever error is
+ * generated, the value of 0 is returned."
+ */
+
+ if (!nextQueryId) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glGetNextPerfQueryIdINTEL(nextQueryId == NULL)");
+ return;
+ }
+
+ if (!queryid_valid(ctx, queryId)) {
+ *nextQueryId = 0;
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glGetNextPerfQueryIdINTEL(invalid query)");
+ return;
+ }
+
+ ++queryId;
+
+ if (!queryid_valid(ctx, queryId)) {
+ *nextQueryId = 0;
+ } else {
+ *nextQueryId = queryId;
+ }
+}
+
+extern void GLAPIENTRY
+_mesa_GetPerfQueryIdByNameINTEL(char *queryName, GLuint *queryId)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ unsigned i;
+
+ /* The GL_INTEL_performance_query spec says:
+ *
+ * "If queryName does not reference a valid query name, an INVALID_VALUE
+ * error is generated."
+ */
+ if (!queryName) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glGetPerfQueryIdByNameINTEL(queryName == NULL)");
+ return;
+ }
+
+ /* The specification does not state that this produces an error. */
+ if (!queryId) {
+ _mesa_warning(ctx, "glGetPerfQueryIdByNameINTEL(queryId == NULL)");
+ return;
+ }
+
+ for (i = 0; i < ctx->PerfMonitor.NumGroups; ++i) {
+ const struct gl_perf_monitor_group *group_obj = get_group(ctx, i);
+ if (strcmp(group_obj->Name, queryName) == 0) {
+ *queryId = index_to_queryid(i);
+ return;
+ }
+ }
+
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glGetPerfQueryIdByNameINTEL(invalid query name)");
+}
+
+extern void GLAPIENTRY
+_mesa_GetPerfQueryInfoINTEL(GLuint queryId,
+ GLuint queryNameLength, char *queryName,
+ GLuint *dataSize, GLuint *noCounters,
+ GLuint *noActiveInstances,
+ GLuint *capsMask)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ unsigned i;
+
+ const struct gl_perf_monitor_group *group_obj =
+ get_group(ctx, queryid_to_index(queryId));
+
+ if (group_obj == NULL) {
+ /* The GL_INTEL_performance_query spec says:
+ *
+ * "If queryId does not reference a valid query type, an
+ * INVALID_VALUE error is generated."
+ */
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glGetPerfQueryInfoINTEL(invalid query)");
+ return;
+ }
+
+ if (queryName) {
+ strncpy(queryName, group_obj->Name, queryNameLength);
+
+ /* No specification given about whether the string needs to be
+ * zero-terminated. Zero-terminate the string always as we don't
+ * otherwise communicate the length of the returned string.
+ */
+ if (queryNameLength > 0) {
+ queryName[queryNameLength - 1] = '\0';
+ }
+ }
+
+ if (dataSize) {
+ unsigned size = 0;
+ for (i = 0; i < group_obj->NumCounters; ++i) {
+ /* What we get from the driver is group id (uint32_t) + counter id
+ * (uint32_t) + value.
+ */
+ size += 2 * sizeof(uint32_t) + _mesa_perf_monitor_counter_size(&group_obj->Counters[i]);
+ }
+ *dataSize = size;
+ }
+
+ if (noCounters) {
+ *noCounters = group_obj->NumCounters;
+ }
+
+ /* The GL_INTEL_performance_query spec says:
+ *
+ * "-- the actual number of already created query instances in
+ * maxInstances location"
+ *
+ * 1) Typo in the specification, should be noActiveInstances.
+ * 2) Another typo in the specification, maxInstances parameter is not listed
+ * in the declaration of this function in the list of new functions.
+ */
+ if (noActiveInstances) {
+ *noActiveInstances = _mesa_HashNumEntries(ctx->PerfMonitor.Monitors);
+ }
+
+ if (capsMask) {
+ /* TODO: This information not yet available in the monitor structs. For
+ * now, we hardcode SINGLE_CONTEXT, since that's what the implementation
+ * currently tries very hard to do.
+ */
+ *capsMask = GL_PERFQUERY_SINGLE_CONTEXT_INTEL;
+ }
+}
+
+extern void GLAPIENTRY
+_mesa_GetPerfCounterInfoINTEL(GLuint queryId, GLuint counterId,
+ GLuint counterNameLength, char *counterName,
+ GLuint counterDescLength, char *counterDesc,
+ GLuint *counterOffset, GLuint *counterDataSize, GLuint *counterTypeEnum,
+ GLuint *counterDataTypeEnum, GLuint64 *rawCounterMaxValue)
+{
+ GET_CURRENT_CONTEXT(ctx);
+
+ const struct gl_perf_monitor_group *group_obj;
+ const struct gl_perf_monitor_counter *counter_obj;
+ unsigned counterIndex;
+ unsigned i;
+
+ group_obj = get_group(ctx, queryid_to_index(queryId));
+
+ /* The GL_INTEL_performance_query spec says:
+ *
+ * "If the pair of queryId and counterId does not reference a valid
+ * counter, an INVALID_VALUE error is generated."
+ */
+ if (group_obj == NULL) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glGetPerfCounterInfoINTEL(invalid queryId)");
+ return;
+ }
+
+ counterIndex = counterid_to_index(counterId);
+ counter_obj = get_counter(group_obj, counterIndex);
+
+ if (counter_obj == NULL) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glGetPerfCounterInfoINTEL(invalid counterId)");
+ return;
+ }
+
+ if (counterName) {
+ strncpy(counterName, counter_obj->Name, counterNameLength);
+
+ /* No specification given about whether the string needs to be
+ * zero-terminated. Zero-terminate the string always as we don't
+ * otherwise communicate the length of the returned string.
+ */
+ if (counterNameLength > 0) {
+ counterName[counterNameLength - 1] = '\0';
+ }
+ }
+
+ if (counterDesc) {
+ /* TODO: No separate description text at the moment. We pass the name
+ * again for the moment.
+ */
+ strncpy(counterDesc, counter_obj->Name, counterDescLength);
+
+ /* No specification given about whether the string needs to be
+ * zero-terminated. Zero-terminate the string always as we don't
+ * otherwise communicate the length of the returned string.
+ */
+ if (counterDescLength > 0) {
+ counterDesc[counterDescLength - 1] = '\0';
+ }
+ }
+
+ if (counterOffset) {
+ unsigned offset = 0;
+ for (i = 0; i < counterIndex; ++i) {
+ /* What we get from the driver is group id (uint32_t) + counter id
+ * (uint32_t) + value.
+ */
+ offset += 2 * sizeof(uint32_t) + _mesa_perf_monitor_counter_size(&group_obj->Counters[i]);
+ }
+ *counterOffset = 2 * sizeof(uint32_t) + offset;
+ }
+
+ if (counterDataSize) {
+ *counterDataSize = _mesa_perf_monitor_counter_size(counter_obj);
+ }
+
+ if (counterTypeEnum) {
+ /* TODO: Different counter types (semantic type, not data type) not
+ * supported as of yet.
+ */
+ *counterTypeEnum = GL_PERFQUERY_COUNTER_RAW_INTEL;
+ }
+
+ if (counterDataTypeEnum) {
+ switch (counter_obj->Type) {
+ case GL_FLOAT:
+ case GL_PERCENTAGE_AMD:
+ *counterDataTypeEnum = GL_PERFQUERY_COUNTER_DATA_FLOAT_INTEL;
+ break;
+ case GL_UNSIGNED_INT:
+ *counterDataTypeEnum = GL_PERFQUERY_COUNTER_DATA_UINT32_INTEL;
+ break;
+ case GL_UNSIGNED_INT64_AMD:
+ *counterDataTypeEnum = GL_PERFQUERY_COUNTER_DATA_UINT64_INTEL;
+ break;
+ default:
+ assert(!"Should not get here: invalid counter type");
+ return;
+ }
+ }
+
+ if (rawCounterMaxValue) {
+ /* This value is (implicitly) specified to be used only with
+ * GL_PERFQUERY_COUNTER_RAW_INTEL counters. When semantic types for
+ * counters are added, that needs to be checked.
+ */
+
+ /* The GL_INTEL_performance_query spec says:
+ *
+ * "for some raw counters for which the maximal value is
+ * deterministic, the maximal value of the counter in 1 second is
+ * returned in the location pointed by rawCounterMaxValue, otherwise,
+ * the location is written with the value of 0."
+ *
+ * The maximum value reported by the driver at the moment is not with
+ * these semantics, so write 0 always to be safe.
+ */
+ *rawCounterMaxValue = 0;
+ }
+}
+
+extern void GLAPIENTRY
+_mesa_CreatePerfQueryINTEL(GLuint queryId, GLuint *queryHandle)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GLuint first;
+ GLuint group;
+ const struct gl_perf_monitor_group *group_obj;
+ struct gl_perf_monitor_object *m;
+ unsigned i;
+
+ /* This is not specified in the extension, but is the only sane thing to
+ * do.
+ */
+ if (queryHandle == NULL) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glCreatePerfQueryINTEL(queryHandle == NULL)");
+ return;
+ }
+
+ group = queryid_to_index(queryId);
+ group_obj = get_group(ctx, group);
+
+ /* The GL_INTEL_performance_query spec says:
+ *
+ * "If queryId does not reference a valid query type, an INVALID_VALUE
+ * error is generated."
+ */
+ if (group_obj == NULL) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glCreatePerfQueryINTEL(invalid queryId)");
+ return;
+ }
+
+ /* The query object created here is the counterpart of a `monitor' in
+ * AMD_performance_monitor. This call is equivalent to calling
+ * GenPerfMonitorsAMD and SelectPerfMonitorCountersAMD with a list of all
+ * counters in a group.
+ */
+
+ /* We keep the monitor ids contiguous */
+ first = _mesa_HashFindFreeKeyBlock(ctx->PerfMonitor.Monitors, 1);
+ if (!first) {
+ /* The GL_INTEL_performance_query spec says:
+ *
+ * "If the query instance cannot be created due to exceeding the
+ * number of allowed instances or driver fails query creation due to
+ * an insufficient memory reason, an OUT_OF_MEMORY error is
+ * generated, and the location pointed by queryHandle returns NULL."
+ */
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCreatePerfQueryINTEL");
+ return;
+ }
+
+ m = new_performance_monitor(ctx, first);
+ _mesa_HashInsert(ctx->PerfMonitor.Monitors, first, m);
+ *queryHandle = first;
+
+ ctx->Driver.ResetPerfMonitor(ctx, m);
+
+ for (i = 0; i < group_obj->NumCounters; ++i) {
+ ++m->ActiveGroups[group];
+ /* Counters are a continuous range of integers, 0 to NumCounters (excl),
+ * so i is the counter value to use here.
+ */
+ BITSET_SET(m->ActiveCounters[group], i);
+ }
+}
+
+extern void GLAPIENTRY
+_mesa_DeletePerfQueryINTEL(GLuint queryHandle)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct gl_perf_monitor_object *m;
+
+ /* The queryHandle is the counterpart to AMD_performance_monitor's monitor
+ * id.
+ */
+ m = lookup_monitor(ctx, queryHandle);
+
+ /* The GL_INTEL_performance_query spec says:
+ *
+ * "If a query handle doesn't reference a previously created performance
+ * query instance, an INVALID_VALUE error is generated."
+ */
+ if (m == NULL) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glDeletePerfQueryINTEL(invalid queryHandle)");
+ return;
+ }
+
+ /* Let the driver stop the monitor if it's active. */
+ if (m->Active) {
+ ctx->Driver.ResetPerfMonitor(ctx, m);
+ m->Ended = false;
+ }
+
+ _mesa_HashRemove(ctx->PerfMonitor.Monitors, queryHandle);
+ ralloc_free(m->ActiveGroups);
+ ralloc_free(m->ActiveCounters);
+ ctx->Driver.DeletePerfMonitor(ctx, m);
+}
+
+extern void GLAPIENTRY
+_mesa_BeginPerfQueryINTEL(GLuint queryHandle)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct gl_perf_monitor_object *m;
+
+ /* The queryHandle is the counterpart to AMD_performance_monitor's monitor
+ * id.
+ */
+
+ m = lookup_monitor(ctx, queryHandle);
+
+ /* The GL_INTEL_performance_query spec says:
+ *
+ * "If a query handle doesn't reference a previously created performance
+ * query instance, an INVALID_VALUE error is generated."
+ */
+ if (m == NULL) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glBeginPerfQueryINTEL(invalid queryHandle)");
+ return;
+ }
+
+ /* The GL_INTEL_performance_query spec says:
+ *
+ * "Note that some query types, they cannot be collected in the same
+ * time. Therefore calls of BeginPerfQueryINTEL() cannot be nested if
+ * they refer to queries of such different types. In such case
+ * INVALID_OPERATION error is generated."
+ *
+ * We also generate an INVALID_OPERATION error if the driver can't begin
+ * monitoring for its own reasons, and for nesting the same query.
+ */
+ if (m->Active) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glBeginPerfQueryINTEL(already active)");
+ return;
+ }
+
+ if (ctx->Driver.BeginPerfMonitor(ctx, m)) {
+ m->Active = true;
+ m->Ended = false;
+ } else {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glBeginPerfQueryINTEL(driver unable to begin monitoring)");
+ }
+}
+
+extern void GLAPIENTRY
+_mesa_EndPerfQueryINTEL(GLuint queryHandle)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct gl_perf_monitor_object *m;
+
+ /* The queryHandle is the counterpart to AMD_performance_monitor's monitor
+ * id.
+ */
+
+ m = lookup_monitor(ctx, queryHandle);
+
+ /* The GL_INTEL_performance_query spec says:
+ *
+ * "If a performance query is not currently started, an
+ * INVALID_OPERATION error will be generated."
+ *
+ * The specification doesn't state that an invalid handle would be an
+ * INVALID_VALUE error. Regardless, query for such a handle will not be
+ * started, so we generate an INVALID_OPERATION in that case too.
+ */
+ if (m == NULL) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glEndPerfQueryINTEL(invalid queryHandle)");
+ return;
+ }
+
+ if (!m->Active) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glEndPerfQueryINTEL(not active)");
+ return;
+ }
+
+ ctx->Driver.EndPerfMonitor(ctx, m);
+
+ m->Active = false;
+ m->Ended = true;
+}
+
+extern void GLAPIENTRY
+_mesa_GetPerfQueryDataINTEL(GLuint queryHandle, GLuint flags,
+ GLsizei dataSize, void *data, GLuint *bytesWritten)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct gl_perf_monitor_object *m;
+ bool result_available;
+
+ /* The GL_INTEL_performance_query spec says:
+ *
+ * "If bytesWritten or data pointers are NULL then an INVALID_VALUE
+ * error is generated."
+ */
+ if (!bytesWritten || !data) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glGetPerfQueryDataINTEL(bytesWritten or data is NULL)");
+ return;
+ }
+
+ /* The queryHandle is the counterpart to AMD_performance_monitor's monitor
+ * id.
+ */
+
+ m = lookup_monitor(ctx, queryHandle);
+
+ /* The specification doesn't state that an invalid handle generates an
+ * error. We could interpret that to mean the case should be handled as
+ * "measurement not ready for this query", but what should be done if
+ * `flags' equals PERFQUERY_WAIT_INTEL?
+ *
+ * To resolve this, we just generate an INVALID_VALUE from an invalid query
+ * handle.
+ */
+ if (m == NULL) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glGetPerfQueryDataINTEL(invalid queryHandle)");
+ return;
+ }
+
+ /* We need at least enough room for a single value. */
+ if (dataSize < sizeof(GLuint)) {
+ *bytesWritten = 0;
+ return;
+ }
+
+ /* The GL_INTEL_performance_query spec says:
+ *
+ * "The call may end without returning any data if they are not ready
+ * for reading as the measurement session is still pending (the
+ * EndPerfQueryINTEL() command processing is not finished by
+ * hardware). In this case location pointed by the bytesWritten
+ * parameter will be set to 0."
+ *
+ * If EndPerfQueryINTEL() is not called at all, we follow this.
+ */
+ if (!m->Ended) {
+ *bytesWritten = 0;
+ return;
+ }
+
+ result_available = ctx->Driver.IsPerfMonitorResultAvailable(ctx, m);
+
+ if (!result_available) {
+ if (flags == GL_PERFQUERY_FLUSH_INTEL) {
+ ctx->Driver.Flush(ctx);
+ } else if (flags == GL_PERFQUERY_WAIT_INTEL) {
+ /* Assume Finish() is both enough and not too much to wait for
+ * results. If results are still not available after Finish(), the
+ * later code automatically bails out with 0 for bytesWritten.
+ */
+ ctx->Driver.Finish(ctx);
+ result_available =
+ ctx->Driver.IsPerfMonitorResultAvailable(ctx, m);
+ }
+ }
+
+ if (result_available) {
+ ctx->Driver.GetPerfMonitorResult(ctx, m, dataSize, data, (GLint*)bytesWritten);
+ } else {
+ *bytesWritten = 0;
+ }
+}
diff --git a/mesalib/src/mesa/main/performance_monitor.h b/mesalib/src/mesa/main/performance_monitor.h
index 76234e5c1..7b311e4e0 100644
--- a/mesalib/src/mesa/main/performance_monitor.h
+++ b/mesalib/src/mesa/main/performance_monitor.h
@@ -23,7 +23,8 @@
/**
* \file performance_monitor.h
- * Core Mesa support for the AMD_performance_monitor extension.
+ * Core Mesa support for the AMD_performance_monitor extension and the
+ * INTEL_performance_query extension.
*/
#pragma once
@@ -85,4 +86,44 @@ _mesa_GetPerfMonitorCounterDataAMD(GLuint monitor, GLenum pname,
unsigned
_mesa_perf_monitor_counter_size(const struct gl_perf_monitor_counter *);
+
+extern void GLAPIENTRY
+_mesa_GetFirstPerfQueryIdINTEL(GLuint *queryId);
+
+extern void GLAPIENTRY
+_mesa_GetNextPerfQueryIdINTEL(GLuint queryId, GLuint *nextQueryId);
+
+extern void GLAPIENTRY
+_mesa_GetPerfQueryIdByNameINTEL(char *queryName, GLuint *queryId);
+
+extern void GLAPIENTRY
+_mesa_GetPerfQueryInfoINTEL(GLuint queryId,
+ GLuint queryNameLength, char *queryName,
+ GLuint *dataSize, GLuint *noCounters,
+ GLuint *noActiveInstances,
+ GLuint *capsMask);
+
+extern void GLAPIENTRY
+_mesa_GetPerfCounterInfoINTEL(GLuint queryId, GLuint counterId,
+ GLuint counterNameLength, char *counterName,
+ GLuint counterDescLength, char *counterDesc,
+ GLuint *counterOffset, GLuint *counterDataSize, GLuint *counterTypeEnum,
+ GLuint *counterDataTypeEnum, GLuint64 *rawCounterMaxValue);
+
+extern void GLAPIENTRY
+_mesa_CreatePerfQueryINTEL(GLuint queryId, GLuint *queryHandle);
+
+extern void GLAPIENTRY
+_mesa_DeletePerfQueryINTEL(GLuint queryHandle);
+
+extern void GLAPIENTRY
+_mesa_BeginPerfQueryINTEL(GLuint queryHandle);
+
+extern void GLAPIENTRY
+_mesa_EndPerfQueryINTEL(GLuint queryHandle);
+
+extern void GLAPIENTRY
+_mesa_GetPerfQueryDataINTEL(GLuint queryHandle, GLuint flags,
+ GLsizei dataSize, void *data, GLuint *bytesWritten);
+
#endif
diff --git a/mesalib/src/mesa/main/pipelineobj.c b/mesalib/src/mesa/main/pipelineobj.c
index f55251e06..90c1d005f 100644
--- a/mesalib/src/mesa/main/pipelineobj.c
+++ b/mesalib/src/mesa/main/pipelineobj.c
@@ -412,8 +412,15 @@ _mesa_BindProgramPipeline(GLuint pipeline)
newObj->EverBound = GL_TRUE;
}
+ _mesa_bind_pipeline(ctx, newObj);
+}
+
+void
+_mesa_bind_pipeline(struct gl_context *ctx,
+ struct gl_pipeline_object *pipe)
+{
/* First bind the Pipeline to pipeline binding point */
- _mesa_reference_pipeline_object(ctx, &ctx->Pipeline.Current, newObj);
+ _mesa_reference_pipeline_object(ctx, &ctx->Pipeline.Current, pipe);
/* Section 2.11.3 (Program Objects) of the OpenGL 4.1 spec says:
*
@@ -424,11 +431,11 @@ _mesa_BindProgramPipeline(GLuint pipeline)
* considered current."
*/
if (&ctx->Shader != ctx->_Shader) {
- if (pipeline) {
+ if (pipe != NULL) {
/* Bound the pipeline to the current program and
* restore the pipeline state
*/
- _mesa_reference_pipeline_object(ctx, &ctx->_Shader, newObj);
+ _mesa_reference_pipeline_object(ctx, &ctx->_Shader, pipe);
} else {
/* Unbind the pipeline */
_mesa_reference_pipeline_object(ctx, &ctx->_Shader,
diff --git a/mesalib/src/mesa/main/pipelineobj.h b/mesalib/src/mesa/main/pipelineobj.h
index ceaf4f14c..7285a78f1 100644
--- a/mesalib/src/mesa/main/pipelineobj.h
+++ b/mesalib/src/mesa/main/pipelineobj.h
@@ -59,6 +59,10 @@ _mesa_reference_pipeline_object(struct gl_context *ctx,
_mesa_reference_pipeline_object_(ctx, ptr, obj);
}
+extern void
+_mesa_bind_pipeline(struct gl_context *ctx,
+ struct gl_pipeline_object *pipe);
+
extern GLboolean
_mesa_validate_program_pipeline(struct gl_context * ctx, struct gl_pipeline_object *pipe, GLboolean IsBound);
diff --git a/mesalib/src/mesa/main/samplerobj.c b/mesalib/src/mesa/main/samplerobj.c
index 4900d5256..18a14d89a 100644
--- a/mesalib/src/mesa/main/samplerobj.c
+++ b/mesalib/src/mesa/main/samplerobj.c
@@ -51,6 +51,28 @@ _mesa_lookup_samplerobj(struct gl_context *ctx, GLuint name)
}
+static inline void
+begin_samplerobj_lookups(struct gl_context *ctx)
+{
+ _mesa_HashLockMutex(ctx->Shared->SamplerObjects);
+}
+
+
+static inline void
+end_samplerobj_lookups(struct gl_context *ctx)
+{
+ _mesa_HashUnlockMutex(ctx->Shared->SamplerObjects);
+}
+
+
+static inline struct gl_sampler_object *
+lookup_samplerobj_locked(struct gl_context *ctx, GLuint name)
+{
+ return (struct gl_sampler_object *)
+ _mesa_HashLookupLocked(ctx->Shared->SamplerObjects, name);
+}
+
+
/**
* Handle reference counting.
*/
@@ -285,6 +307,105 @@ _mesa_BindSampler(GLuint unit, GLuint sampler)
}
+void GLAPIENTRY
+_mesa_BindSamplers(GLuint first, GLsizei count, const GLuint *samplers)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GLint i;
+
+ /* The ARB_multi_bind spec says:
+ *
+ * "An INVALID_OPERATION error is generated if <first> + <count> is
+ * greater than the number of texture image units supported by
+ * the implementation."
+ */
+ if (first + count > ctx->Const.MaxCombinedTextureImageUnits) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glBindSamplers(first=%u + count=%d > the value of "
+ "GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS=%u)",
+ first, count, ctx->Const.MaxCombinedTextureImageUnits);
+ return;
+ }
+
+ FLUSH_VERTICES(ctx, 0);
+
+ if (samplers) {
+ /* Note that the error semantics for multi-bind commands differ from
+ * those of other GL commands.
+ *
+ * The Issues section in the ARB_multi_bind spec says:
+ *
+ * "(11) Typically, OpenGL specifies that if an error is generated by
+ * a command, that command has no effect. This is somewhat
+ * unfortunate for multi-bind commands, because it would require
+ * a first pass to scan the entire list of bound objects for
+ * errors and then a second pass to actually perform the
+ * bindings. Should we have different error semantics?
+ *
+ * RESOLVED: Yes. In this specification, when the parameters for
+ * one of the <count> binding points are invalid, that binding
+ * point is not updated and an error will be generated. However,
+ * other binding points in the same command will be updated if
+ * their parameters are valid and no other error occurs."
+ */
+
+ begin_samplerobj_lookups(ctx);
+
+ for (i = 0; i < count; i++) {
+ const GLuint unit = first + i;
+ struct gl_sampler_object * const currentSampler =
+ ctx->Texture.Unit[unit].Sampler;
+ struct gl_sampler_object *sampObj;
+
+ if (samplers[i] != 0) {
+ if (currentSampler && currentSampler->Name == samplers[i])
+ sampObj = currentSampler;
+ else
+ sampObj = lookup_samplerobj_locked(ctx, samplers[i]);
+
+ /* The ARB_multi_bind spec says:
+ *
+ * "An INVALID_OPERATION error is generated if any value
+ * in <samplers> is not zero or the name of an existing
+ * sampler object (per binding)."
+ */
+ if (!sampObj) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glBindSamplers(samplers[%d]=%u is not zero or "
+ "the name of an existing sampler object)",
+ i, samplers[i]);
+ continue;
+ }
+ } else {
+ sampObj = NULL;
+ }
+
+ /* Bind the new sampler */
+ if (sampObj != currentSampler) {
+ _mesa_reference_sampler_object(ctx,
+ &ctx->Texture.Unit[unit].Sampler,
+ sampObj);
+ ctx->NewState |= _NEW_TEXTURE;
+ }
+ }
+
+ end_samplerobj_lookups(ctx);
+ } else {
+ /* Unbind all samplers in the range <first> through <first>+<count>-1 */
+ for (i = 0; i < count; i++) {
+ const GLuint unit = first + i;
+
+ if (ctx->Texture.Unit[unit].Sampler) {
+ _mesa_reference_sampler_object(ctx,
+ &ctx->Texture.Unit[unit].Sampler,
+ NULL);
+ ctx->NewState |= _NEW_TEXTURE;
+ }
+ }
+ }
+}
+
+
/**
* Check if a coordinate wrap mode is legal.
* \return GL_TRUE if legal, GL_FALSE otherwise
diff --git a/mesalib/src/mesa/main/samplerobj.h b/mesalib/src/mesa/main/samplerobj.h
index c72b1cd8d..7d80b383d 100644
--- a/mesalib/src/mesa/main/samplerobj.h
+++ b/mesalib/src/mesa/main/samplerobj.h
@@ -81,6 +81,8 @@ _mesa_IsSampler(GLuint sampler);
void GLAPIENTRY
_mesa_BindSampler(GLuint unit, GLuint sampler);
void GLAPIENTRY
+_mesa_BindSamplers(GLuint first, GLsizei count, const GLuint *samplers);
+void GLAPIENTRY
_mesa_SamplerParameteri(GLuint sampler, GLenum pname, GLint param);
void GLAPIENTRY
_mesa_SamplerParameterf(GLuint sampler, GLenum pname, GLfloat param);
diff --git a/mesalib/src/mesa/main/shader_query.cpp b/mesalib/src/mesa/main/shader_query.cpp
index f66c11733..36d1d9cc0 100644
--- a/mesalib/src/mesa/main/shader_query.cpp
+++ b/mesalib/src/mesa/main/shader_query.cpp
@@ -153,6 +153,63 @@ _mesa_GetActiveAttrib(GLhandleARB program, GLuint desired_index,
_mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib(index)");
}
+/* Locations associated with shader variables (array or non-array) can be
+ * queried using its base name or using the base name appended with the
+ * valid array index. For example, in case of below vertex shader, valid
+ * queries can be made to know the location of "xyz", "array", "array[0]",
+ * "array[1]", "array[2]" and "array[3]". In this example index reurned
+ * will be 0, 0, 0, 1, 2, 3 respectively.
+ *
+ * [Vertex Shader]
+ * layout(location=0) in vec4 xyz;
+ * layout(location=1) in vec4[4] array;
+ * void main()
+ * { }
+ *
+ * This requirement came up with the addition of ARB_program_interface_query
+ * to OpenGL 4.3 specification. See page 101 (page 122 of the PDF) for details.
+ *
+ * This utility function is used by:
+ * _mesa_GetAttribLocation
+ * _mesa_GetFragDataLocation
+ * _mesa_GetFragDataIndex
+ *
+ * Returns 0:
+ * if the 'name' string matches var->name.
+ * Returns 'matched index':
+ * if the 'name' string matches var->name appended with valid array index.
+ */
+int static inline
+get_matching_index(const ir_variable *const var, const char *name) {
+ unsigned idx = 0;
+ const char *const paren = strchr(name, '[');
+ const unsigned len = (paren != NULL) ? paren - name : strlen(name);
+
+ if (paren != NULL) {
+ if (!var->type->is_array())
+ return -1;
+
+ char *endptr;
+ idx = (unsigned) strtol(paren + 1, &endptr, 10);
+ const unsigned idx_len = endptr != (paren + 1) ? endptr - paren - 1 : 0;
+
+ /* Validate the sub string representing index in 'name' string */
+ if ((idx > 0 && paren[1] == '0') /* leading zeroes */
+ || (idx == 0 && idx_len > 1) /* all zeroes */
+ || paren[1] == ' ' /* whitespace */
+ || endptr[0] != ']' /* closing brace */
+ || endptr[1] != '\0' /* null char */
+ || idx_len == 0 /* missing index */
+ || idx >= var->type->length) /* exceeding array bound */
+ return -1;
+ }
+
+ if (strncmp(var->name, name, len) == 0 && var->name[len] == '\0')
+ return idx;
+
+ return -1;
+}
+
GLint GLAPIENTRY
_mesa_GetAttribLocation(GLhandleARB program, const GLcharARB * name)
{
@@ -196,8 +253,10 @@ _mesa_GetAttribLocation(GLhandleARB program, const GLcharARB * name)
|| var->data.location < VERT_ATTRIB_GENERIC0)
continue;
- if (strcmp(var->name, name) == 0)
- return var->data.location - VERT_ATTRIB_GENERIC0;
+ int index = get_matching_index(var, (const char *) name);
+
+ if (index >= 0)
+ return var->data.location + index - VERT_ATTRIB_GENERIC0;
}
return -1;
@@ -358,7 +417,7 @@ _mesa_GetFragDataIndex(GLuint program, const GLchar *name)
|| var->data.location < FRAG_RESULT_DATA0)
continue;
- if (strcmp(var->name, name) == 0)
+ if (get_matching_index(var, (const char *) name) >= 0)
return var->data.index;
}
@@ -414,8 +473,10 @@ _mesa_GetFragDataLocation(GLuint program, const GLchar *name)
|| var->data.location < FRAG_RESULT_DATA0)
continue;
- if (strcmp(var->name, name) == 0)
- return var->data.location - FRAG_RESULT_DATA0;
+ int index = get_matching_index(var, (const char *) name);
+
+ if (index >= 0)
+ return var->data.location + index - FRAG_RESULT_DATA0;
}
return -1;
diff --git a/mesalib/src/mesa/main/shaderapi.c b/mesalib/src/mesa/main/shaderapi.c
index 1c8e6b4cf..6f84acd01 100644
--- a/mesalib/src/mesa/main/shaderapi.c
+++ b/mesalib/src/mesa/main/shaderapi.c
@@ -700,9 +700,6 @@ get_programiv(struct gl_context *ctx, GLuint program, GLenum pname, GLint *param
return;
}
case GL_PROGRAM_SEPARABLE:
- if (!ctx->Extensions.ARB_separate_shader_objects)
- break;
-
*params = shProg->SeparateShader;
return;
default:
@@ -795,7 +792,7 @@ get_shader_source(struct gl_context *ctx, GLuint shader, GLsizei maxLength,
/**
* Set/replace shader source code. A helper function used by
- * glShaderSource[ARB] and glCreateShaderProgramEXT.
+ * glShaderSource[ARB].
*/
static void
shader_source(struct gl_context *ctx, GLuint shader, const GLchar *source)
@@ -1548,15 +1545,14 @@ _mesa_UseProgram(GLhandleARB program)
shProg = NULL;
}
- /* The "Dependencies on EXT_separate_shader_objects" section of the
- * ARB_separate_shader_object spec says:
+ /* The ARB_separate_shader_object spec says:
*
* "The executable code for an individual shader stage is taken from
* the current program for that stage. If there is a current program
- * object for any shader stage or for uniform updates established by
- * UseProgram, UseShaderProgramEXT, or ActiveProgramEXT, the current
- * program for that stage (if any) is considered current. Otherwise,
- * if there is a bound program pipeline object ..."
+ * object established by UseProgram, that program is considered current
+ * for all stages. Otherwise, if there is a bound program pipeline
+ * object (section 2.14.PPO), the program bound to the appropriate
+ * stage of the pipeline object is considered current."
*/
if (program) {
/* Attach shader state to the binding point */
@@ -1777,9 +1773,6 @@ _mesa_ProgramParameteri(GLuint program, GLenum pname, GLint value)
return;
case GL_PROGRAM_SEPARABLE:
- if (!ctx->Extensions.ARB_separate_shader_objects)
- break;
-
/* Spec imply that the behavior is the same as ARB_get_program_binary
* Chapter 7.3 Program Objects
*/
@@ -1814,124 +1807,6 @@ _mesa_use_shader_program(struct gl_context *ctx, GLenum type,
}
-/**
- * For GL_EXT_separate_shader_objects
- */
-void GLAPIENTRY
-_mesa_UseShaderProgramEXT(GLenum type, GLuint program)
-{
- GET_CURRENT_CONTEXT(ctx);
- struct gl_shader_program *shProg = NULL;
-
- if (!_mesa_validate_shader_target(ctx, type)) {
- _mesa_error(ctx, GL_INVALID_ENUM, "glUseShaderProgramEXT(type)");
- return;
- }
-
- if (_mesa_is_xfb_active_and_unpaused(ctx)) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glUseShaderProgramEXT(transform feedback is active)");
- return;
- }
-
- if (program) {
- shProg = _mesa_lookup_shader_program_err(ctx, program,
- "glUseShaderProgramEXT");
- if (shProg == NULL)
- return;
-
- if (!shProg->LinkStatus) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glUseShaderProgramEXT(program not linked)");
- return;
- }
- }
-
- /* The "Dependencies on EXT_separate_shader_objects" section of the
- * ARB_separate_shader_object spec says:
- *
- * "The executable code for an individual shader stage is taken from
- * the current program for that stage. If there is a current program
- * object for any shader stage or for uniform updates established by
- * UseProgram, UseShaderProgramEXT, or ActiveProgramEXT, the current
- * program for that stage (if any) is considered current. Otherwise,
- * if there is a bound program pipeline object ..."
- */
- if (program) {
- /* Attach shader state to the binding point */
- _mesa_reference_pipeline_object(ctx, &ctx->_Shader, &ctx->Shader);
- /* Update the program */
- _mesa_use_shader_program(ctx, type, shProg, ctx->_Shader);
- } else {
- /* Must be done first: detach the progam */
- _mesa_use_shader_program(ctx, type, shProg, ctx->_Shader);
-
- /* Nothing remains current */
- if (!ctx->Shader.CurrentProgram[MESA_SHADER_VERTEX] &&
- !ctx->Shader.CurrentProgram[MESA_SHADER_GEOMETRY] &&
- !ctx->Shader.CurrentProgram[MESA_SHADER_FRAGMENT] &&
- !ctx->Shader.ActiveProgram) {
-
- /* Unattach shader_state binding point */
- _mesa_reference_pipeline_object(ctx, &ctx->_Shader,
- ctx->Pipeline.Default);
-
- /* If a pipeline was bound, rebind it */
- if (ctx->Pipeline.Current) {
- _mesa_BindProgramPipeline(ctx->Pipeline.Current->Name);
- }
- }
- }
-}
-
-
-/**
- * For GL_EXT_separate_shader_objects
- */
-void GLAPIENTRY
-_mesa_ActiveProgramEXT(GLuint program)
-{
- GET_CURRENT_CONTEXT(ctx);
- struct gl_shader_program *shProg = (program != 0)
- ? _mesa_lookup_shader_program_err(ctx, program, "glActiveProgramEXT")
- : NULL;
-
- /* The "Dependencies on EXT_separate_shader_objects" section of the
- * ARB_separate_shader_object spec says:
- *
- * "The executable code for an individual shader stage is taken from
- * the current program for that stage. If there is a current program
- * object for any shader stage or for uniform updates established by
- * UseProgram, UseShaderProgramEXT, or ActiveProgramEXT, the current
- * program for that stage (if any) is considered current. Otherwise,
- * if there is a bound program pipeline object ..."
- */
- if (shProg != NULL) {
- /* Attach shader state to the binding point */
- _mesa_reference_pipeline_object(ctx, &ctx->_Shader, &ctx->Shader);
- _mesa_active_program(ctx, shProg, "glActiveProgramEXT");
- } else {
- /* Must be done first: unset the current active progam */
- _mesa_active_program(ctx, shProg, "glActiveProgramEXT");
-
- /* Nothing remains current */
- if (!ctx->Shader.CurrentProgram[MESA_SHADER_VERTEX] &&
- !ctx->Shader.CurrentProgram[MESA_SHADER_GEOMETRY] &&
- !ctx->Shader.CurrentProgram[MESA_SHADER_FRAGMENT] &&
- !ctx->Shader.ActiveProgram) {
-
- /* Unattach shader_state binding point */
- _mesa_reference_pipeline_object(ctx, &ctx->_Shader, ctx->Pipeline.Default);
- /* If a pipeline was bound, rebind it */
- if (ctx->Pipeline.Current) {
- _mesa_BindProgramPipeline(ctx->Pipeline.Current->Name);
- }
- }
- }
-
- return;
-}
-
static GLuint
_mesa_create_shader_program(struct gl_context* ctx, GLboolean separate,
GLenum type, GLsizei count, const GLchar* const *strings)
@@ -2016,23 +1891,8 @@ _mesa_copy_linked_program_data(gl_shader_stage type,
}
}
-
-/**
- * For GL_EXT_separate_shader_objects
- */
-GLuint GLAPIENTRY
-_mesa_CreateShaderProgramEXT(GLenum type, const GLchar *string)
-{
- GET_CURRENT_CONTEXT(ctx);
-
- return _mesa_create_shader_program(ctx, GL_FALSE, type, 1, &string);
-}
-
/**
* ARB_separate_shader_objects: Compile & Link Program
- *
- * Basically the same as _mesa_CreateShaderProgramEXT but with support of
- * multiple strings and sets the SeparateShader flag to true.
*/
GLuint GLAPIENTRY
_mesa_CreateShaderProgramv(GLenum type, GLsizei count,
diff --git a/mesalib/src/mesa/main/shaderimage.c b/mesalib/src/mesa/main/shaderimage.c
index d1e752d3d..9e62f4294 100644
--- a/mesalib/src/mesa/main/shaderimage.c
+++ b/mesalib/src/mesa/main/shaderimage.c
@@ -33,6 +33,7 @@
#include "context.h"
#include "texobj.h"
#include "teximage.h"
+#include "enums.h"
/*
* Define endian-invariant aliases for some mesa formats that are
@@ -479,6 +480,148 @@ _mesa_BindImageTexture(GLuint unit, GLuint texture, GLint level,
}
void GLAPIENTRY
+_mesa_BindImageTextures(GLuint first, GLsizei count, const GLuint *textures)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ int i;
+
+ if (!ctx->Extensions.ARB_shader_image_load_store) {
+ _mesa_error(ctx, GL_INVALID_OPERATION, "glBindImageTextures()");
+ return;
+ }
+
+ if (first + count > ctx->Const.MaxImageUnits) {
+ /* The ARB_multi_bind spec says:
+ *
+ * "An INVALID_OPERATION error is generated if <first> + <count>
+ * is greater than the number of image units supported by
+ * the implementation."
+ */
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glBindImageTextures(first=%u + count=%d > the value of "
+ "GL_MAX_IMAGE_UNITS=%u)",
+ first, count, ctx->Const.MaxImageUnits);
+ return;
+ }
+
+ /* Assume that at least one binding will be changed */
+ FLUSH_VERTICES(ctx, 0);
+ ctx->NewDriverState |= ctx->DriverFlags.NewImageUnits;
+
+ /* Note that the error semantics for multi-bind commands differ from
+ * those of other GL commands.
+ *
+ * The Issues section in the ARB_multi_bind spec says:
+ *
+ * "(11) Typically, OpenGL specifies that if an error is generated by
+ * a command, that command has no effect. This is somewhat
+ * unfortunate for multi-bind commands, because it would require
+ * a first pass to scan the entire list of bound objects for
+ * errors and then a second pass to actually perform the
+ * bindings. Should we have different error semantics?
+ *
+ * RESOLVED: Yes. In this specification, when the parameters for
+ * one of the <count> binding points are invalid, that binding
+ * point is not updated and an error will be generated. However,
+ * other binding points in the same command will be updated if
+ * their parameters are valid and no other error occurs."
+ */
+
+ _mesa_begin_texture_lookups(ctx);
+
+ for (i = 0; i < count; i++) {
+ struct gl_image_unit *u = &ctx->ImageUnits[first + i];
+ const GLuint texture = textures ? textures[i] : 0;
+
+ if (texture != 0) {
+ struct gl_texture_object *texObj;
+ struct gl_texture_image *image;
+ mesa_format actualFormat;
+
+ if (!u->TexObj || u->TexObj->Name != texture) {
+ texObj = _mesa_lookup_texture_locked(ctx, texture);
+ if (!texObj) {
+ /* The ARB_multi_bind spec says:
+ *
+ * "An INVALID_OPERATION error is generated if any value
+ * in <textures> is not zero or the name of an existing
+ * texture object (per binding)."
+ */
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glBindImageTextures(textures[%d]=%u "
+ "is not zero or the name of an existing texture "
+ "object)", i, texture);
+ continue;
+ }
+ } else {
+ texObj = u->TexObj;
+ }
+
+ image = texObj->Image[0][0];
+
+ if (!image || image->Width == 0 || image->Height == 0 || image->Depth == 0) {
+ /* The ARB_multi_bind spec says:
+ *
+ * "An INVALID_OPERATION error is generated if the width,
+ * height, or depth of the level zero texture image of
+ * any texture in <textures> is zero (per binding)."
+ */
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glBindImageTextures(the width, height or depth "
+ "of the level zero texture image of "
+ "textures[%d]=%u is zero)", i, texture);
+ continue;
+ }
+
+ actualFormat = get_image_format(image->InternalFormat);
+
+ if (actualFormat == MESA_FORMAT_NONE) {
+ /* The ARB_multi_bind spec says:
+ *
+ * "An INVALID_OPERATION error is generated if the internal
+ * format of the level zero texture image of any texture
+ * in <textures> is not found in table 8.33 (per binding)."
+ */
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glBindImageTextures(the internal format %s of "
+ "the level zero texture image of textures[%d]=%u "
+ "is not supported)",
+ _mesa_lookup_enum_by_nr(image->InternalFormat),
+ i, texture);
+ continue;
+ }
+
+ /* Update the texture binding */
+ _mesa_reference_texobj(&u->TexObj, texObj);
+ u->Level = 0;
+ u->Layered = _mesa_tex_target_is_layered(texObj->Target);
+ u->Layer = 0;
+ u->Access = GL_READ_WRITE;
+ u->Format = image->InternalFormat;
+ u->_ActualFormat = actualFormat;
+ u->_Valid = validate_image_unit(ctx, u);
+ } else {
+ /* Unbind the texture from the unit */
+ _mesa_reference_texobj(&u->TexObj, NULL);
+ u->Level = 0;
+ u->Layered = GL_FALSE;
+ u->Layer = 0;
+ u->Access = GL_READ_ONLY;
+ u->Format = GL_R8;
+ u->_ActualFormat = MESA_FORMAT_R_UNORM8;
+ u->_Valid = GL_FALSE;
+ }
+
+ /* Pass the BindImageTexture call down to the device driver */
+ if (ctx->Driver.BindImageTexture)
+ ctx->Driver.BindImageTexture(ctx, u, u->TexObj, u->Level, u->Layered,
+ u->Layer, u->Access, u->Format);
+ }
+
+ _mesa_end_texture_lookups(ctx);
+}
+
+void GLAPIENTRY
_mesa_MemoryBarrier(GLbitfield barriers)
{
GET_CURRENT_CONTEXT(ctx);
diff --git a/mesalib/src/mesa/main/shaderimage.h b/mesalib/src/mesa/main/shaderimage.h
index aaecc5d29..733ac7747 100644
--- a/mesalib/src/mesa/main/shaderimage.h
+++ b/mesalib/src/mesa/main/shaderimage.h
@@ -46,6 +46,9 @@ _mesa_BindImageTexture(GLuint unit, GLuint texture, GLint level,
GLenum format);
void GLAPIENTRY
+_mesa_BindImageTextures(GLuint first, GLsizei count, const GLuint *textures);
+
+void GLAPIENTRY
_mesa_MemoryBarrier(GLbitfield barriers);
#endif
diff --git a/mesalib/src/mesa/main/texgetimage.c b/mesalib/src/mesa/main/texgetimage.c
index 2beb0abe6..1ac707d13 100644
--- a/mesalib/src/mesa/main/texgetimage.c
+++ b/mesalib/src/mesa/main/texgetimage.c
@@ -131,8 +131,8 @@ get_tex_depth_stencil(struct gl_context *ctx, GLuint dimensions,
GLint img, row;
assert(format == GL_DEPTH_STENCIL);
- assert(type == GL_UNSIGNED_INT_24_8);
- /* XXX type == GL_FLOAT_32_UNSIGNED_INT_24_8_REV is not handled yet */
+ assert(type == GL_UNSIGNED_INT_24_8 ||
+ type == GL_FLOAT_32_UNSIGNED_INT_24_8_REV);
for (img = 0; img < depth; img++) {
GLubyte *srcMap;
@@ -149,11 +149,10 @@ get_tex_depth_stencil(struct gl_context *ctx, GLuint dimensions,
void *dest = _mesa_image_address(dimensions, &ctx->Pack, pixels,
width, height, format, type,
img, row, 0);
- /* Unpack from texture's format to GL's z24_s8 layout */
- _mesa_unpack_uint_24_8_depth_stencil_row(texImage->TexFormat,
- width,
- (const GLuint *) src,
- dest);
+ _mesa_unpack_depth_stencil_row(texImage->TexFormat,
+ width,
+ (const GLuint *) src,
+ type, dest);
if (ctx->Pack.SwapBytes) {
_mesa_swap4((GLuint *) dest, width);
}
@@ -838,6 +837,11 @@ getteximage_error_check(struct gl_context *ctx, GLenum target, GLint level,
_mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
return GL_TRUE;
}
+ else if (_mesa_is_stencil_format(format)
+ && !ctx->Extensions.ARB_texture_stencil8) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexImage(format=GL_STENCIL_INDEX)");
+ return GL_TRUE;
+ }
else if (_mesa_is_ycbcr_format(format)
&& !_mesa_is_ycbcr_format(baseFormat)) {
_mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexImage(format mismatch)");
diff --git a/mesalib/src/mesa/main/texobj.c b/mesalib/src/mesa/main/texobj.c
index 85246c8ab..2a82c2d4e 100644
--- a/mesalib/src/mesa/main/texobj.c
+++ b/mesalib/src/mesa/main/texobj.c
@@ -61,6 +61,27 @@ _mesa_lookup_texture(struct gl_context *ctx, GLuint id)
}
+void
+_mesa_begin_texture_lookups(struct gl_context *ctx)
+{
+ _mesa_HashLockMutex(ctx->Shared->TexObjects);
+}
+
+
+void
+_mesa_end_texture_lookups(struct gl_context *ctx)
+{
+ _mesa_HashUnlockMutex(ctx->Shared->TexObjects);
+}
+
+
+struct gl_texture_object *
+_mesa_lookup_texture_locked(struct gl_context *ctx, GLuint id)
+{
+ return (struct gl_texture_object *)
+ _mesa_HashLookupLocked(ctx->Shared->TexObjects, id);
+}
+
/**
* Allocate and initialize a new texture object. But don't put it into the
@@ -260,6 +281,7 @@ _mesa_copy_texture_object( struct gl_texture_object *dest,
const struct gl_texture_object *src )
{
dest->Target = src->Target;
+ dest->TargetIndex = src->TargetIndex;
dest->Name = src->Name;
dest->Priority = src->Priority;
dest->Sampler.BorderColor.f[0] = src->Sampler.BorderColor.f[0];
@@ -1092,17 +1114,20 @@ static void
unbind_texobj_from_texunits(struct gl_context *ctx,
struct gl_texture_object *texObj)
{
- GLuint u, tex;
+ const gl_texture_index index = texObj->TargetIndex;
+ GLuint u;
+
+ if (texObj->Target == 0)
+ return;
for (u = 0; u < ctx->Texture.NumCurrentTexUsed; u++) {
struct gl_texture_unit *unit = &ctx->Texture.Unit[u];
- for (tex = 0; tex < NUM_TEXTURE_TARGETS; tex++) {
- if (texObj == unit->CurrentTex[tex]) {
- _mesa_reference_texobj(&unit->CurrentTex[tex],
- ctx->Shared->DefaultTex[tex]);
- ASSERT(unit->CurrentTex[tex]);
- break;
- }
+
+ if (texObj == unit->CurrentTex[index]) {
+ /* Bind the default texture for this unit/target */
+ _mesa_reference_texobj(&unit->CurrentTex[index],
+ ctx->Shared->DefaultTex[index]);
+ unit->_BoundTextures &= ~(1 << index);
}
}
}
@@ -1126,6 +1151,28 @@ unbind_texobj_from_image_units(struct gl_context *ctx,
}
}
+/**
+ * Unbinds all textures bound to the given texture image unit.
+ */
+static void
+unbind_textures_from_unit(struct gl_context *ctx, GLuint unit)
+{
+ struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
+
+ while (texUnit->_BoundTextures) {
+ const GLuint index = ffs(texUnit->_BoundTextures) - 1;
+ struct gl_texture_object *texObj = ctx->Shared->DefaultTex[index];
+
+ _mesa_reference_texobj(&texUnit->CurrentTex[index], texObj);
+
+ /* Pass BindTexture call to device driver */
+ if (ctx->Driver.BindTexture)
+ ctx->Driver.BindTexture(ctx, unit, 0, texObj);
+
+ texUnit->_BoundTextures &= ~(1 << index);
+ ctx->NewState |= _NEW_TEXTURE;
+ }
+}
/**
* Delete named textures.
@@ -1327,6 +1374,7 @@ _mesa_BindTexture( GLenum target, GLuint texName )
mtx_unlock(&ctx->Shared->Mutex);
}
newTexObj->Target = target;
+ newTexObj->TargetIndex = targetIndex;
}
assert(valid_texture_object(newTexObj));
@@ -1357,9 +1405,118 @@ _mesa_BindTexture( GLenum target, GLuint texName )
ctx->Texture.CurrentUnit + 1);
ASSERT(texUnit->CurrentTex[targetIndex]);
+ if (texName != 0)
+ texUnit->_BoundTextures |= (1 << targetIndex);
+ else
+ texUnit->_BoundTextures &= ~(1 << targetIndex);
+
/* Pass BindTexture call to device driver */
if (ctx->Driver.BindTexture)
- ctx->Driver.BindTexture(ctx, target, newTexObj);
+ ctx->Driver.BindTexture(ctx, ctx->Texture.CurrentUnit, target, newTexObj);
+}
+
+
+void GLAPIENTRY
+_mesa_BindTextures(GLuint first, GLsizei count, const GLuint *textures)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ GLint i;
+
+ /* The ARB_multi_bind spec says:
+ *
+ * "An INVALID_OPERATION error is generated if <first> + <count>
+ * is greater than the number of texture image units supported
+ * by the implementation."
+ */
+ if (first + count > ctx->Const.MaxCombinedTextureImageUnits) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glBindTextures(first=%u + count=%d > the value of "
+ "GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS=%u)",
+ first, count, ctx->Const.MaxCombinedTextureImageUnits);
+ return;
+ }
+
+ /* Flush before changing bindings */
+ FLUSH_VERTICES(ctx, 0);
+
+ ctx->Texture.NumCurrentTexUsed = MAX2(ctx->Texture.NumCurrentTexUsed,
+ first + count);
+
+ if (textures) {
+ /* Note that the error semantics for multi-bind commands differ from
+ * those of other GL commands.
+ *
+ * The issues section in the ARB_multi_bind spec says:
+ *
+ * "(11) Typically, OpenGL specifies that if an error is generated by
+ * a command, that command has no effect. This is somewhat
+ * unfortunate for multi-bind commands, because it would require
+ * a first pass to scan the entire list of bound objects for
+ * errors and then a second pass to actually perform the
+ * bindings. Should we have different error semantics?
+ *
+ * RESOLVED: Yes. In this specification, when the parameters for
+ * one of the <count> binding points are invalid, that binding
+ * point is not updated and an error will be generated. However,
+ * other binding points in the same command will be updated if
+ * their parameters are valid and no other error occurs."
+ */
+
+ _mesa_begin_texture_lookups(ctx);
+
+ for (i = 0; i < count; i++) {
+ if (textures[i] != 0) {
+ struct gl_texture_unit *texUnit = &ctx->Texture.Unit[first + i];
+ struct gl_texture_object *current = texUnit->_Current;
+ struct gl_texture_object *texObj;
+
+ if (current && current->Name == textures[i])
+ texObj = current;
+ else
+ texObj = _mesa_lookup_texture_locked(ctx, textures[i]);
+
+ if (texObj && texObj->Target != 0) {
+ const gl_texture_index targetIndex = texObj->TargetIndex;
+
+ if (texUnit->CurrentTex[targetIndex] != texObj) {
+ /* Do the actual binding. The refcount on the previously
+ * bound texture object will be decremented. It will be
+ * deleted if the count hits zero.
+ */
+ _mesa_reference_texobj(&texUnit->CurrentTex[targetIndex],
+ texObj);
+
+ texUnit->_BoundTextures |= (1 << targetIndex);
+ ctx->NewState |= _NEW_TEXTURE;
+
+ /* Pass the BindTexture call to the device driver */
+ if (ctx->Driver.BindTexture)
+ ctx->Driver.BindTexture(ctx, first + i,
+ texObj->Target, texObj);
+ }
+ } else {
+ /* The ARB_multi_bind spec says:
+ *
+ * "An INVALID_OPERATION error is generated if any value
+ * in <textures> is not zero or the name of an existing
+ * texture object (per binding)."
+ */
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glBindTextures(textures[%d]=%u is not zero "
+ "or the name of an existing texture object)",
+ i, textures[i]);
+ }
+ } else {
+ unbind_textures_from_unit(ctx, first + i);
+ }
+ }
+
+ _mesa_end_texture_lookups(ctx);
+ } else {
+ /* Unbind all textures in the range <first> through <first>+<count>-1 */
+ for (i = 0; i < count; i++)
+ unbind_textures_from_unit(ctx, first + i);
+ }
}
diff --git a/mesalib/src/mesa/main/texobj.h b/mesalib/src/mesa/main/texobj.h
index a9de73fff..b1b7a3027 100644
--- a/mesalib/src/mesa/main/texobj.h
+++ b/mesalib/src/mesa/main/texobj.h
@@ -46,6 +46,15 @@
extern struct gl_texture_object *
_mesa_lookup_texture(struct gl_context *ctx, GLuint id);
+extern void
+_mesa_begin_texture_lookups(struct gl_context *ctx);
+
+extern void
+_mesa_end_texture_lookups(struct gl_context *ctx);
+
+extern struct gl_texture_object *
+_mesa_lookup_texture_locked(struct gl_context *ctx, GLuint id);
+
extern struct gl_texture_object *
_mesa_new_texture_object( struct gl_context *ctx, GLuint name, GLenum target );
@@ -177,6 +186,10 @@ _mesa_BindTexture( GLenum target, GLuint texture );
extern void GLAPIENTRY
+_mesa_BindTextures( GLuint first, GLsizei count, const GLuint *textures );
+
+
+extern void GLAPIENTRY
_mesa_PrioritizeTextures( GLsizei n, const GLuint *textures,
const GLclampf *priorities );
diff --git a/mesalib/src/mesa/main/texstate.c b/mesalib/src/mesa/main/texstate.c
index 91b290691..19508cf39 100644
--- a/mesalib/src/mesa/main/texstate.c
+++ b/mesalib/src/mesa/main/texstate.c
@@ -113,6 +113,7 @@ _mesa_copy_texture_state( const struct gl_context *src, struct gl_context *dst )
MAX2(dst->Texture.NumCurrentTexUsed, u + 1);
}
}
+ dst->Texture.Unit[u]._BoundTextures = src->Texture.Unit[u]._BoundTextures;
_mesa_unlock_context_textures(dst);
}
}
@@ -877,6 +878,8 @@ init_texture_unit( struct gl_context *ctx, GLuint unit )
_mesa_reference_texobj(&texUnit->CurrentTex[tex],
ctx->Shared->DefaultTex[tex]);
}
+
+ texUnit->_BoundTextures = 0;
}
diff --git a/mesalib/src/mesa/main/texstore.c b/mesalib/src/mesa/main/texstore.c
index d9096abf3..764214669 100644
--- a/mesalib/src/mesa/main/texstore.c
+++ b/mesalib/src/mesa/main/texstore.c
@@ -2473,74 +2473,71 @@ _mesa_texstore_z24_s8(TEXSTORE_PARAMS)
const GLint srcRowStride
= _mesa_image_row_stride(srcPacking, srcWidth, srcFormat, srcType);
GLint img, row;
+ GLuint *depth = malloc(srcWidth * sizeof(GLuint));
+ GLubyte *stencil = malloc(srcWidth * sizeof(GLubyte));
ASSERT(dstFormat == MESA_FORMAT_S8_UINT_Z24_UNORM);
ASSERT(srcFormat == GL_DEPTH_STENCIL_EXT ||
srcFormat == GL_DEPTH_COMPONENT ||
srcFormat == GL_STENCIL_INDEX);
- ASSERT(srcFormat != GL_DEPTH_STENCIL_EXT || srcType == GL_UNSIGNED_INT_24_8_EXT);
+ ASSERT(srcFormat != GL_DEPTH_STENCIL_EXT ||
+ srcType == GL_UNSIGNED_INT_24_8_EXT ||
+ srcType == GL_FLOAT_32_UNSIGNED_INT_24_8_REV);
- if (srcFormat == GL_DEPTH_COMPONENT ||
- srcFormat == GL_STENCIL_INDEX) {
- GLuint *depth = malloc(srcWidth * sizeof(GLuint));
- GLubyte *stencil = malloc(srcWidth * sizeof(GLubyte));
+ if (!depth || !stencil) {
+ free(depth);
+ free(stencil);
+ return GL_FALSE;
+ }
- if (!depth || !stencil) {
- free(depth);
- free(stencil);
- return GL_FALSE;
- }
+ /* In case we only upload depth we need to preserve the stencil */
+ for (img = 0; img < srcDepth; img++) {
+ GLuint *dstRow = (GLuint *) dstSlices[img];
+ const GLubyte *src
+ = (const GLubyte *) _mesa_image_address(dims, srcPacking, srcAddr,
+ srcWidth, srcHeight,
+ srcFormat, srcType,
+ img, 0, 0);
+ for (row = 0; row < srcHeight; row++) {
+ GLint i;
+ GLboolean keepdepth = GL_FALSE, keepstencil = GL_FALSE;
- /* In case we only upload depth we need to preserve the stencil */
- for (img = 0; img < srcDepth; img++) {
- GLuint *dstRow = (GLuint *) dstSlices[img];
- const GLubyte *src
- = (const GLubyte *) _mesa_image_address(dims, srcPacking, srcAddr,
- srcWidth, srcHeight,
- srcFormat, srcType,
- img, 0, 0);
- for (row = 0; row < srcHeight; row++) {
- GLint i;
- GLboolean keepdepth = GL_FALSE, keepstencil = GL_FALSE;
+ if (srcFormat == GL_DEPTH_COMPONENT) { /* preserve stencil */
+ keepstencil = GL_TRUE;
+ }
+ else if (srcFormat == GL_STENCIL_INDEX) { /* preserve depth */
+ keepdepth = GL_TRUE;
+ }
- if (srcFormat == GL_DEPTH_COMPONENT) { /* preserve stencil */
- keepstencil = GL_TRUE;
- }
- else if (srcFormat == GL_STENCIL_INDEX) { /* preserve depth */
- keepdepth = GL_TRUE;
- }
+ if (keepdepth == GL_FALSE)
+ /* the 24 depth bits will be in the low position: */
+ _mesa_unpack_depth_span(ctx, srcWidth,
+ GL_UNSIGNED_INT, /* dst type */
+ keepstencil ? depth : dstRow, /* dst addr */
+ depthScale,
+ srcType, src, srcPacking);
- if (keepdepth == GL_FALSE)
- /* the 24 depth bits will be in the low position: */
- _mesa_unpack_depth_span(ctx, srcWidth,
- GL_UNSIGNED_INT, /* dst type */
- keepstencil ? depth : dstRow, /* dst addr */
- depthScale,
- srcType, src, srcPacking);
-
- if (keepstencil == GL_FALSE)
- /* get the 8-bit stencil values */
- _mesa_unpack_stencil_span(ctx, srcWidth,
- GL_UNSIGNED_BYTE, /* dst type */
- stencil, /* dst addr */
- srcType, src, srcPacking,
- ctx->_ImageTransferState);
-
- for (i = 0; i < srcWidth; i++) {
- if (keepstencil)
- dstRow[i] = depth[i] << 8 | (dstRow[i] & 0x000000FF);
- else
- dstRow[i] = (dstRow[i] & 0xFFFFFF00) | (stencil[i] & 0xFF);
- }
+ if (keepstencil == GL_FALSE)
+ /* get the 8-bit stencil values */
+ _mesa_unpack_stencil_span(ctx, srcWidth,
+ GL_UNSIGNED_BYTE, /* dst type */
+ stencil, /* dst addr */
+ srcType, src, srcPacking,
+ ctx->_ImageTransferState);
- src += srcRowStride;
- dstRow += dstRowStride / sizeof(GLuint);
+ for (i = 0; i < srcWidth; i++) {
+ if (keepstencil)
+ dstRow[i] = depth[i] << 8 | (dstRow[i] & 0x000000FF);
+ else
+ dstRow[i] = (dstRow[i] & 0xFFFFFF00) | (stencil[i] & 0xFF);
}
+ src += srcRowStride;
+ dstRow += dstRowStride / sizeof(GLuint);
}
-
- free(depth);
- free(stencil);
}
+
+ free(depth);
+ free(stencil);
return GL_TRUE;
}
@@ -2563,7 +2560,8 @@ _mesa_texstore_s8_z24(TEXSTORE_PARAMS)
srcFormat == GL_DEPTH_COMPONENT ||
srcFormat == GL_STENCIL_INDEX);
ASSERT(srcFormat != GL_DEPTH_STENCIL_EXT ||
- srcType == GL_UNSIGNED_INT_24_8_EXT);
+ srcType == GL_UNSIGNED_INT_24_8_EXT ||
+ srcType == GL_FLOAT_32_UNSIGNED_INT_24_8_REV);
depth = malloc(srcWidth * sizeof(GLuint));
stencil = malloc(srcWidth * sizeof(GLubyte));
@@ -3417,49 +3415,47 @@ _mesa_texstore_r11_g11_b10f(TEXSTORE_PARAMS)
static GLboolean
_mesa_texstore_z32f_x24s8(TEXSTORE_PARAMS)
{
+ GLint img, row;
+ const GLint srcRowStride
+ = _mesa_image_row_stride(srcPacking, srcWidth, srcFormat, srcType)
+ / sizeof(uint64_t);
+
ASSERT(dstFormat == MESA_FORMAT_Z32_FLOAT_S8X24_UINT);
ASSERT(srcFormat == GL_DEPTH_STENCIL ||
srcFormat == GL_DEPTH_COMPONENT ||
srcFormat == GL_STENCIL_INDEX);
ASSERT(srcFormat != GL_DEPTH_STENCIL ||
+ srcType == GL_UNSIGNED_INT_24_8 ||
srcType == GL_FLOAT_32_UNSIGNED_INT_24_8_REV);
- if (srcFormat == GL_DEPTH_COMPONENT ||
- srcFormat == GL_STENCIL_INDEX) {
- GLint img, row;
- const GLint srcRowStride
- = _mesa_image_row_stride(srcPacking, srcWidth, srcFormat, srcType)
- / sizeof(uint64_t);
+ /* In case we only upload depth we need to preserve the stencil */
+ for (img = 0; img < srcDepth; img++) {
+ uint64_t *dstRow = (uint64_t *) dstSlices[img];
+ const uint64_t *src
+ = (const uint64_t *) _mesa_image_address(dims, srcPacking, srcAddr,
+ srcWidth, srcHeight,
+ srcFormat, srcType,
+ img, 0, 0);
+ for (row = 0; row < srcHeight; row++) {
+ /* The unpack functions with:
+ * dstType = GL_FLOAT_32_UNSIGNED_INT_24_8_REV
+ * only write their own dword, so the other dword (stencil
+ * or depth) is preserved. */
+ if (srcFormat != GL_STENCIL_INDEX)
+ _mesa_unpack_depth_span(ctx, srcWidth,
+ GL_FLOAT_32_UNSIGNED_INT_24_8_REV, /* dst type */
+ dstRow, /* dst addr */
+ ~0U, srcType, src, srcPacking);
- /* In case we only upload depth we need to preserve the stencil */
- for (img = 0; img < srcDepth; img++) {
- uint64_t *dstRow = (uint64_t *) dstSlices[img];
- const uint64_t *src
- = (const uint64_t *) _mesa_image_address(dims, srcPacking, srcAddr,
- srcWidth, srcHeight,
- srcFormat, srcType,
- img, 0, 0);
- for (row = 0; row < srcHeight; row++) {
- /* The unpack functions with:
- * dstType = GL_FLOAT_32_UNSIGNED_INT_24_8_REV
- * only write their own dword, so the other dword (stencil
- * or depth) is preserved. */
- if (srcFormat != GL_STENCIL_INDEX)
- _mesa_unpack_depth_span(ctx, srcWidth,
- GL_FLOAT_32_UNSIGNED_INT_24_8_REV, /* dst type */
- dstRow, /* dst addr */
- ~0U, srcType, src, srcPacking);
-
- if (srcFormat != GL_DEPTH_COMPONENT)
- _mesa_unpack_stencil_span(ctx, srcWidth,
- GL_FLOAT_32_UNSIGNED_INT_24_8_REV, /* dst type */
- dstRow, /* dst addr */
- srcType, src, srcPacking,
- ctx->_ImageTransferState);
+ if (srcFormat != GL_DEPTH_COMPONENT)
+ _mesa_unpack_stencil_span(ctx, srcWidth,
+ GL_FLOAT_32_UNSIGNED_INT_24_8_REV, /* dst type */
+ dstRow, /* dst addr */
+ srcType, src, srcPacking,
+ ctx->_ImageTransferState);
- src += srcRowStride;
- dstRow += dstRowStride / sizeof(uint64_t);
- }
+ src += srcRowStride;
+ dstRow += dstRowStride / sizeof(uint64_t);
}
}
return GL_TRUE;
diff --git a/mesalib/src/mesa/main/transformfeedback.c b/mesalib/src/mesa/main/transformfeedback.c
index abeb25e87..a73746335 100644
--- a/mesalib/src/mesa/main/transformfeedback.c
+++ b/mesalib/src/mesa/main/transformfeedback.c
@@ -32,7 +32,6 @@
#include "buffers.h"
-#include "bufferobj.h"
#include "context.h"
#include "hash.h"
#include "macros.h"
@@ -533,14 +532,7 @@ bind_buffer_range(struct gl_context *ctx, GLuint index,
bufObj);
/* The per-attribute binding point */
- _mesa_reference_buffer_object(ctx,
- &obj->Buffers[index],
- bufObj);
-
- obj->BufferNames[index] = bufObj->Name;
-
- obj->Offset[index] = offset;
- obj->RequestedSize[index] = size;
+ _mesa_set_transform_feedback_binding(ctx, obj, index, bufObj, offset, size);
}
diff --git a/mesalib/src/mesa/main/transformfeedback.h b/mesalib/src/mesa/main/transformfeedback.h
index 7aecd66a7..87f4080e0 100644
--- a/mesalib/src/mesa/main/transformfeedback.h
+++ b/mesalib/src/mesa/main/transformfeedback.h
@@ -27,6 +27,7 @@
#define TRANSFORM_FEEDBACK_H
#include <stdbool.h>
+#include "bufferobj.h"
#include "compiler.h"
#include "glheader.h"
#include "mtypes.h"
@@ -127,4 +128,17 @@ extern bool
_mesa_transform_feedback_is_using_program(struct gl_context *ctx,
struct gl_shader_program *shProg);
+static inline void
+_mesa_set_transform_feedback_binding(struct gl_context *ctx,
+ struct gl_transform_feedback_object *tfObj, GLuint index,
+ struct gl_buffer_object *bufObj,
+ GLintptr offset, GLsizeiptr size)
+{
+ _mesa_reference_buffer_object(ctx, &tfObj->Buffers[index], bufObj);
+
+ tfObj->BufferNames[index] = bufObj->Name;
+ tfObj->Offset[index] = offset;
+ tfObj->RequestedSize[index] = size;
+}
+
#endif /* TRANSFORM_FEEDBACK_H */
diff --git a/mesalib/src/mesa/main/uniforms.h b/mesalib/src/mesa/main/uniforms.h
index c8b555cbe..10518dcbb 100644
--- a/mesalib/src/mesa/main/uniforms.h
+++ b/mesalib/src/mesa/main/uniforms.h
@@ -319,7 +319,7 @@ struct gl_builtin_uniform_element {
struct gl_builtin_uniform_desc {
const char *name;
- struct gl_builtin_uniform_element *elements;
+ const struct gl_builtin_uniform_element *elements;
unsigned int num_elements;
};
diff --git a/mesalib/src/mesa/main/varray.c b/mesalib/src/mesa/main/varray.c
index 66a3ef119..46956efb5 100644
--- a/mesalib/src/mesa/main/varray.c
+++ b/mesalib/src/mesa/main/varray.c
@@ -784,13 +784,7 @@ static const GLfloat *
get_current_attrib(struct gl_context *ctx, GLuint index, const char *function)
{
if (index == 0) {
- /* In OpenGL 3.1 attribute 0 becomes non-magic, just like in OpenGL ES
- * 2.0. Note that we cannot just check for API_OPENGL_CORE here because
- * that will erroneously allow this usage in a 3.0 forward-compatible
- * context too.
- */
- if ((ctx->API != API_OPENGL_CORE || ctx->Version < 31)
- && ctx->API != API_OPENGLES2) {
+ if (_mesa_attr_zero_aliases_vertex(ctx)) {
_mesa_error(ctx, GL_INVALID_OPERATION, "%s(index==0)", function);
return NULL;
}
@@ -1446,6 +1440,126 @@ _mesa_BindVertexBuffer(GLuint bindingIndex, GLuint buffer, GLintptr offset,
void GLAPIENTRY
+_mesa_BindVertexBuffers(GLuint first, GLsizei count, const GLuint *buffers,
+ const GLintptr *offsets, const GLsizei *strides)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct gl_vertex_array_object * const vao = ctx->Array.VAO;
+ GLuint i;
+
+ ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+ /* The ARB_vertex_attrib_binding spec says:
+ *
+ * "An INVALID_OPERATION error is generated if no
+ * vertex array object is bound."
+ */
+ if (ctx->API == API_OPENGL_CORE &&
+ ctx->Array.VAO == ctx->Array.DefaultVAO) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glBindVertexBuffers(No array object bound)");
+ return;
+ }
+
+ /* The ARB_multi_bind spec says:
+ *
+ * "An INVALID_OPERATION error is generated if <first> + <count>
+ * is greater than the value of MAX_VERTEX_ATTRIB_BINDINGS."
+ */
+ if (first + count > ctx->Const.MaxVertexAttribBindings) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glBindVertexBuffers(first=%u + count=%d > the value of "
+ "GL_MAX_VERTEX_ATTRIB_BINDINGS=%u)",
+ first, count, ctx->Const.MaxVertexAttribBindings);
+ return;
+ }
+
+ if (!buffers) {
+ /**
+ * The ARB_multi_bind spec says:
+ *
+ * "If <buffers> is NULL, each affected vertex buffer binding point
+ * from <first> through <first>+<count>-1 will be reset to have no
+ * bound buffer object. In this case, the offsets and strides
+ * associated with the binding points are set to default values,
+ * ignoring <offsets> and <strides>."
+ */
+ struct gl_buffer_object *vbo = ctx->Shared->NullBufferObj;
+
+ for (i = 0; i < count; i++)
+ bind_vertex_buffer(ctx, VERT_ATTRIB_GENERIC(first + i), vbo, 0, 16);
+
+ return;
+ }
+
+ /* Note that the error semantics for multi-bind commands differ from
+ * those of other GL commands.
+ *
+ * The Issues section in the ARB_multi_bind spec says:
+ *
+ * "(11) Typically, OpenGL specifies that if an error is generated by
+ * a command, that command has no effect. This is somewhat
+ * unfortunate for multi-bind commands, because it would require
+ * a first pass to scan the entire list of bound objects for
+ * errors and then a second pass to actually perform the
+ * bindings. Should we have different error semantics?
+ *
+ * RESOLVED: Yes. In this specification, when the parameters for
+ * one of the <count> binding points are invalid, that binding
+ * point is not updated and an error will be generated. However,
+ * other binding points in the same command will be updated if
+ * their parameters are valid and no other error occurs."
+ */
+
+ _mesa_begin_bufferobj_lookups(ctx);
+
+ for (i = 0; i < count; i++) {
+ struct gl_buffer_object *vbo;
+
+ /* The ARB_multi_bind spec says:
+ *
+ * "An INVALID_VALUE error is generated if any value in
+ * <offsets> or <strides> is negative (per binding)."
+ */
+ if (offsets[i] < 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glBindVertexBuffer(offsets[%u]=%lldd < 0)",
+ i, (long long int) offsets[i]);
+ continue;
+ }
+
+ if (strides[i] < 0) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glBindVertexBuffer(strides[%u]=%lld < 0)",
+ i, (long long int) strides[i]);
+ continue;
+ }
+
+ if (buffers[i]) {
+ struct gl_vertex_buffer_binding *binding =
+ &vao->VertexBinding[VERT_ATTRIB_GENERIC(first + i)];
+
+ if (buffers[i] == binding->BufferObj->Name)
+ vbo = binding->BufferObj;
+ else
+ vbo = _mesa_multi_bind_lookup_bufferobj(ctx, buffers, i,
+ "glBindVertexBuffers");
+
+ if (!vbo)
+ continue;
+ } else {
+ vbo = ctx->Shared->NullBufferObj;
+ }
+
+ bind_vertex_buffer(ctx, VERT_ATTRIB_GENERIC(first + i), vbo,
+ offsets[i], strides[i]);
+ }
+
+ _mesa_end_bufferobj_lookups(ctx);
+}
+
+
+void GLAPIENTRY
_mesa_VertexAttribFormat(GLuint attribIndex, GLint size, GLenum type,
GLboolean normalized, GLuint relativeOffset)
{
diff --git a/mesalib/src/mesa/main/varray.h b/mesalib/src/mesa/main/varray.h
index bc820ed23..f94ebac99 100644
--- a/mesalib/src/mesa/main/varray.h
+++ b/mesalib/src/mesa/main/varray.h
@@ -106,6 +106,22 @@ _mesa_update_client_array(struct gl_context *ctx,
_mesa_reference_buffer_object(ctx, &dst->BufferObj, binding->BufferObj);
}
+static inline bool
+_mesa_attr_zero_aliases_vertex(struct gl_context *ctx)
+{
+ const bool is_forward_compatible_context =
+ ctx->Const.ContextFlags & GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT;
+
+ /* In OpenGL 3.1 attribute 0 becomes non-magic, just like in OpenGL ES
+ * 2.0. Note that we cannot just check for API_OPENGL_COMPAT here because
+ * that will erroneously allow this usage in a 3.0 forward-compatible
+ * context too.
+ */
+ return (ctx->API == API_OPENGLES
+ || (ctx->API == API_OPENGL_COMPAT
+ && !is_forward_compatible_context));
+}
+
extern void GLAPIENTRY
_mesa_VertexPointer(GLint size, GLenum type, GLsizei stride,
const GLvoid *ptr);
@@ -291,6 +307,10 @@ _mesa_BindVertexBuffer(GLuint bindingIndex, GLuint buffer, GLintptr offset,
GLsizei stride);
extern void GLAPIENTRY
+_mesa_BindVertexBuffers(GLuint first, GLsizei count, const GLuint *buffers,
+ const GLintptr *offsets, const GLsizei *strides);
+
+extern void GLAPIENTRY
_mesa_VertexAttribFormat(GLuint attribIndex, GLint size, GLenum type,
GLboolean normalized, GLuint relativeOffset);
diff --git a/mesalib/src/mesa/state_tracker/st_atom_texture.c b/mesalib/src/mesa/state_tracker/st_atom_texture.c
index afc6d9dab..928a4ffd2 100644
--- a/mesalib/src/mesa/state_tracker/st_atom_texture.c
+++ b/mesalib/src/mesa/state_tracker/st_atom_texture.c
@@ -271,6 +271,10 @@ st_get_texture_sampler_view_from_stobj(struct st_context *st,
sv = st_texture_get_sampler_view(st, stObj);
+ if (stObj->base.StencilSampling &&
+ util_format_is_depth_and_stencil(format))
+ format = util_format_stencil_only(format);
+
/* if sampler view has changed dereference it */
if (*sv) {
if (check_sampler_swizzle(stObj, *sv) ||
diff --git a/mesalib/src/mesa/state_tracker/st_extensions.c b/mesalib/src/mesa/state_tracker/st_extensions.c
index a245fdf18..12ba82df3 100644
--- a/mesalib/src/mesa/state_tracker/st_extensions.c
+++ b/mesalib/src/mesa/state_tracker/st_extensions.c
@@ -507,6 +507,11 @@ void st_init_extensions(struct st_context *st)
{ { o(OES_compressed_ETC1_RGB8_texture) },
{ PIPE_FORMAT_ETC1_RGB8 } },
+
+ { { o(ARB_stencil_texturing) },
+ { PIPE_FORMAT_X24S8_UINT,
+ PIPE_FORMAT_S8X24_UINT },
+ GL_TRUE }, /* at least one format must be supported */
};
/* Required: vertex fetch support. */
@@ -560,13 +565,6 @@ void st_init_extensions(struct st_context *st)
ctx->Extensions.EXT_point_parameters = GL_TRUE;
ctx->Extensions.EXT_provoking_vertex = GL_TRUE;
- /* IMPORTANT:
- * Don't enable EXT_separate_shader_objects. It disallows a certain
- * optimization in the GLSL compiler and therefore is considered
- * harmful.
- */
- ctx->Extensions.EXT_separate_shader_objects = GL_FALSE;
-
ctx->Extensions.EXT_texture_env_dot3 = GL_TRUE;
ctx->Extensions.EXT_vertex_array_bgra = GL_TRUE;
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 d1c3856b5..6eb6c8a97 100644
--- a/mesalib/src/mesa/state_tracker/st_glsl_to_tgsi.cpp
+++ b/mesalib/src/mesa/state_tracker/st_glsl_to_tgsi.cpp
@@ -5396,6 +5396,8 @@ st_link_shader(struct gl_context *ctx, struct gl_shader_program *prog)
EXP_TO_EXP2 |
LOG_TO_LOG2 |
LDEXP_TO_ARITH |
+ CARRY_TO_ARITH |
+ BORROW_TO_ARITH |
(options->EmitNoPow ? POW_TO_EXP2 : 0) |
(!ctx->Const.NativeIntegers ? INT_DIV_TO_MUL_RCP : 0));
diff --git a/mesalib/src/mesa/tnl/t_vertex.c b/mesalib/src/mesa/tnl/t_vertex.c
index b3deac024..421bae2b8 100644
--- a/mesalib/src/mesa/tnl/t_vertex.c
+++ b/mesalib/src/mesa/tnl/t_vertex.c
@@ -83,12 +83,22 @@ void _tnl_register_fastpath( struct tnl_clipspace *vtx,
struct tnl_clipspace_fastpath *fastpath = CALLOC_STRUCT(tnl_clipspace_fastpath);
GLuint i;
+ if (fastpath == NULL) {
+ _mesa_error_no_memory(__func__);
+ return;
+ }
+
fastpath->vertex_size = vtx->vertex_size;
fastpath->attr_count = vtx->attr_count;
fastpath->match_strides = match_strides;
fastpath->func = vtx->emit;
- fastpath->attr =
- malloc(vtx->attr_count * sizeof(fastpath->attr[0]));
+ fastpath->attr = malloc(vtx->attr_count * sizeof(fastpath->attr[0]));
+
+ if (fastpath->attr == NULL) {
+ free(fastpath);
+ _mesa_error_no_memory(__func__);
+ return;
+ }
for (i = 0; i < vtx->attr_count; i++) {
fastpath->attr[i].format = vtx->attr[i].format;
diff --git a/mesalib/src/mesa/vbo/vbo_attrib_tmp.h b/mesalib/src/mesa/vbo/vbo_attrib_tmp.h
index a2ea6d0c8..ec66934fc 100644
--- a/mesalib/src/mesa/vbo/vbo_attrib_tmp.h
+++ b/mesalib/src/mesa/vbo/vbo_attrib_tmp.h
@@ -26,6 +26,7 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
**************************************************************************/
#include "util/u_format_r11g11b10f.h"
+#include "main/varray.h"
/* float */
#define ATTR1FV( A, V ) ATTR( A, 1, GL_FLOAT, (V)[0], 0, 0, 1 )
@@ -499,7 +500,7 @@ static void GLAPIENTRY
TAG(VertexAttrib1fARB)(GLuint index, GLfloat x)
{
GET_CURRENT_CONTEXT(ctx);
- if (index == 0)
+ if (index == 0 && _mesa_attr_zero_aliases_vertex(ctx))
ATTR1F(0, x);
else if (index < MAX_VERTEX_GENERIC_ATTRIBS)
ATTR1F(VBO_ATTRIB_GENERIC0 + index, x);
@@ -511,7 +512,7 @@ static void GLAPIENTRY
TAG(VertexAttrib1fvARB)(GLuint index, const GLfloat * v)
{
GET_CURRENT_CONTEXT(ctx);
- if (index == 0)
+ if (index == 0 && _mesa_attr_zero_aliases_vertex(ctx))
ATTR1FV(0, v);
else if (index < MAX_VERTEX_GENERIC_ATTRIBS)
ATTR1FV(VBO_ATTRIB_GENERIC0 + index, v);
@@ -523,7 +524,7 @@ static void GLAPIENTRY
TAG(VertexAttrib2fARB)(GLuint index, GLfloat x, GLfloat y)
{
GET_CURRENT_CONTEXT(ctx);
- if (index == 0)
+ if (index == 0 && _mesa_attr_zero_aliases_vertex(ctx))
ATTR2F(0, x, y);
else if (index < MAX_VERTEX_GENERIC_ATTRIBS)
ATTR2F(VBO_ATTRIB_GENERIC0 + index, x, y);
@@ -535,7 +536,7 @@ static void GLAPIENTRY
TAG(VertexAttrib2fvARB)(GLuint index, const GLfloat * v)
{
GET_CURRENT_CONTEXT(ctx);
- if (index == 0)
+ if (index == 0 && _mesa_attr_zero_aliases_vertex(ctx))
ATTR2FV(0, v);
else if (index < MAX_VERTEX_GENERIC_ATTRIBS)
ATTR2FV(VBO_ATTRIB_GENERIC0 + index, v);
@@ -547,7 +548,7 @@ static void GLAPIENTRY
TAG(VertexAttrib3fARB)(GLuint index, GLfloat x, GLfloat y, GLfloat z)
{
GET_CURRENT_CONTEXT(ctx);
- if (index == 0)
+ if (index == 0 && _mesa_attr_zero_aliases_vertex(ctx))
ATTR3F(0, x, y, z);
else if (index < MAX_VERTEX_GENERIC_ATTRIBS)
ATTR3F(VBO_ATTRIB_GENERIC0 + index, x, y, z);
@@ -559,7 +560,7 @@ static void GLAPIENTRY
TAG(VertexAttrib3fvARB)(GLuint index, const GLfloat * v)
{
GET_CURRENT_CONTEXT(ctx);
- if (index == 0)
+ if (index == 0 && _mesa_attr_zero_aliases_vertex(ctx))
ATTR3FV(0, v);
else if (index < MAX_VERTEX_GENERIC_ATTRIBS)
ATTR3FV(VBO_ATTRIB_GENERIC0 + index, v);
@@ -571,7 +572,7 @@ static void GLAPIENTRY
TAG(VertexAttrib4fARB)(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
{
GET_CURRENT_CONTEXT(ctx);
- if (index == 0)
+ if (index == 0 && _mesa_attr_zero_aliases_vertex(ctx))
ATTR4F(0, x, y, z, w);
else if (index < MAX_VERTEX_GENERIC_ATTRIBS)
ATTR4F(VBO_ATTRIB_GENERIC0 + index, x, y, z, w);
@@ -583,7 +584,7 @@ static void GLAPIENTRY
TAG(VertexAttrib4fvARB)(GLuint index, const GLfloat * v)
{
GET_CURRENT_CONTEXT(ctx);
- if (index == 0)
+ if (index == 0 && _mesa_attr_zero_aliases_vertex(ctx))
ATTR4FV(0, v);
else if (index < MAX_VERTEX_GENERIC_ATTRIBS)
ATTR4FV(VBO_ATTRIB_GENERIC0 + index, v);
@@ -600,7 +601,7 @@ static void GLAPIENTRY
TAG(VertexAttribI1i)(GLuint index, GLint x)
{
GET_CURRENT_CONTEXT(ctx);
- if (index == 0)
+ if (index == 0 && _mesa_attr_zero_aliases_vertex(ctx))
ATTR1I(0, x);
else if (index < MAX_VERTEX_GENERIC_ATTRIBS)
ATTR1I(VBO_ATTRIB_GENERIC0 + index, x);
@@ -612,7 +613,7 @@ static void GLAPIENTRY
TAG(VertexAttribI2i)(GLuint index, GLint x, GLint y)
{
GET_CURRENT_CONTEXT(ctx);
- if (index == 0)
+ if (index == 0 && _mesa_attr_zero_aliases_vertex(ctx))
ATTR2I(0, x, y);
else if (index < MAX_VERTEX_GENERIC_ATTRIBS)
ATTR2I(VBO_ATTRIB_GENERIC0 + index, x, y);
@@ -624,7 +625,7 @@ static void GLAPIENTRY
TAG(VertexAttribI3i)(GLuint index, GLint x, GLint y, GLint z)
{
GET_CURRENT_CONTEXT(ctx);
- if (index == 0)
+ if (index == 0 && _mesa_attr_zero_aliases_vertex(ctx))
ATTR3I(0, x, y, z);
else if (index < MAX_VERTEX_GENERIC_ATTRIBS)
ATTR3I(VBO_ATTRIB_GENERIC0 + index, x, y, z);
@@ -636,7 +637,7 @@ static void GLAPIENTRY
TAG(VertexAttribI4i)(GLuint index, GLint x, GLint y, GLint z, GLint w)
{
GET_CURRENT_CONTEXT(ctx);
- if (index == 0)
+ if (index == 0 && _mesa_attr_zero_aliases_vertex(ctx))
ATTR4I(0, x, y, z, w);
else if (index < MAX_VERTEX_GENERIC_ATTRIBS)
ATTR4I(VBO_ATTRIB_GENERIC0 + index, x, y, z, w);
@@ -648,7 +649,7 @@ static void GLAPIENTRY
TAG(VertexAttribI2iv)(GLuint index, const GLint *v)
{
GET_CURRENT_CONTEXT(ctx);
- if (index == 0)
+ if (index == 0 && _mesa_attr_zero_aliases_vertex(ctx))
ATTR2IV(0, v);
else if (index < MAX_VERTEX_GENERIC_ATTRIBS)
ATTR2IV(VBO_ATTRIB_GENERIC0 + index, v);
@@ -660,7 +661,7 @@ static void GLAPIENTRY
TAG(VertexAttribI3iv)(GLuint index, const GLint *v)
{
GET_CURRENT_CONTEXT(ctx);
- if (index == 0)
+ if (index == 0 && _mesa_attr_zero_aliases_vertex(ctx))
ATTR3IV(0, v);
else if (index < MAX_VERTEX_GENERIC_ATTRIBS)
ATTR3IV(VBO_ATTRIB_GENERIC0 + index, v);
@@ -672,7 +673,7 @@ static void GLAPIENTRY
TAG(VertexAttribI4iv)(GLuint index, const GLint *v)
{
GET_CURRENT_CONTEXT(ctx);
- if (index == 0)
+ if (index == 0 && _mesa_attr_zero_aliases_vertex(ctx))
ATTR4IV(0, v);
else if (index < MAX_VERTEX_GENERIC_ATTRIBS)
ATTR4IV(VBO_ATTRIB_GENERIC0 + index, v);
@@ -689,7 +690,7 @@ static void GLAPIENTRY
TAG(VertexAttribI1ui)(GLuint index, GLuint x)
{
GET_CURRENT_CONTEXT(ctx);
- if (index == 0)
+ if (index == 0 && _mesa_attr_zero_aliases_vertex(ctx))
ATTR1UI(0, x);
else if (index < MAX_VERTEX_GENERIC_ATTRIBS)
ATTR1UI(VBO_ATTRIB_GENERIC0 + index, x);
@@ -701,7 +702,7 @@ static void GLAPIENTRY
TAG(VertexAttribI2ui)(GLuint index, GLuint x, GLuint y)
{
GET_CURRENT_CONTEXT(ctx);
- if (index == 0)
+ if (index == 0 && _mesa_attr_zero_aliases_vertex(ctx))
ATTR2UI(0, x, y);
else if (index < MAX_VERTEX_GENERIC_ATTRIBS)
ATTR2UI(VBO_ATTRIB_GENERIC0 + index, x, y);
@@ -713,7 +714,7 @@ static void GLAPIENTRY
TAG(VertexAttribI3ui)(GLuint index, GLuint x, GLuint y, GLuint z)
{
GET_CURRENT_CONTEXT(ctx);
- if (index == 0)
+ if (index == 0 && _mesa_attr_zero_aliases_vertex(ctx))
ATTR3UI(0, x, y, z);
else if (index < MAX_VERTEX_GENERIC_ATTRIBS)
ATTR3UI(VBO_ATTRIB_GENERIC0 + index, x, y, z);
@@ -725,7 +726,7 @@ static void GLAPIENTRY
TAG(VertexAttribI4ui)(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w)
{
GET_CURRENT_CONTEXT(ctx);
- if (index == 0)
+ if (index == 0 && _mesa_attr_zero_aliases_vertex(ctx))
ATTR4UI(0, x, y, z, w);
else if (index < MAX_VERTEX_GENERIC_ATTRIBS)
ATTR4UI(VBO_ATTRIB_GENERIC0 + index, x, y, z, w);
@@ -737,7 +738,7 @@ static void GLAPIENTRY
TAG(VertexAttribI2uiv)(GLuint index, const GLuint *v)
{
GET_CURRENT_CONTEXT(ctx);
- if (index == 0)
+ if (index == 0 && _mesa_attr_zero_aliases_vertex(ctx))
ATTR2UIV(0, v);
else if (index < MAX_VERTEX_GENERIC_ATTRIBS)
ATTR2UIV(VBO_ATTRIB_GENERIC0 + index, v);
@@ -749,7 +750,7 @@ static void GLAPIENTRY
TAG(VertexAttribI3uiv)(GLuint index, const GLuint *v)
{
GET_CURRENT_CONTEXT(ctx);
- if (index == 0)
+ if (index == 0 && _mesa_attr_zero_aliases_vertex(ctx))
ATTR3UIV(0, v);
else if (index < MAX_VERTEX_GENERIC_ATTRIBS)
ATTR3UIV(VBO_ATTRIB_GENERIC0 + index, v);
@@ -761,7 +762,7 @@ static void GLAPIENTRY
TAG(VertexAttribI4uiv)(GLuint index, const GLuint *v)
{
GET_CURRENT_CONTEXT(ctx);
- if (index == 0)
+ if (index == 0 && _mesa_attr_zero_aliases_vertex(ctx))
ATTR4UIV(0, v);
else if (index < MAX_VERTEX_GENERIC_ATTRIBS)
ATTR4UIV(VBO_ATTRIB_GENERIC0 + index, v);
diff --git a/mesalib/src/mesa/vbo/vbo_rebase.c b/mesalib/src/mesa/vbo/vbo_rebase.c
index f3fe5f757..82a0b8e2b 100644
--- a/mesalib/src/mesa/vbo/vbo_rebase.c
+++ b/mesalib/src/mesa/vbo/vbo_rebase.c
@@ -58,9 +58,14 @@ static void *rebase_##TYPE( const void *ptr, \
GLuint count, \
TYPE min_index ) \
{ \
- const TYPE *in = (TYPE *)ptr; \
- TYPE *tmp_indices = malloc(count * sizeof(TYPE)); \
GLuint i; \
+ const TYPE *in = (TYPE *)ptr; \
+ TYPE *tmp_indices = malloc(count * sizeof(TYPE)); \
+ \
+ if (tmp_indices == NULL) { \
+ _mesa_error_no_memory(__func__); \
+ return NULL; \
+ } \
\
for (i = 0; i < count; i++) \
tmp_indices[i] = in[i] - min_index; \
@@ -148,6 +153,11 @@ void vbo_rebase_prims( struct gl_context *ctx,
*/
tmp_prims = malloc(sizeof(*prim) * nr_prims);
+ if (tmp_prims == NULL) {
+ _mesa_error_no_memory(__func__);
+ return;
+ }
+
for (i = 0; i < nr_prims; i++) {
tmp_prims[i] = prim[i];
tmp_prims[i].basevertex -= min_index;
@@ -186,6 +196,10 @@ void vbo_rebase_prims( struct gl_context *ctx,
if (map_ib)
ctx->Driver.UnmapBuffer(ctx, ib->obj, MAP_INTERNAL);
+ if (tmp_indices == NULL) {
+ return;
+ }
+
tmp_ib.obj = ctx->Shared->NullBufferObj;
tmp_ib.ptr = tmp_indices;
tmp_ib.count = ib->count;
@@ -198,6 +212,11 @@ void vbo_rebase_prims( struct gl_context *ctx,
*/
tmp_prims = malloc(sizeof(*prim) * nr_prims);
+ if (tmp_prims == NULL) {
+ _mesa_error_no_memory(__func__);
+ return;
+ }
+
for (i = 0; i < nr_prims; i++) {
/* If this fails, it could indicate an application error:
*/