diff options
author | marha <marha@users.sourceforge.net> | 2014-05-08 00:18:25 +0200 |
---|---|---|
committer | marha <marha@users.sourceforge.net> | 2014-05-08 00:18:25 +0200 |
commit | 683155917770af9e63a938bc450df25d1904d567 (patch) | |
tree | 5eb9d2d0bba27ed4e8afe58c195d1918282c343b /mesalib/src | |
parent | ea0cd87ecbe9fc3c5503ccad7f87a895a458d6d4 (diff) | |
download | vcxsrv-683155917770af9e63a938bc450df25d1904d567.tar.gz vcxsrv-683155917770af9e63a938bc450df25d1904d567.tar.bz2 vcxsrv-683155917770af9e63a938bc450df25d1904d567.zip |
xserver xcb-proto mesa pixman xkeyboard-config git update 7 May 2014
xserver commit a5b9757142a2ab471ca26651dce9cc5f5e351f3d
libxcb commit d978a4f69b30b630f28d07f1003cf290284d24d8
libxcb/xcb-proto commit 389889e2f95af19e7fc7ac89e7faeb2f28652415
xkeyboard-config commit 3e54f31b1f118f00c240f59d72d7ddb685c6db79
libX11 commit 8be4610939b833587954957f5963eb4191b43d19
libXdmcp commit 089081dca4ba3598c6f9bf401c029378943b5854
libXext commit 11aad96bd689d54156064d2e81213dc827a689d1
libfontenc commit 0037a42107b952c9d903719615747e760e4e7247
libXinerama commit edd95182b26eb5d576d4878c559e0f17dddaa909
libXau commit 1e4635be11154dd8262f37b379511bd627defa2a
xkbcomp commit d4e02a09258063c6d024c3ccd42d6b22212e6e18
pixman commit 91f32ce961bc85f98b3372b95681ad8918d24b18
xextproto commit 66afec3f49e8eb0d4c2e9af7088fc3116d4bafd7
randrproto commit a4a6694c059d74247c16527eef4a0ec9f56bbef6
glproto commit f84853d97d5749308992412a215fa518b6536eb3
mkfontscale commit 399db42a151687f1181ae23d28a76d31125a2853
xwininfo commit ba0d1b0da21d2dbdd81098ed5778f3792b472e13
libXft commit 4acfdaf95adb0a05c2a25550bdde036c865902f4
libXmu commit 22d9c590901e121936f50dee97dc60c4f7defb63
libxtrans commit a57a7f62242e1ea972b81414741729bf3dbae0a4
fontconfig commit 81664fe54f117e4781fda5a30429b51858302e91
mesa commit 9ced3fc649ec04710a5f5c855bfb582b898cff83
Diffstat (limited to 'mesalib/src')
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: */ |