diff options
Diffstat (limited to 'mesalib/src')
135 files changed, 5744 insertions, 1708 deletions
diff --git a/mesalib/src/gallium/auxiliary/Makefile.sources b/mesalib/src/gallium/auxiliary/Makefile.sources index ec7547cad..62e6b94ca 100644 --- a/mesalib/src/gallium/auxiliary/Makefile.sources +++ b/mesalib/src/gallium/auxiliary/Makefile.sources @@ -197,7 +197,6 @@ C_SOURCES := \ util/u_dirty_surfaces.h \ util/u_dl.c \ util/u_dl.h \ - util/u_double_list.h \ util/u_draw.c \ util/u_draw.h \ util/u_draw_quad.c \ diff --git a/mesalib/src/gallium/auxiliary/hud/hud_driver_query.c b/mesalib/src/gallium/auxiliary/hud/hud_driver_query.c index 53771fcae..603aba7e8 100644 --- a/mesalib/src/gallium/auxiliary/hud/hud_driver_query.c +++ b/mesalib/src/gallium/auxiliary/hud/hud_driver_query.c @@ -187,6 +187,7 @@ hud_driver_query_install(struct hud_pane *pane, struct pipe_context *pipe, struct pipe_screen *screen = pipe->screen; struct pipe_driver_query_info query; unsigned num_queries, i; + boolean uses_byte_units; boolean found = FALSE; if (!screen->get_driver_query_info) @@ -205,7 +206,9 @@ hud_driver_query_install(struct hud_pane *pane, struct pipe_context *pipe, if (!found) return FALSE; + uses_byte_units = query.type == PIPE_DRIVER_QUERY_TYPE_BYTES; hud_pipe_query_install(pane, pipe, query.name, query.query_type, 0, - query.max_value, query.uses_byte_units); + query.max_value.u64, uses_byte_units); + return TRUE; } diff --git a/mesalib/src/gallium/auxiliary/hud/hud_private.h b/mesalib/src/gallium/auxiliary/hud/hud_private.h index 230f02664..632926b87 100644 --- a/mesalib/src/gallium/auxiliary/hud/hud_private.h +++ b/mesalib/src/gallium/auxiliary/hud/hud_private.h @@ -29,7 +29,7 @@ #define HUD_PRIVATE_H #include "pipe/p_context.h" -#include "util/u_double_list.h" +#include "util/list.h" struct hud_graph { /* initialized by common code */ diff --git a/mesalib/src/gallium/auxiliary/util/u_blitter.c b/mesalib/src/gallium/auxiliary/util/u_blitter.c index 9d087fe8a..24a5b93e1 100644 --- a/mesalib/src/gallium/auxiliary/util/u_blitter.c +++ b/mesalib/src/gallium/auxiliary/util/u_blitter.c @@ -1306,6 +1306,7 @@ void util_blitter_default_src_texture(struct pipe_sampler_view *src_templ, unsigned srclevel) { memset(src_templ, 0, sizeof(*src_templ)); + src_templ->target = src->target; src_templ->format = util_format_linear(src->format); src_templ->u.tex.first_level = srclevel; src_templ->u.tex.last_level = srclevel; diff --git a/mesalib/src/gallium/auxiliary/util/u_debug_flush.c b/mesalib/src/gallium/auxiliary/util/u_debug_flush.c index cdefca2fb..52e72cd6d 100644 --- a/mesalib/src/gallium/auxiliary/util/u_debug_flush.c +++ b/mesalib/src/gallium/auxiliary/util/u_debug_flush.c @@ -44,7 +44,7 @@ #include "util/u_memory.h" #include "util/u_debug_flush.h" #include "util/u_hash_table.h" -#include "util/u_double_list.h" +#include "util/list.h" #include "util/u_inlines.h" #include "util/u_string.h" #include "os/os_thread.h" diff --git a/mesalib/src/gallium/auxiliary/util/u_debug_memory.c b/mesalib/src/gallium/auxiliary/util/u_debug_memory.c index 1ad0e7220..747837cd1 100644 --- a/mesalib/src/gallium/auxiliary/util/u_debug_memory.c +++ b/mesalib/src/gallium/auxiliary/util/u_debug_memory.c @@ -42,7 +42,7 @@ #include "util/u_debug.h" #include "util/u_debug_stack.h" -#include "util/u_double_list.h" +#include "util/list.h" #define DEBUG_MEMORY_MAGIC 0x6e34090aU diff --git a/mesalib/src/gallium/auxiliary/util/u_dirty_surfaces.h b/mesalib/src/gallium/auxiliary/util/u_dirty_surfaces.h index f3618d9be..d31f8b917 100644 --- a/mesalib/src/gallium/auxiliary/util/u_dirty_surfaces.h +++ b/mesalib/src/gallium/auxiliary/util/u_dirty_surfaces.h @@ -29,7 +29,7 @@ #include "pipe/p_state.h" -#include "util/u_double_list.h" +#include "util/list.h" #include "util/u_math.h" struct pipe_context; diff --git a/mesalib/src/glsl/Makefile.sources b/mesalib/src/glsl/Makefile.sources index c471eca23..d784a8107 100644 --- a/mesalib/src/glsl/Makefile.sources +++ b/mesalib/src/glsl/Makefile.sources @@ -22,6 +22,7 @@ NIR_FILES = \ nir/glsl_to_nir.h \ nir/nir.c \ nir/nir.h \ + nir/nir_array.h \ nir/nir_builder.h \ nir/nir_constant_expressions.h \ nir/nir_dominance.c \ diff --git a/mesalib/src/glsl/ast_to_hir.cpp b/mesalib/src/glsl/ast_to_hir.cpp index 18b82e3be..14e630905 100644 --- a/mesalib/src/glsl/ast_to_hir.cpp +++ b/mesalib/src/glsl/ast_to_hir.cpp @@ -1558,6 +1558,18 @@ ast_expression::do_hir(exec_list *instructions, error_emitted = true; } + /* From section 4.1.7 of the GLSL 4.50 spec (Opaque Types): + * + * "Except for array indexing, structure member selection, and + * parentheses, opaque variables are not allowed to be operands in + * expressions; such use results in a compile-time error." + */ + if (type->contains_opaque()) { + _mesa_glsl_error(&loc, state, "opaque variables cannot be operands " + "of the ?: operator"); + error_emitted = true; + } + ir_constant *cond_val = op[0]->constant_expression_value(); if (then_instructions.is_empty() @@ -2357,6 +2369,14 @@ apply_image_qualifier_to_variable(const struct ast_type_qualifier *qual, var->data.image_format = GL_NONE; } + } else if (qual->flags.q.read_only || + qual->flags.q.write_only || + qual->flags.q.coherent || + qual->flags.q._volatile || + qual->flags.q.restrict_flag || + qual->flags.q.explicit_image_format) { + _mesa_glsl_error(loc, state, "memory qualifiers may only be applied to " + "images"); } } @@ -2781,8 +2801,21 @@ apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual, validate_matrix_layout_for_type(state, loc, var->type, var); } - if (var->type->contains_image()) - apply_image_qualifier_to_variable(qual, var, state, loc); + apply_image_qualifier_to_variable(qual, var, state, loc); + + /* From section 4.4.1.3 of the GLSL 4.50 specification (Fragment Shader + * Inputs): + * + * "Fragment shaders also allow the following layout qualifier on in only + * (not with variable declarations) + * layout-qualifier-id + * early_fragment_tests + * [...]" + */ + if (qual->flags.q.early_fragment_tests) { + _mesa_glsl_error(loc, state, "early_fragment_tests layout qualifier only " + "valid in fragment shader input layout declaration."); + } } /** @@ -3541,6 +3574,9 @@ ast_declarator_list::hir(exec_list *instructions, case GLSL_TYPE_INT: if (state->is_version(120, 300)) break; + case GLSL_TYPE_DOUBLE: + if (check_type->base_type == GLSL_TYPE_DOUBLE && (state->is_version(410, 0) || state->ARB_vertex_attrib_64bit_enable)) + break; /* FALLTHROUGH */ default: _mesa_glsl_error(& loc, state, diff --git a/mesalib/src/glsl/ast_type.cpp b/mesalib/src/glsl/ast_type.cpp index b596cd59e..1bcf6a2e8 100644 --- a/mesalib/src/glsl/ast_type.cpp +++ b/mesalib/src/glsl/ast_type.cpp @@ -293,11 +293,7 @@ ast_type_qualifier::merge_in_qualifier(YYLTYPE *loc, valid_in_mask.flags.q.invocations = 1; break; case MESA_SHADER_FRAGMENT: - if (q.flags.q.early_fragment_tests) { - state->early_fragment_tests = true; - } else { - _mesa_glsl_error(loc, state, "invalid input layout qualifier"); - } + valid_in_mask.flags.q.early_fragment_tests = 1; break; case MESA_SHADER_COMPUTE: create_cs_ast |= @@ -345,6 +341,10 @@ ast_type_qualifier::merge_in_qualifier(YYLTYPE *loc, this->invocations = q.invocations; } + if (q.flags.q.early_fragment_tests) { + state->fs_early_fragment_tests = true; + } + if (create_gs_ast) { node = new(mem_ctx) ast_gs_input_layout(*loc, q.prim_type); } else if (create_cs_ast) { diff --git a/mesalib/src/glsl/builtin_functions.cpp b/mesalib/src/glsl/builtin_functions.cpp index 524b8d6e8..97055d85d 100644 --- a/mesalib/src/glsl/builtin_functions.cpp +++ b/mesalib/src/glsl/builtin_functions.cpp @@ -136,6 +136,12 @@ v140(const _mesa_glsl_parse_state *state) } static bool +es31(const _mesa_glsl_parse_state *state) +{ + return state->is_version(0, 310); +} + +static bool texture_rectangle(const _mesa_glsl_parse_state *state) { return state->ARB_texture_rectangle_enable; @@ -194,7 +200,8 @@ shader_bit_encoding(const _mesa_glsl_parse_state *state) static bool shader_integer_mix(const _mesa_glsl_parse_state *state) { - return v130(state) && state->EXT_shader_integer_mix_enable; + return state->is_version(450, 310) || + (v130(state) && state->EXT_shader_integer_mix_enable); } static bool @@ -219,10 +226,17 @@ gpu_shader5(const _mesa_glsl_parse_state *state) } static bool -shader_packing_or_gpu_shader5(const _mesa_glsl_parse_state *state) +gpu_shader5_or_es31(const _mesa_glsl_parse_state *state) +{ + return state->is_version(400, 310) || state->ARB_gpu_shader5_enable; +} + +static bool +shader_packing_or_es31_or_gpu_shader5(const _mesa_glsl_parse_state *state) { return state->ARB_shading_language_packing_enable || - gpu_shader5(state); + state->ARB_gpu_shader5_enable || + state->is_version(400, 310); } static bool @@ -297,15 +311,24 @@ texture_gather(const _mesa_glsl_parse_state *state) state->ARB_gpu_shader5_enable; } +static bool +texture_gather_or_es31(const _mesa_glsl_parse_state *state) +{ + return state->is_version(400, 310) || + state->ARB_texture_gather_enable || + state->ARB_gpu_shader5_enable; +} + /* Only ARB_texture_gather but not GLSL 4.0 or ARB_gpu_shader5. * used for relaxation of const offset requirements. */ static bool -texture_gather_only(const _mesa_glsl_parse_state *state) +texture_gather_only_or_es31(const _mesa_glsl_parse_state *state) { return !state->is_version(400, 0) && !state->ARB_gpu_shader5_enable && - state->ARB_texture_gather_enable; + (state->ARB_texture_gather_enable || + state->is_version(0, 310)); } /* Desktop GL or OES_standard_derivatives + fragment shader only */ @@ -359,7 +382,7 @@ tex3d_lod(const _mesa_glsl_parse_state *state) static bool shader_atomic_counters(const _mesa_glsl_parse_state *state) { - return state->ARB_shader_atomic_counters_enable; + return state->has_atomic_counters(); } static bool @@ -1161,12 +1184,12 @@ builtin_builder::create_builtins() add_function("packUnorm2x16", _packUnorm2x16(shader_packing_or_es3_or_gpu_shader5), NULL); add_function("packSnorm2x16", _packSnorm2x16(shader_packing_or_es3), NULL); - add_function("packUnorm4x8", _packUnorm4x8(shader_packing_or_gpu_shader5), NULL); - add_function("packSnorm4x8", _packSnorm4x8(shader_packing_or_gpu_shader5), NULL); + add_function("packUnorm4x8", _packUnorm4x8(shader_packing_or_es31_or_gpu_shader5), NULL); + add_function("packSnorm4x8", _packSnorm4x8(shader_packing_or_es31_or_gpu_shader5), NULL); add_function("unpackUnorm2x16", _unpackUnorm2x16(shader_packing_or_es3_or_gpu_shader5), NULL); add_function("unpackSnorm2x16", _unpackSnorm2x16(shader_packing_or_es3), NULL); - add_function("unpackUnorm4x8", _unpackUnorm4x8(shader_packing_or_gpu_shader5), NULL); - add_function("unpackSnorm4x8", _unpackSnorm4x8(shader_packing_or_gpu_shader5), NULL); + add_function("unpackUnorm4x8", _unpackUnorm4x8(shader_packing_or_es31_or_gpu_shader5), NULL); + add_function("unpackSnorm4x8", _unpackSnorm4x8(shader_packing_or_es31_or_gpu_shader5), NULL); add_function("packHalf2x16", _packHalf2x16(shader_packing_or_es3), NULL); add_function("unpackHalf2x16", _unpackHalf2x16(shader_packing_or_es3), NULL); add_function("packDouble2x32", _packDouble2x32(fp64), NULL); @@ -2202,61 +2225,69 @@ builtin_builder::create_builtins() NULL); add_function("textureGather", - _texture(ir_tg4, texture_gather, glsl_type::vec4_type, glsl_type::sampler2D_type, glsl_type::vec2_type), - _texture(ir_tg4, texture_gather, glsl_type::ivec4_type, glsl_type::isampler2D_type, glsl_type::vec2_type), - _texture(ir_tg4, texture_gather, glsl_type::uvec4_type, glsl_type::usampler2D_type, glsl_type::vec2_type), + _texture(ir_tg4, texture_gather_or_es31, glsl_type::vec4_type, glsl_type::sampler2D_type, glsl_type::vec2_type), + _texture(ir_tg4, texture_gather_or_es31, glsl_type::ivec4_type, glsl_type::isampler2D_type, glsl_type::vec2_type), + _texture(ir_tg4, texture_gather_or_es31, glsl_type::uvec4_type, glsl_type::usampler2D_type, glsl_type::vec2_type), _texture(ir_tg4, gpu_shader5, glsl_type::vec4_type, glsl_type::sampler2DRect_type, glsl_type::vec2_type), _texture(ir_tg4, gpu_shader5, glsl_type::ivec4_type, glsl_type::isampler2DRect_type, glsl_type::vec2_type), _texture(ir_tg4, gpu_shader5, glsl_type::uvec4_type, glsl_type::usampler2DRect_type, glsl_type::vec2_type), - _texture(ir_tg4, texture_gather, glsl_type::vec4_type, glsl_type::sampler2DArray_type, glsl_type::vec3_type), - _texture(ir_tg4, texture_gather, glsl_type::ivec4_type, glsl_type::isampler2DArray_type, glsl_type::vec3_type), - _texture(ir_tg4, texture_gather, glsl_type::uvec4_type, glsl_type::usampler2DArray_type, glsl_type::vec3_type), + _texture(ir_tg4, texture_gather_or_es31, glsl_type::vec4_type, glsl_type::sampler2DArray_type, glsl_type::vec3_type), + _texture(ir_tg4, texture_gather_or_es31, glsl_type::ivec4_type, glsl_type::isampler2DArray_type, glsl_type::vec3_type), + _texture(ir_tg4, texture_gather_or_es31, glsl_type::uvec4_type, glsl_type::usampler2DArray_type, glsl_type::vec3_type), - _texture(ir_tg4, texture_gather, glsl_type::vec4_type, glsl_type::samplerCube_type, glsl_type::vec3_type), - _texture(ir_tg4, texture_gather, glsl_type::ivec4_type, glsl_type::isamplerCube_type, glsl_type::vec3_type), - _texture(ir_tg4, texture_gather, glsl_type::uvec4_type, glsl_type::usamplerCube_type, glsl_type::vec3_type), + _texture(ir_tg4, texture_gather_or_es31, glsl_type::vec4_type, glsl_type::samplerCube_type, glsl_type::vec3_type), + _texture(ir_tg4, texture_gather_or_es31, glsl_type::ivec4_type, glsl_type::isamplerCube_type, glsl_type::vec3_type), + _texture(ir_tg4, texture_gather_or_es31, glsl_type::uvec4_type, glsl_type::usamplerCube_type, glsl_type::vec3_type), _texture(ir_tg4, texture_gather, glsl_type::vec4_type, glsl_type::samplerCubeArray_type, glsl_type::vec4_type), _texture(ir_tg4, texture_gather, glsl_type::ivec4_type, glsl_type::isamplerCubeArray_type, glsl_type::vec4_type), _texture(ir_tg4, texture_gather, glsl_type::uvec4_type, glsl_type::usamplerCubeArray_type, glsl_type::vec4_type), - _texture(ir_tg4, gpu_shader5, glsl_type::vec4_type, glsl_type::sampler2D_type, glsl_type::vec2_type, TEX_COMPONENT), - _texture(ir_tg4, gpu_shader5, glsl_type::ivec4_type, glsl_type::isampler2D_type, glsl_type::vec2_type, TEX_COMPONENT), - _texture(ir_tg4, gpu_shader5, glsl_type::uvec4_type, glsl_type::usampler2D_type, glsl_type::vec2_type, TEX_COMPONENT), + _texture(ir_tg4, gpu_shader5_or_es31, glsl_type::vec4_type, glsl_type::sampler2D_type, glsl_type::vec2_type, TEX_COMPONENT), + _texture(ir_tg4, gpu_shader5_or_es31, glsl_type::ivec4_type, glsl_type::isampler2D_type, glsl_type::vec2_type, TEX_COMPONENT), + _texture(ir_tg4, gpu_shader5_or_es31, glsl_type::uvec4_type, glsl_type::usampler2D_type, glsl_type::vec2_type, TEX_COMPONENT), _texture(ir_tg4, gpu_shader5, glsl_type::vec4_type, glsl_type::sampler2DRect_type, glsl_type::vec2_type, TEX_COMPONENT), _texture(ir_tg4, gpu_shader5, glsl_type::ivec4_type, glsl_type::isampler2DRect_type, glsl_type::vec2_type, TEX_COMPONENT), _texture(ir_tg4, gpu_shader5, glsl_type::uvec4_type, glsl_type::usampler2DRect_type, glsl_type::vec2_type, TEX_COMPONENT), - _texture(ir_tg4, gpu_shader5, glsl_type::vec4_type, glsl_type::sampler2DArray_type, glsl_type::vec3_type, TEX_COMPONENT), - _texture(ir_tg4, gpu_shader5, glsl_type::ivec4_type, glsl_type::isampler2DArray_type, glsl_type::vec3_type, TEX_COMPONENT), - _texture(ir_tg4, gpu_shader5, glsl_type::uvec4_type, glsl_type::usampler2DArray_type, glsl_type::vec3_type, TEX_COMPONENT), + _texture(ir_tg4, gpu_shader5_or_es31, glsl_type::vec4_type, glsl_type::sampler2DArray_type, glsl_type::vec3_type, TEX_COMPONENT), + _texture(ir_tg4, gpu_shader5_or_es31, glsl_type::ivec4_type, glsl_type::isampler2DArray_type, glsl_type::vec3_type, TEX_COMPONENT), + _texture(ir_tg4, gpu_shader5_or_es31, glsl_type::uvec4_type, glsl_type::usampler2DArray_type, glsl_type::vec3_type, TEX_COMPONENT), - _texture(ir_tg4, gpu_shader5, glsl_type::vec4_type, glsl_type::samplerCube_type, glsl_type::vec3_type, TEX_COMPONENT), - _texture(ir_tg4, gpu_shader5, glsl_type::ivec4_type, glsl_type::isamplerCube_type, glsl_type::vec3_type, TEX_COMPONENT), - _texture(ir_tg4, gpu_shader5, glsl_type::uvec4_type, glsl_type::usamplerCube_type, glsl_type::vec3_type, TEX_COMPONENT), + _texture(ir_tg4, gpu_shader5_or_es31, glsl_type::vec4_type, glsl_type::samplerCube_type, glsl_type::vec3_type, TEX_COMPONENT), + _texture(ir_tg4, gpu_shader5_or_es31, glsl_type::ivec4_type, glsl_type::isamplerCube_type, glsl_type::vec3_type, TEX_COMPONENT), + _texture(ir_tg4, gpu_shader5_or_es31, glsl_type::uvec4_type, glsl_type::usamplerCube_type, glsl_type::vec3_type, TEX_COMPONENT), _texture(ir_tg4, gpu_shader5, glsl_type::vec4_type, glsl_type::samplerCubeArray_type, glsl_type::vec4_type, TEX_COMPONENT), _texture(ir_tg4, gpu_shader5, glsl_type::ivec4_type, glsl_type::isamplerCubeArray_type, glsl_type::vec4_type, TEX_COMPONENT), _texture(ir_tg4, gpu_shader5, glsl_type::uvec4_type, glsl_type::usamplerCubeArray_type, glsl_type::vec4_type, TEX_COMPONENT), - _texture(ir_tg4, gpu_shader5, glsl_type::vec4_type, glsl_type::sampler2DShadow_type, glsl_type::vec2_type), - _texture(ir_tg4, gpu_shader5, glsl_type::vec4_type, glsl_type::sampler2DArrayShadow_type, glsl_type::vec3_type), - _texture(ir_tg4, gpu_shader5, glsl_type::vec4_type, glsl_type::samplerCubeShadow_type, glsl_type::vec3_type), + _texture(ir_tg4, gpu_shader5_or_es31, glsl_type::vec4_type, glsl_type::sampler2DShadow_type, glsl_type::vec2_type), + _texture(ir_tg4, gpu_shader5_or_es31, glsl_type::vec4_type, glsl_type::sampler2DArrayShadow_type, glsl_type::vec3_type), + _texture(ir_tg4, gpu_shader5_or_es31, glsl_type::vec4_type, glsl_type::samplerCubeShadow_type, glsl_type::vec3_type), _texture(ir_tg4, gpu_shader5, glsl_type::vec4_type, glsl_type::samplerCubeArrayShadow_type, glsl_type::vec4_type), _texture(ir_tg4, gpu_shader5, glsl_type::vec4_type, glsl_type::sampler2DRectShadow_type, glsl_type::vec2_type), NULL); add_function("textureGatherOffset", - _texture(ir_tg4, texture_gather_only, glsl_type::vec4_type, glsl_type::sampler2D_type, glsl_type::vec2_type, TEX_OFFSET), - _texture(ir_tg4, texture_gather_only, glsl_type::ivec4_type, glsl_type::isampler2D_type, glsl_type::vec2_type, TEX_OFFSET), - _texture(ir_tg4, texture_gather_only, glsl_type::uvec4_type, glsl_type::usampler2D_type, glsl_type::vec2_type, TEX_OFFSET), + _texture(ir_tg4, texture_gather_only_or_es31, glsl_type::vec4_type, glsl_type::sampler2D_type, glsl_type::vec2_type, TEX_OFFSET), + _texture(ir_tg4, texture_gather_only_or_es31, glsl_type::ivec4_type, glsl_type::isampler2D_type, glsl_type::vec2_type, TEX_OFFSET), + _texture(ir_tg4, texture_gather_only_or_es31, glsl_type::uvec4_type, glsl_type::usampler2D_type, glsl_type::vec2_type, TEX_OFFSET), + + _texture(ir_tg4, texture_gather_only_or_es31, glsl_type::vec4_type, glsl_type::sampler2DArray_type, glsl_type::vec3_type, TEX_OFFSET), + _texture(ir_tg4, texture_gather_only_or_es31, glsl_type::ivec4_type, glsl_type::isampler2DArray_type, glsl_type::vec3_type, TEX_OFFSET), + _texture(ir_tg4, texture_gather_only_or_es31, glsl_type::uvec4_type, glsl_type::usampler2DArray_type, glsl_type::vec3_type, TEX_OFFSET), - _texture(ir_tg4, texture_gather_only, glsl_type::vec4_type, glsl_type::sampler2DArray_type, glsl_type::vec3_type, TEX_OFFSET), - _texture(ir_tg4, texture_gather_only, glsl_type::ivec4_type, glsl_type::isampler2DArray_type, glsl_type::vec3_type, TEX_OFFSET), - _texture(ir_tg4, texture_gather_only, glsl_type::uvec4_type, glsl_type::usampler2DArray_type, glsl_type::vec3_type, TEX_OFFSET), + _texture(ir_tg4, es31, glsl_type::vec4_type, glsl_type::sampler2D_type, glsl_type::vec2_type, TEX_OFFSET | TEX_COMPONENT), + _texture(ir_tg4, es31, glsl_type::ivec4_type, glsl_type::isampler2D_type, glsl_type::vec2_type, TEX_OFFSET | TEX_COMPONENT), + _texture(ir_tg4, es31, glsl_type::uvec4_type, glsl_type::usampler2D_type, glsl_type::vec2_type, TEX_OFFSET | TEX_COMPONENT), + + _texture(ir_tg4, es31, glsl_type::vec4_type, glsl_type::sampler2DArray_type, glsl_type::vec3_type, TEX_OFFSET | TEX_COMPONENT), + _texture(ir_tg4, es31, glsl_type::ivec4_type, glsl_type::isampler2DArray_type, glsl_type::vec3_type, TEX_OFFSET | TEX_COMPONENT), + _texture(ir_tg4, es31, glsl_type::uvec4_type, glsl_type::usampler2DArray_type, glsl_type::vec3_type, TEX_OFFSET | TEX_COMPONENT), _texture(ir_tg4, gpu_shader5, glsl_type::vec4_type, glsl_type::sampler2D_type, glsl_type::vec2_type, TEX_OFFSET_NONCONST), _texture(ir_tg4, gpu_shader5, glsl_type::ivec4_type, glsl_type::isampler2D_type, glsl_type::vec2_type, TEX_OFFSET_NONCONST), @@ -2285,6 +2316,9 @@ builtin_builder::create_builtins() _texture(ir_tg4, gpu_shader5, glsl_type::vec4_type, glsl_type::sampler2DShadow_type, glsl_type::vec2_type, TEX_OFFSET_NONCONST), _texture(ir_tg4, gpu_shader5, glsl_type::vec4_type, glsl_type::sampler2DArrayShadow_type, glsl_type::vec3_type, TEX_OFFSET_NONCONST), _texture(ir_tg4, gpu_shader5, glsl_type::vec4_type, glsl_type::sampler2DRectShadow_type, glsl_type::vec2_type, TEX_OFFSET_NONCONST), + + _texture(ir_tg4, es31, glsl_type::vec4_type, glsl_type::sampler2DShadow_type, glsl_type::vec2_type, TEX_OFFSET), + _texture(ir_tg4, es31, glsl_type::vec4_type, glsl_type::sampler2DArrayShadow_type, glsl_type::vec3_type, TEX_OFFSET), NULL); add_function("textureGatherOffsets", @@ -4445,7 +4479,7 @@ builtin_builder::_bitfieldExtract(const glsl_type *type) ir_variable *value = in_var(type, "value"); ir_variable *offset = in_var(glsl_type::int_type, "offset"); ir_variable *bits = in_var(glsl_type::int_type, "bits"); - MAKE_SIG(type, gpu_shader5, 3, value, offset, bits); + MAKE_SIG(type, gpu_shader5_or_es31, 3, value, offset, bits); body.emit(ret(expr(ir_triop_bitfield_extract, value, offset, bits))); @@ -4459,33 +4493,33 @@ builtin_builder::_bitfieldInsert(const glsl_type *type) ir_variable *insert = in_var(type, "insert"); ir_variable *offset = in_var(glsl_type::int_type, "offset"); ir_variable *bits = in_var(glsl_type::int_type, "bits"); - MAKE_SIG(type, gpu_shader5, 4, base, insert, offset, bits); + MAKE_SIG(type, gpu_shader5_or_es31, 4, base, insert, offset, bits); body.emit(ret(bitfield_insert(base, insert, offset, bits))); return sig; } -UNOP(bitfieldReverse, ir_unop_bitfield_reverse, gpu_shader5) +UNOP(bitfieldReverse, ir_unop_bitfield_reverse, gpu_shader5_or_es31) ir_function_signature * builtin_builder::_bitCount(const glsl_type *type) { - return unop(gpu_shader5, ir_unop_bit_count, + return unop(gpu_shader5_or_es31, ir_unop_bit_count, glsl_type::ivec(type->vector_elements), type); } ir_function_signature * builtin_builder::_findLSB(const glsl_type *type) { - return unop(gpu_shader5, ir_unop_find_lsb, + return unop(gpu_shader5_or_es31, ir_unop_find_lsb, glsl_type::ivec(type->vector_elements), type); } ir_function_signature * builtin_builder::_findMSB(const glsl_type *type) { - return unop(gpu_shader5, ir_unop_find_msb, + return unop(gpu_shader5_or_es31, ir_unop_find_msb, glsl_type::ivec(type->vector_elements), type); } @@ -4505,7 +4539,7 @@ builtin_builder::_fma(builtin_available_predicate avail, const glsl_type *type) ir_function_signature * builtin_builder::_ldexp(const glsl_type *x_type, const glsl_type *exp_type) { - return binop(ir_binop_ldexp, x_type->base_type == GLSL_TYPE_DOUBLE ? fp64 : gpu_shader5, x_type, x_type, exp_type); + return binop(ir_binop_ldexp, x_type->base_type == GLSL_TYPE_DOUBLE ? fp64 : gpu_shader5_or_es31, x_type, x_type, exp_type); } ir_function_signature * @@ -4526,7 +4560,7 @@ builtin_builder::_frexp(const glsl_type *x_type, const glsl_type *exp_type) { ir_variable *x = in_var(x_type, "x"); ir_variable *exponent = out_var(exp_type, "exp"); - MAKE_SIG(x_type, gpu_shader5, 2, x, exponent); + MAKE_SIG(x_type, gpu_shader5_or_es31, 2, x, exponent); const unsigned vec_elem = x_type->vector_elements; const glsl_type *bvec = glsl_type::get_instance(GLSL_TYPE_BOOL, vec_elem, 1); @@ -4575,7 +4609,7 @@ builtin_builder::_uaddCarry(const glsl_type *type) ir_variable *x = in_var(type, "x"); ir_variable *y = in_var(type, "y"); ir_variable *carry = out_var(type, "carry"); - MAKE_SIG(type, gpu_shader5, 3, x, y, carry); + MAKE_SIG(type, gpu_shader5_or_es31, 3, x, y, carry); body.emit(assign(carry, ir_builder::carry(x, y))); body.emit(ret(add(x, y))); @@ -4589,7 +4623,7 @@ builtin_builder::_usubBorrow(const glsl_type *type) ir_variable *x = in_var(type, "x"); ir_variable *y = in_var(type, "y"); ir_variable *borrow = out_var(type, "borrow"); - MAKE_SIG(type, gpu_shader5, 3, x, y, borrow); + MAKE_SIG(type, gpu_shader5_or_es31, 3, x, y, borrow); body.emit(assign(borrow, ir_builder::borrow(x, y))); body.emit(ret(sub(x, y))); @@ -4607,7 +4641,7 @@ builtin_builder::_mulExtended(const glsl_type *type) ir_variable *y = in_var(type, "y"); ir_variable *msb = out_var(type, "msb"); ir_variable *lsb = out_var(type, "lsb"); - MAKE_SIG(glsl_type::void_type, gpu_shader5, 4, x, y, msb, lsb); + MAKE_SIG(glsl_type::void_type, gpu_shader5_or_es31, 4, x, y, msb, lsb); body.emit(assign(msb, imul_high(x, y))); body.emit(assign(lsb, mul(x, y))); diff --git a/mesalib/src/glsl/builtin_types.cpp b/mesalib/src/glsl/builtin_types.cpp index fef86df28..d92e2eb30 100644 --- a/mesalib/src/glsl/builtin_types.cpp +++ b/mesalib/src/glsl/builtin_types.cpp @@ -372,7 +372,7 @@ _mesa_glsl_initialize_types(struct _mesa_glsl_parse_state *state) add_type(symbols, glsl_type::uimage2DMSArray_type); } - if (state->ARB_shader_atomic_counters_enable) { + if (state->has_atomic_counters()) { add_type(symbols, glsl_type::atomic_uint_type); } diff --git a/mesalib/src/glsl/builtin_variables.cpp b/mesalib/src/glsl/builtin_variables.cpp index 21e7331c7..6806aa1f9 100644 --- a/mesalib/src/glsl/builtin_variables.cpp +++ b/mesalib/src/glsl/builtin_variables.cpp @@ -653,19 +653,46 @@ builtin_variable_generator::generate_constants() add_const("gl_MaxTextureCoords", state->Const.MaxTextureCoords); } - if (state->ARB_shader_atomic_counters_enable) { + if (state->has_atomic_counters()) { add_const("gl_MaxVertexAtomicCounters", state->Const.MaxVertexAtomicCounters); - add_const("gl_MaxGeometryAtomicCounters", - state->Const.MaxGeometryAtomicCounters); add_const("gl_MaxFragmentAtomicCounters", state->Const.MaxFragmentAtomicCounters); add_const("gl_MaxCombinedAtomicCounters", state->Const.MaxCombinedAtomicCounters); add_const("gl_MaxAtomicCounterBindings", state->Const.MaxAtomicBufferBindings); - add_const("gl_MaxTessControlAtomicCounters", 0); - add_const("gl_MaxTessEvaluationAtomicCounters", 0); + + /* When Mesa adds support for GL_OES_geometry_shader and + * GL_OES_tessellation_shader, this will need to change. + */ + if (!state->es_shader) { + add_const("gl_MaxGeometryAtomicCounters", + state->Const.MaxGeometryAtomicCounters); + add_const("gl_MaxTessControlAtomicCounters", 0); + add_const("gl_MaxTessEvaluationAtomicCounters", 0); + } + } + + if (state->is_version(420, 310)) { + add_const("gl_MaxVertexAtomicCounterBuffers", + state->Const.MaxVertexAtomicCounterBuffers); + add_const("gl_MaxFragmentAtomicCounterBuffers", + state->Const.MaxFragmentAtomicCounterBuffers); + add_const("gl_MaxCombinedAtomicCounterBuffers", + state->Const.MaxCombinedAtomicCounterBuffers); + add_const("gl_MaxAtomicCounterBufferSize", + state->Const.MaxAtomicCounterBufferSize); + + /* When Mesa adds support for GL_OES_geometry_shader and + * GL_OES_tessellation_shader, this will need to change. + */ + if (!state->es_shader) { + add_const("gl_MaxGeometryAtomicCounterBuffers", + state->Const.MaxGeometryAtomicCounterBuffers); + add_const("gl_MaxTessControlAtomicCounterBuffers", 0); + add_const("gl_MaxTessEvaluationAtomicCounterBuffers", 0); + } } if (state->is_version(430, 0) || state->ARB_compute_shader_enable) { diff --git a/mesalib/src/glsl/glcpp/glcpp-parse.y b/mesalib/src/glsl/glcpp/glcpp-parse.y index cfceca66b..a11b6b2c7 100644 --- a/mesalib/src/glsl/glcpp/glcpp-parse.y +++ b/mesalib/src/glsl/glcpp/glcpp-parse.y @@ -2448,6 +2448,9 @@ _glcpp_parser_handle_version_declaration(glcpp_parser_t *parser, intmax_t versio if (extensions->ARB_gpu_shader_fp64) add_builtin_define(parser, "GL_ARB_gpu_shader_fp64", 1); + if (extensions->ARB_vertex_attrib_64bit) + add_builtin_define(parser, "GL_ARB_vertex_attrib_64bit", 1); + if (extensions->AMD_vertex_shader_layer) add_builtin_define(parser, "GL_AMD_vertex_shader_layer", 1); diff --git a/mesalib/src/glsl/glsl_lexer.ll b/mesalib/src/glsl/glsl_lexer.ll index 2785ed168..10db5b8b6 100644 --- a/mesalib/src/glsl/glsl_lexer.ll +++ b/mesalib/src/glsl/glsl_lexer.ll @@ -409,7 +409,7 @@ restrict KEYWORD_WITH_ALT(420, 300, 420, 0, yyextra->ARB_shader_image_load_store readonly KEYWORD_WITH_ALT(420, 300, 420, 0, yyextra->ARB_shader_image_load_store_enable, READONLY); writeonly KEYWORD_WITH_ALT(420, 300, 420, 0, yyextra->ARB_shader_image_load_store_enable, WRITEONLY); -atomic_uint KEYWORD_WITH_ALT(420, 300, 420, 0, yyextra->ARB_shader_atomic_counters_enable, ATOMIC_UINT); +atomic_uint KEYWORD_WITH_ALT(420, 300, 420, 310, yyextra->ARB_shader_atomic_counters_enable, ATOMIC_UINT); struct return STRUCT; void return VOID_TOK; diff --git a/mesalib/src/glsl/glsl_parser.yy b/mesalib/src/glsl/glsl_parser.yy index aceb3b916..3ce9e103f 100644 --- a/mesalib/src/glsl/glsl_parser.yy +++ b/mesalib/src/glsl/glsl_parser.yy @@ -214,6 +214,7 @@ static bool match_layout_qualifier(const char *s1, const char *s2, %type <type_qualifier> layout_qualifier %type <type_qualifier> layout_qualifier_id_list layout_qualifier_id %type <type_qualifier> interface_block_layout_qualifier +%type <type_qualifier> memory_qualifier %type <type_qualifier> interface_qualifier %type <type_specifier> type_specifier %type <type_specifier> type_specifier_nonarray @@ -1000,6 +1001,11 @@ parameter_qualifier: $$ = $2; $$.precision = $1; } + | memory_qualifier parameter_qualifier + { + $$ = $1; + $$.merge_qualifier(&@1, state, $2); + } parameter_direction_qualifier: IN_TOK @@ -1360,6 +1366,21 @@ layout_qualifier_id: if (!$$.flags.i && match_layout_qualifier($1, "early_fragment_tests", state) == 0) { + /* From section 4.4.1.3 of the GLSL 4.50 specification + * (Fragment Shader Inputs): + * + * "Fragment shaders also allow the following layout + * qualifier on in only (not with variable declarations) + * layout-qualifier-id + * early_fragment_tests + * [...]" + */ + if (state->stage != MESA_SHADER_FRAGMENT) { + _mesa_glsl_error(& @1, state, + "early_fragment_tests layout qualifier only " + "valid in fragment shaders"); + } + $$.flags.q.early_fragment_tests = 1; } } @@ -1404,13 +1425,13 @@ layout_qualifier_id: } if ((state->ARB_shading_language_420pack_enable || - state->ARB_shader_atomic_counters_enable) && + state->has_atomic_counters()) && match_layout_qualifier("binding", $1, state) == 0) { $$.flags.q.explicit_binding = 1; $$.binding = $3; } - if (state->ARB_shader_atomic_counters_enable && + if (state->has_atomic_counters() && match_layout_qualifier("offset", $1, state) == 0) { $$.flags.q.explicit_offset = 1; $$.offset = $3; @@ -1581,6 +1602,7 @@ type_qualifier: | storage_qualifier | interpolation_qualifier | layout_qualifier + | memory_qualifier | precision_qualifier { memset(&$$, 0, sizeof($$)); @@ -1718,6 +1740,11 @@ type_qualifier: $$ = $2; $$.precision = $1; } + | memory_qualifier type_qualifier + { + $$ = $1; + $$.merge_qualifier(&@1, state, $2); + } ; auxiliary_storage_qualifier: @@ -1778,7 +1805,10 @@ storage_qualifier: memset(& $$, 0, sizeof($$)); $$.flags.q.uniform = 1; } - | COHERENT + ; + +memory_qualifier: + COHERENT { memset(& $$, 0, sizeof($$)); $$.flags.q.coherent = 1; diff --git a/mesalib/src/glsl/glsl_parser_extras.cpp b/mesalib/src/glsl/glsl_parser_extras.cpp index 0aa3c54fc..be6713c46 100644 --- a/mesalib/src/glsl/glsl_parser_extras.cpp +++ b/mesalib/src/glsl/glsl_parser_extras.cpp @@ -117,6 +117,16 @@ _mesa_glsl_parse_state::_mesa_glsl_parse_state(struct gl_context *_ctx, this->Const.MaxFragmentAtomicCounters = ctx->Const.Program[MESA_SHADER_FRAGMENT].MaxAtomicCounters; this->Const.MaxCombinedAtomicCounters = ctx->Const.MaxCombinedAtomicCounters; this->Const.MaxAtomicBufferBindings = ctx->Const.MaxAtomicBufferBindings; + this->Const.MaxVertexAtomicCounterBuffers = + ctx->Const.Program[MESA_SHADER_VERTEX].MaxAtomicBuffers; + this->Const.MaxGeometryAtomicCounterBuffers = + ctx->Const.Program[MESA_SHADER_GEOMETRY].MaxAtomicBuffers; + this->Const.MaxFragmentAtomicCounterBuffers = + ctx->Const.Program[MESA_SHADER_FRAGMENT].MaxAtomicBuffers; + this->Const.MaxCombinedAtomicCounterBuffers = + ctx->Const.MaxCombinedAtomicBuffers; + this->Const.MaxAtomicCounterBufferSize = + ctx->Const.MaxAtomicBufferSize; /* Compute shader constants */ for (unsigned i = 0; i < ARRAY_SIZE(this->Const.MaxComputeWorkGroupCount); i++) @@ -143,9 +153,9 @@ _mesa_glsl_parse_state::_mesa_glsl_parse_state(struct gl_context *_ctx, this->num_user_structures = 0; /* supported_versions should be large enough to support the known desktop - * GLSL versions plus 2 GLES versions (ES2 & ES3) + * GLSL versions plus 3 GLES versions (ES 1.00, ES 3.00, and ES 3.10)) */ - STATIC_ASSERT((ARRAY_SIZE(known_desktop_glsl_versions) + 2) == + STATIC_ASSERT((ARRAY_SIZE(known_desktop_glsl_versions) + 3) == ARRAY_SIZE(this->supported_versions)); /* Populate the list of supported GLSL versions */ @@ -175,6 +185,11 @@ _mesa_glsl_parse_state::_mesa_glsl_parse_state(struct gl_context *_ctx, this->supported_versions[this->num_supported_versions].es = true; this->num_supported_versions++; } + if (_mesa_is_gles31(ctx)) { + this->supported_versions[this->num_supported_versions].ver = 310; + this->supported_versions[this->num_supported_versions].es = true; + this->num_supported_versions++; + } /* Create a string for use in error messages to tell the user which GLSL * versions are supported. @@ -212,7 +227,7 @@ _mesa_glsl_parse_state::_mesa_glsl_parse_state(struct gl_context *_ctx, this->gs_input_size = 0; this->in_qualifier = new(this) ast_type_qualifier(); this->out_qualifier = new(this) ast_type_qualifier(); - this->early_fragment_tests = false; + this->fs_early_fragment_tests = false; memset(this->atomic_counter_offsets, 0, sizeof(this->atomic_counter_offsets)); this->allow_extension_directive_midshader = @@ -565,6 +580,7 @@ static const _mesa_glsl_extension _mesa_glsl_supported_extensions[] = { EXT(ARB_texture_query_lod, true, false, ARB_texture_query_lod), EXT(ARB_texture_rectangle, true, false, dummy_true), EXT(ARB_uniform_buffer_object, true, false, ARB_uniform_buffer_object), + EXT(ARB_vertex_attrib_64bit, true, false, ARB_vertex_attrib_64bit), EXT(ARB_viewport_array, true, false, ARB_viewport_array), /* KHR extensions go here, sorted alphabetically. @@ -1418,6 +1434,7 @@ set_shader_inout_layout(struct gl_shader *shader, assert(!state->fs_redeclares_gl_fragcoord); assert(!state->fs_pixel_center_integer); assert(!state->fs_origin_upper_left); + assert(!state->fs_early_fragment_tests); } switch (shader->Stage) { @@ -1460,6 +1477,7 @@ set_shader_inout_layout(struct gl_shader *shader, shader->origin_upper_left = state->fs_origin_upper_left; shader->ARB_fragment_coord_conventions_enable = state->ARB_fragment_coord_conventions_enable; + shader->EarlyFragmentTests = state->fs_early_fragment_tests; break; default: diff --git a/mesalib/src/glsl/glsl_parser_extras.h b/mesalib/src/glsl/glsl_parser_extras.h index dae7864fd..9a0c24e67 100644 --- a/mesalib/src/glsl/glsl_parser_extras.h +++ b/mesalib/src/glsl/glsl_parser_extras.h @@ -160,7 +160,7 @@ struct _mesa_glsl_parse_state { { if (!this->has_separate_shader_objects()) { const char *const requirement = this->es_shader - ? "GL_EXT_separate_shader_objects extension" + ? "GL_EXT_separate_shader_objects extension or GLSL ES 310" : "GL_ARB_separate_shader_objects extension or GLSL 420"; _mesa_glsl_error(locp, this, "%s explicit location requires %s", @@ -175,17 +175,26 @@ struct _mesa_glsl_parse_state { const ir_variable *) { if (!this->has_explicit_attrib_location() || - !this->ARB_explicit_uniform_location_enable) { + !this->has_explicit_uniform_location()) { + const char *const requirement = this->es_shader + ? "GLSL ES 310" + : "GL_ARB_explicit_uniform_location and either " + "GL_ARB_explicit_attrib_location or GLSL 330."; + _mesa_glsl_error(locp, this, - "uniform explicit location requires " - "GL_ARB_explicit_uniform_location and either " - "GL_ARB_explicit_attrib_location or GLSL 330."); + "uniform explicit location requires %s", + requirement); return false; } return true; } + bool has_atomic_counters() const + { + return ARB_shader_atomic_counters_enable || is_version(420, 310); + } + bool has_explicit_attrib_stream() const { return ARB_gpu_shader5_enable || is_version(400, 0); @@ -196,6 +205,11 @@ struct _mesa_glsl_parse_state { return ARB_explicit_attrib_location_enable || is_version(330, 300); } + bool has_explicit_uniform_location() const + { + return ARB_explicit_uniform_location_enable || is_version(430, 310); + } + bool has_uniform_buffer_objects() const { return ARB_uniform_buffer_object_enable || is_version(140, 300); @@ -203,7 +217,7 @@ 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, 310) || EXT_separate_shader_objects_enable; } @@ -224,7 +238,7 @@ struct _mesa_glsl_parse_state { struct { unsigned ver; bool es; - } supported_versions[14]; + } supported_versions[15]; bool es_shader; unsigned language_version; @@ -339,6 +353,16 @@ struct _mesa_glsl_parse_state { unsigned MaxCombinedAtomicCounters; unsigned MaxAtomicBufferBindings; + /* These are also atomic counter related, but they weren't added to + * until atomic counters were added to core in GLSL 4.20 and GLSL ES + * 3.10. + */ + unsigned MaxVertexAtomicCounterBuffers; + unsigned MaxGeometryAtomicCounterBuffers; + unsigned MaxFragmentAtomicCounterBuffers; + unsigned MaxCombinedAtomicCounterBuffers; + unsigned MaxAtomicCounterBufferSize; + /* ARB_compute_shader */ unsigned MaxComputeWorkGroupCount[3]; unsigned MaxComputeWorkGroupSize[3]; @@ -458,6 +482,8 @@ struct _mesa_glsl_parse_state { bool ARB_texture_rectangle_warn; bool ARB_uniform_buffer_object_enable; bool ARB_uniform_buffer_object_warn; + bool ARB_vertex_attrib_64bit_enable; + bool ARB_vertex_attrib_64bit_warn; bool ARB_viewport_array_enable; bool ARB_viewport_array_warn; @@ -510,7 +536,7 @@ struct _mesa_glsl_parse_state { */ unsigned gs_input_size; - bool early_fragment_tests; + bool fs_early_fragment_tests; /** Atomic counter offsets by binding */ unsigned atomic_counter_offsets[MAX_COMBINED_ATOMIC_BUFFERS]; diff --git a/mesalib/src/glsl/ir_set_program_inouts.cpp b/mesalib/src/glsl/ir_set_program_inouts.cpp index e877a2019..b968a1efd 100644 --- a/mesalib/src/glsl/ir_set_program_inouts.cpp +++ b/mesalib/src/glsl/ir_set_program_inouts.cpp @@ -105,13 +105,10 @@ mark(struct gl_program *prog, ir_variable *var, int offset, int len, int idx = var->data.location + var->data.index + offset + i; GLbitfield64 bitfield = BITFIELD64_BIT(idx); - /* dvec3 and dvec4 take up 2 slots */ - if (dual_slot) { - idx += i; - bitfield |= bitfield << 1; - } if (var->data.mode == ir_var_shader_in) { - prog->InputsRead |= bitfield; + prog->InputsRead |= bitfield; + if (dual_slot) + prog->DoubleInputsRead |= bitfield; if (is_fragment_shader) { gl_fragment_program *fprog = (gl_fragment_program *) prog; fprog->InterpQualifier[idx] = @@ -120,13 +117,6 @@ mark(struct gl_program *prog, ir_variable *var, int offset, int len, fprog->IsCentroid |= bitfield; if (var->data.sample) fprog->IsSample |= bitfield; - - /* Set the InterpQualifier of the next slot to the same as the - * current one, since dvec3 and dvec4 spans 2 slots. - */ - if (dual_slot) - fprog->InterpQualifier[idx + 1] = - (glsl_interp_qualifier) var->data.interpolation; } } else if (var->data.mode == ir_var_system_value) { prog->SystemValuesRead |= bitfield; diff --git a/mesalib/src/glsl/link_uniform_blocks.cpp b/mesalib/src/glsl/link_uniform_blocks.cpp index 6ca41107e..898544bea 100644 --- a/mesalib/src/glsl/link_uniform_blocks.cpp +++ b/mesalib/src/glsl/link_uniform_blocks.cpp @@ -67,14 +67,14 @@ private: assert(!"Should not get here."); } - virtual void enter_record(const glsl_type *type, const char *name, + virtual void enter_record(const glsl_type *type, const char *, bool row_major) { assert(type->is_record()); this->offset = glsl_align( this->offset, type->std140_base_alignment(row_major)); } - virtual void leave_record(const glsl_type *type, const char *name, + virtual void leave_record(const glsl_type *type, const char *, bool row_major) { assert(type->is_record()); @@ -90,8 +90,8 @@ private: } virtual void visit_field(const glsl_type *type, const char *name, - bool row_major, const glsl_type *record_type, - bool last_field) + bool row_major, const glsl_type *, + bool /* last_field */) { assert(this->index < this->num_variables); diff --git a/mesalib/src/glsl/link_uniforms.cpp b/mesalib/src/glsl/link_uniforms.cpp index d5ca23a38..2c928e144 100644 --- a/mesalib/src/glsl/link_uniforms.cpp +++ b/mesalib/src/glsl/link_uniforms.cpp @@ -544,7 +544,7 @@ private: assert(!"Should not get here."); } - virtual void enter_record(const glsl_type *type, const char *name, + virtual void enter_record(const glsl_type *type, const char *, bool row_major) { assert(type->is_record()); if (this->ubo_block_index == -1) @@ -553,7 +553,7 @@ private: this->ubo_byte_offset, type->std140_base_alignment(row_major)); } - virtual void leave_record(const glsl_type *type, const char *name, + virtual void leave_record(const glsl_type *type, const char *, bool row_major) { assert(type->is_record()); if (this->ubo_block_index == -1) @@ -564,7 +564,7 @@ private: virtual void visit_field(const glsl_type *type, const char *name, bool row_major, const glsl_type *record_type, - bool last_field) + bool /* last_field */) { assert(!type->without_array()->is_record()); assert(!type->without_array()->is_interface()); diff --git a/mesalib/src/glsl/linker.cpp b/mesalib/src/glsl/linker.cpp index 21fde9444..ea73c6f9d 100644 --- a/mesalib/src/glsl/linker.cpp +++ b/mesalib/src/glsl/linker.cpp @@ -1413,6 +1413,8 @@ link_fs_input_layout_qualifiers(struct gl_shader_program *prog, linked_shader->origin_upper_left = shader->origin_upper_left; linked_shader->pixel_center_integer = shader->pixel_center_integer; } + + linked_shader->EarlyFragmentTests |= shader->EarlyFragmentTests; } } @@ -1975,6 +1977,7 @@ assign_attribute_or_color_locations(gl_shader_program *prog, } to_assign[16]; unsigned num_attr = 0; + unsigned total_attribs_size = 0; foreach_in_list(ir_instruction, node, sh->ir) { ir_variable *const var = node->as_variable(); @@ -2016,12 +2019,41 @@ assign_attribute_or_color_locations(gl_shader_program *prog, } } + const unsigned slots = var->type->count_attribute_slots(); + + /* From GL4.5 core spec, section 11.1.1 (Vertex Attributes): + * + * "A program with more than the value of MAX_VERTEX_ATTRIBS active + * attribute variables may fail to link, unless device-dependent + * optimizations are able to make the program fit within available + * hardware resources. For the purposes of this test, attribute variables + * of the type dvec3, dvec4, dmat2x3, dmat2x4, dmat3, dmat3x4, dmat4x3, + * and dmat4 may count as consuming twice as many attributes as equivalent + * single-precision types. While these types use the same number of + * generic attributes as their single-precision equivalents, + * implementations are permitted to consume two single-precision vectors + * of internal storage for each three- or four-component double-precision + * vector." + * Until someone has a good reason in Mesa, enforce that now. + */ + if (target_index == MESA_SHADER_VERTEX) { + total_attribs_size += slots; + if (var->type->without_array() == glsl_type::dvec3_type || + var->type->without_array() == glsl_type::dvec4_type || + var->type->without_array() == glsl_type::dmat2x3_type || + var->type->without_array() == glsl_type::dmat2x4_type || + var->type->without_array() == glsl_type::dmat3_type || + var->type->without_array() == glsl_type::dmat3x4_type || + var->type->without_array() == glsl_type::dmat4x3_type || + var->type->without_array() == glsl_type::dmat4_type) + total_attribs_size += slots; + } + /* If the variable is not a built-in and has a location statically * assigned in the shader (presumably via a layout qualifier), make sure * that it doesn't collide with other assigned locations. Otherwise, * add it to the list of variables that need linker-assigned locations. */ - const unsigned slots = var->type->count_attribute_slots(); if (var->data.location != -1) { if (var->data.location >= generic_base && var->data.index < 1) { /* From page 61 of the OpenGL 4.0 spec: @@ -2141,6 +2173,15 @@ assign_attribute_or_color_locations(gl_shader_program *prog, num_attr++; } + if (target_index == MESA_SHADER_VERTEX) { + if (total_attribs_size > max_index) { + linker_error(prog, + "attempt to use %d vertex attribute slots only %d available ", + total_attribs_size, max_index); + return false; + } + } + /* If all of the attributes were assigned locations by the application (or * are built-in attributes with fixed locations), return early. This should * be the common case. @@ -2556,6 +2597,7 @@ add_interface_variables(struct gl_shader_program *shProg, { foreach_in_list(ir_instruction, node, sh->ir) { ir_variable *var = node->as_variable(); + uint8_t mask = 0; if (!var) continue; @@ -2571,6 +2613,10 @@ add_interface_variables(struct gl_shader_program *shProg, var->data.location != SYSTEM_VALUE_VERTEX_ID_ZERO_BASE && var->data.location != SYSTEM_VALUE_INSTANCE_ID) continue; + /* Mark special built-in inputs referenced by the vertex stage so + * that they are considered active by the shader queries. + */ + mask = (1 << (MESA_SHADER_VERTEX)); /* FALLTHROUGH */ case ir_var_shader_in: if (programInterface != GL_PROGRAM_INPUT) @@ -2585,7 +2631,7 @@ add_interface_variables(struct gl_shader_program *shProg, }; if (!add_program_resource(shProg, programInterface, var, - build_stageref(shProg, var->name))) + build_stageref(shProg, var->name) | mask)) return false; } return true; diff --git a/mesalib/src/glsl/nir/glsl_to_nir.cpp b/mesalib/src/glsl/nir/glsl_to_nir.cpp index f6b8331d4..af758ceb0 100644 --- a/mesalib/src/glsl/nir/glsl_to_nir.cpp +++ b/mesalib/src/glsl/nir/glsl_to_nir.cpp @@ -614,27 +614,135 @@ nir_visitor::visit(ir_call *ir) op = nir_intrinsic_atomic_counter_inc_var; } else if (strcmp(ir->callee_name(), "__intrinsic_atomic_predecrement") == 0) { op = nir_intrinsic_atomic_counter_dec_var; + } else if (strcmp(ir->callee_name(), "__intrinsic_image_load") == 0) { + op = nir_intrinsic_image_load; + } else if (strcmp(ir->callee_name(), "__intrinsic_image_store") == 0) { + op = nir_intrinsic_image_store; + } else if (strcmp(ir->callee_name(), "__intrinsic_image_atomic_add") == 0) { + op = nir_intrinsic_image_atomic_add; + } else if (strcmp(ir->callee_name(), "__intrinsic_image_atomic_min") == 0) { + op = nir_intrinsic_image_atomic_min; + } else if (strcmp(ir->callee_name(), "__intrinsic_image_atomic_max") == 0) { + op = nir_intrinsic_image_atomic_max; + } else if (strcmp(ir->callee_name(), "__intrinsic_image_atomic_and") == 0) { + op = nir_intrinsic_image_atomic_and; + } else if (strcmp(ir->callee_name(), "__intrinsic_image_atomic_or") == 0) { + op = nir_intrinsic_image_atomic_or; + } else if (strcmp(ir->callee_name(), "__intrinsic_image_atomic_xor") == 0) { + op = nir_intrinsic_image_atomic_xor; + } else if (strcmp(ir->callee_name(), "__intrinsic_image_atomic_exchange") == 0) { + op = nir_intrinsic_image_atomic_exchange; + } else if (strcmp(ir->callee_name(), "__intrinsic_image_atomic_comp_swap") == 0) { + op = nir_intrinsic_image_atomic_comp_swap; + } else if (strcmp(ir->callee_name(), "__intrinsic_memory_barrier") == 0) { + op = nir_intrinsic_memory_barrier; } else { unreachable("not reached"); } nir_intrinsic_instr *instr = nir_intrinsic_instr_create(shader, op); - ir_dereference *param = - (ir_dereference *) ir->actual_parameters.get_head(); - instr->variables[0] = evaluate_deref(&instr->instr, param); - nir_ssa_dest_init(&instr->instr, &instr->dest, 1, NULL); + + switch (op) { + case nir_intrinsic_atomic_counter_read_var: + case nir_intrinsic_atomic_counter_inc_var: + case nir_intrinsic_atomic_counter_dec_var: { + ir_dereference *param = + (ir_dereference *) ir->actual_parameters.get_head(); + instr->variables[0] = evaluate_deref(&instr->instr, param); + nir_ssa_dest_init(&instr->instr, &instr->dest, 1, NULL); + break; + } + case nir_intrinsic_image_load: + case nir_intrinsic_image_store: + case nir_intrinsic_image_atomic_add: + case nir_intrinsic_image_atomic_min: + case nir_intrinsic_image_atomic_max: + case nir_intrinsic_image_atomic_and: + case nir_intrinsic_image_atomic_or: + case nir_intrinsic_image_atomic_xor: + case nir_intrinsic_image_atomic_exchange: + case nir_intrinsic_image_atomic_comp_swap: { + nir_ssa_undef_instr *instr_undef = + nir_ssa_undef_instr_create(shader, 1); + nir_instr_insert_after_cf_list(this->cf_node_list, + &instr_undef->instr); + + /* Set the image variable dereference. */ + exec_node *param = ir->actual_parameters.get_head(); + ir_dereference *image = (ir_dereference *)param; + const glsl_type *type = + image->variable_referenced()->type->without_array(); + + instr->variables[0] = evaluate_deref(&instr->instr, image); + param = param->get_next(); + + /* Set the address argument, extending the coordinate vector to four + * components. + */ + const nir_src src_addr = evaluate_rvalue((ir_dereference *)param); + nir_alu_instr *instr_addr = nir_alu_instr_create(shader, nir_op_vec4); + nir_ssa_dest_init(&instr_addr->instr, &instr_addr->dest.dest, 4, NULL); + + for (int i = 0; i < 4; i++) { + if (i < type->coordinate_components()) { + instr_addr->src[i].src = src_addr; + instr_addr->src[i].swizzle[0] = i; + } else { + instr_addr->src[i].src = nir_src_for_ssa(&instr_undef->def); + } + } + + nir_instr_insert_after_cf_list(cf_node_list, &instr_addr->instr); + instr->src[0] = nir_src_for_ssa(&instr_addr->dest.dest.ssa); + param = param->get_next(); + + /* Set the sample argument, which is undefined for single-sample + * images. + */ + if (type->sampler_dimensionality == GLSL_SAMPLER_DIM_MS) { + instr->src[1] = evaluate_rvalue((ir_dereference *)param); + param = param->get_next(); + } else { + instr->src[1] = nir_src_for_ssa(&instr_undef->def); + } + + /* Set the intrinsic parameters. */ + if (!param->is_tail_sentinel()) { + instr->src[2] = evaluate_rvalue((ir_dereference *)param); + param = param->get_next(); + } + + if (!param->is_tail_sentinel()) { + instr->src[3] = evaluate_rvalue((ir_dereference *)param); + param = param->get_next(); + } + + /* Set the intrinsic destination. */ + if (ir->return_deref) + nir_ssa_dest_init(&instr->instr, &instr->dest, + ir->return_deref->type->vector_elements, NULL); + break; + } + case nir_intrinsic_memory_barrier: + break; + default: + unreachable("not reached"); + } nir_instr_insert_after_cf_list(this->cf_node_list, &instr->instr); - nir_intrinsic_instr *store_instr = - nir_intrinsic_instr_create(shader, nir_intrinsic_store_var); - store_instr->num_components = 1; + if (ir->return_deref) { + nir_intrinsic_instr *store_instr = + nir_intrinsic_instr_create(shader, nir_intrinsic_store_var); + store_instr->num_components = ir->return_deref->type->vector_elements; - store_instr->variables[0] = evaluate_deref(&store_instr->instr, ir->return_deref); - store_instr->src[0].is_ssa = true; - store_instr->src[0].ssa = &instr->dest.ssa; + store_instr->variables[0] = + evaluate_deref(&store_instr->instr, ir->return_deref); + store_instr->src[0] = nir_src_for_ssa(&instr->dest.ssa); - nir_instr_insert_after_cf_list(this->cf_node_list, &store_instr->instr); + nir_instr_insert_after_cf_list(this->cf_node_list, + &store_instr->instr); + } return; } @@ -824,7 +932,7 @@ nir_visitor::evaluate_rvalue(ir_rvalue* ir) nir_dest *dest = get_instr_dest(this->result); assert(dest->is_ssa); - nir_src src; + nir_src src = NIR_SRC_INIT; src.is_ssa = true; src.ssa = &dest->ssa; @@ -1038,8 +1146,8 @@ nir_visitor::visit(ir_expression *ir) case ir_unop_rcp: emit(nir_op_frcp, dest_size, srcs); break; case ir_unop_rsq: emit(nir_op_frsq, dest_size, srcs); break; case ir_unop_sqrt: emit(nir_op_fsqrt, dest_size, srcs); break; - case ir_unop_exp: emit(nir_op_fexp, dest_size, srcs); break; - case ir_unop_log: emit(nir_op_flog, dest_size, srcs); break; + case ir_unop_exp: unreachable("ir_unop_exp should have been lowered"); + case ir_unop_log: unreachable("ir_unop_log should have been lowered"); case ir_unop_exp2: emit(nir_op_fexp2, dest_size, srcs); break; case ir_unop_log2: emit(nir_op_flog2, dest_size, srcs); break; case ir_unop_i2f: diff --git a/mesalib/src/glsl/nir/nir.c b/mesalib/src/glsl/nir/nir.c index 4cc074b80..f03e80a4e 100644 --- a/mesalib/src/glsl/nir/nir.c +++ b/mesalib/src/glsl/nir/nir.c @@ -58,12 +58,9 @@ reg_create(void *mem_ctx, struct exec_list *list) nir_register *reg = ralloc(mem_ctx, nir_register); reg->parent_instr = NULL; - reg->uses = _mesa_set_create(reg, _mesa_hash_pointer, - _mesa_key_pointer_equal); - reg->defs = _mesa_set_create(reg, _mesa_hash_pointer, - _mesa_key_pointer_equal); - reg->if_uses = _mesa_set_create(reg, _mesa_hash_pointer, - _mesa_key_pointer_equal); + list_inithead(®->uses); + list_inithead(®->defs); + list_inithead(®->if_uses); reg->num_components = 0; reg->num_array_elems = 0; @@ -1070,11 +1067,14 @@ update_if_uses(nir_cf_node *node) nir_if *if_stmt = nir_cf_node_as_if(node); - struct set *if_uses_set = if_stmt->condition.is_ssa ? - if_stmt->condition.ssa->if_uses : - if_stmt->condition.reg.reg->uses; - - _mesa_set_add(if_uses_set, if_stmt); + if_stmt->condition.parent_if = if_stmt; + if (if_stmt->condition.is_ssa) { + list_addtail(&if_stmt->condition.use_link, + &if_stmt->condition.ssa->if_uses); + } else { + list_addtail(&if_stmt->condition.use_link, + &if_stmt->condition.reg.reg->if_uses); + } } void @@ -1227,16 +1227,7 @@ cleanup_cf_node(nir_cf_node *node) foreach_list_typed(nir_cf_node, child, node, &if_stmt->else_list) cleanup_cf_node(child); - struct set *if_uses; - if (if_stmt->condition.is_ssa) { - if_uses = if_stmt->condition.ssa->if_uses; - } else { - if_uses = if_stmt->condition.reg.reg->if_uses; - } - - struct set_entry *entry = _mesa_set_search(if_uses, if_stmt); - assert(entry); - _mesa_set_remove(if_uses, entry); + list_del(&if_stmt->condition.use_link); break; } @@ -1293,9 +1284,9 @@ add_use_cb(nir_src *src, void *state) { nir_instr *instr = state; - struct set *uses_set = src->is_ssa ? src->ssa->uses : src->reg.reg->uses; - - _mesa_set_add(uses_set, instr); + src->parent_instr = instr; + list_addtail(&src->use_link, + src->is_ssa ? &src->ssa->uses : &src->reg.reg->uses); return true; } @@ -1320,8 +1311,10 @@ add_reg_def_cb(nir_dest *dest, void *state) { nir_instr *instr = state; - if (!dest->is_ssa) - _mesa_set_add(dest->reg.reg->defs, instr); + if (!dest->is_ssa) { + dest->reg.parent_instr = instr; + list_addtail(&dest->reg.def_link, &dest->reg.reg->defs); + } return true; } @@ -1436,13 +1429,7 @@ nir_instr_insert_after_cf_list(struct exec_list *list, nir_instr *after) static bool remove_use_cb(nir_src *src, void *state) { - nir_instr *instr = state; - - struct set *uses_set = src->is_ssa ? src->ssa->uses : src->reg.reg->uses; - - struct set_entry *entry = _mesa_set_search(uses_set, instr); - if (entry) - _mesa_set_remove(uses_set, entry); + list_del(&src->use_link); return true; } @@ -1450,16 +1437,8 @@ remove_use_cb(nir_src *src, void *state) static bool remove_def_cb(nir_dest *dest, void *state) { - nir_instr *instr = state; - - if (dest->is_ssa) - return true; - - nir_register *reg = dest->reg.reg; - - struct set_entry *entry = _mesa_set_search(reg->defs, instr); - if (entry) - _mesa_set_remove(reg->defs, entry); + if (!dest->is_ssa) + list_del(&dest->reg.def_link); return true; } @@ -1834,64 +1813,77 @@ nir_srcs_equal(nir_src src1, nir_src src2) } static bool -src_does_not_use_def(nir_src *src, void *void_def) +src_is_valid(const nir_src *src) { - nir_ssa_def *def = void_def; - - if (src->is_ssa) { - return src->ssa != def; - } else { - return true; - } + return src->is_ssa ? (src->ssa != NULL) : (src->reg.reg != NULL); } -static bool -src_does_not_use_reg(nir_src *src, void *void_reg) +static void +src_remove_all_uses(nir_src *src) { - nir_register *reg = void_reg; + for (; src; src = src->is_ssa ? NULL : src->reg.indirect) { + if (!src_is_valid(src)) + continue; - if (src->is_ssa) { - return true; - } else { - return src->reg.reg != reg; + list_del(&src->use_link); + } +} + +static void +src_add_all_uses(nir_src *src, nir_instr *parent_instr, nir_if *parent_if) +{ + for (; src; src = src->is_ssa ? NULL : src->reg.indirect) { + if (!src_is_valid(src)) + continue; + + if (parent_instr) { + src->parent_instr = parent_instr; + if (src->is_ssa) + list_addtail(&src->use_link, &src->ssa->uses); + else + list_addtail(&src->use_link, &src->reg.reg->uses); + } else { + assert(parent_if); + src->parent_if = parent_if; + if (src->is_ssa) + list_addtail(&src->use_link, &src->ssa->if_uses); + else + list_addtail(&src->use_link, &src->reg.reg->if_uses); + } } } void nir_instr_rewrite_src(nir_instr *instr, nir_src *src, nir_src new_src) { - nir_src old_src = *src; + assert(!src_is_valid(src) || src->parent_instr == instr); + + src_remove_all_uses(src); *src = new_src; + src_add_all_uses(src, instr, NULL); +} - for (nir_src *iter_src = &old_src; iter_src; - iter_src = iter_src->is_ssa ? NULL : iter_src->reg.indirect) { - if (iter_src->is_ssa) { - nir_ssa_def *ssa = iter_src->ssa; - if (ssa && nir_foreach_src(instr, src_does_not_use_def, ssa)) { - struct set_entry *entry = _mesa_set_search(ssa->uses, instr); - assert(entry); - _mesa_set_remove(ssa->uses, entry); - } - } else { - nir_register *reg = iter_src->reg.reg; - if (reg && nir_foreach_src(instr, src_does_not_use_reg, reg)) { - struct set_entry *entry = _mesa_set_search(reg->uses, instr); - assert(entry); - _mesa_set_remove(reg->uses, entry); - } - } - } +void +nir_instr_move_src(nir_instr *dest_instr, nir_src *dest, nir_src *src) +{ + assert(!src_is_valid(dest) || dest->parent_instr == dest_instr); - for (nir_src *iter_src = &new_src; iter_src; - iter_src = iter_src->is_ssa ? NULL : iter_src->reg.indirect) { - if (iter_src->is_ssa) { - if (iter_src->ssa) - _mesa_set_add(iter_src->ssa->uses, instr); - } else { - if (iter_src->reg.reg) - _mesa_set_add(iter_src->reg.reg->uses, instr); - } - } + src_remove_all_uses(dest); + src_remove_all_uses(src); + *dest = *src; + *src = NIR_SRC_INIT; + src_add_all_uses(dest, dest_instr, NULL); +} + +void +nir_if_rewrite_condition(nir_if *if_stmt, nir_src new_src) +{ + nir_src *src = &if_stmt->condition; + assert(!src_is_valid(src) || src->parent_if == if_stmt); + + src_remove_all_uses(src); + *src = new_src; + src_add_all_uses(src, NULL, if_stmt); } void @@ -1900,10 +1892,8 @@ nir_ssa_def_init(nir_instr *instr, nir_ssa_def *def, { def->name = name; def->parent_instr = instr; - def->uses = _mesa_set_create(instr, _mesa_hash_pointer, - _mesa_key_pointer_equal); - def->if_uses = _mesa_set_create(instr, _mesa_hash_pointer, - _mesa_key_pointer_equal); + list_inithead(&def->uses); + list_inithead(&def->if_uses); def->num_components = num_components; if (instr->block) { @@ -1924,57 +1914,23 @@ nir_ssa_dest_init(nir_instr *instr, nir_dest *dest, nir_ssa_def_init(instr, &dest->ssa, num_components, name); } -struct ssa_def_rewrite_state { - void *mem_ctx; - nir_ssa_def *old; - nir_src new_src; -}; - -static bool -ssa_def_rewrite_uses_src(nir_src *src, void *void_state) -{ - struct ssa_def_rewrite_state *state = void_state; - - if (src->is_ssa && src->ssa == state->old) - nir_src_copy(src, &state->new_src, state->mem_ctx); - - return true; -} - void nir_ssa_def_rewrite_uses(nir_ssa_def *def, nir_src new_src, void *mem_ctx) { - struct ssa_def_rewrite_state state; - state.mem_ctx = mem_ctx; - state.old = def; - state.new_src = new_src; - assert(!new_src.is_ssa || def != new_src.ssa); - struct set *new_uses, *new_if_uses; - if (new_src.is_ssa) { - new_uses = new_src.ssa->uses; - new_if_uses = new_src.ssa->if_uses; - } else { - new_uses = new_src.reg.reg->uses; - new_if_uses = new_src.reg.reg->if_uses; - } - - struct set_entry *entry; - set_foreach(def->uses, entry) { - nir_instr *instr = (nir_instr *)entry->key; - - _mesa_set_remove(def->uses, entry); - nir_foreach_src(instr, ssa_def_rewrite_uses_src, &state); - _mesa_set_add(new_uses, instr); + nir_foreach_use_safe(def, use_src) { + nir_instr *src_parent_instr = use_src->parent_instr; + list_del(&use_src->use_link); + nir_src_copy(use_src, &new_src, mem_ctx); + src_add_all_uses(use_src, src_parent_instr, NULL); } - set_foreach(def->if_uses, entry) { - nir_if *if_use = (nir_if *)entry->key; - - _mesa_set_remove(def->if_uses, entry); - nir_src_copy(&if_use->condition, &new_src, mem_ctx); - _mesa_set_add(new_if_uses, if_use); + nir_foreach_if_use_safe(def, use_src) { + nir_if *src_parent_if = use_src->parent_if; + list_del(&use_src->use_link); + nir_src_copy(use_src, &new_src, mem_ctx); + src_add_all_uses(use_src, NULL, src_parent_if); } } diff --git a/mesalib/src/glsl/nir/nir.h b/mesalib/src/glsl/nir/nir.h index 98b0ec328..697d37e95 100644 --- a/mesalib/src/glsl/nir/nir.h +++ b/mesalib/src/glsl/nir/nir.h @@ -30,6 +30,7 @@ #include "util/hash_table.h" #include "../list.h" #include "GL/gl.h" /* GLenum */ +#include "util/list.h" #include "util/ralloc.h" #include "util/set.h" #include "util/bitset.h" @@ -397,13 +398,13 @@ typedef struct { struct nir_instr *parent_instr; /** set of nir_instr's where this register is used (read from) */ - struct set *uses; + struct list_head uses; /** set of nir_instr's where this register is defined (written to) */ - struct set *defs; + struct list_head defs; /** set of nir_if's where this register is used as a condition */ - struct set *if_uses; + struct list_head if_uses; } nir_register; typedef enum { @@ -462,10 +463,10 @@ typedef struct { nir_instr *parent_instr; /** set of nir_instr's where this register is used (read from) */ - struct set *uses; + struct list_head uses; /** set of nir_if's where this register is used as a condition */ - struct set *if_uses; + struct list_head if_uses; uint8_t num_components; } nir_ssa_def; @@ -481,6 +482,9 @@ typedef struct { } nir_reg_src; typedef struct { + nir_instr *parent_instr; + struct list_head def_link; + nir_register *reg; struct nir_src *indirect; /** < NULL for no indirect offset */ unsigned base_offset; @@ -488,8 +492,17 @@ typedef struct { /* TODO def-use chain goes here */ } nir_reg_dest; +struct nir_if; + typedef struct nir_src { union { + nir_instr *parent_instr; + struct nir_if *parent_if; + }; + + struct list_head use_link; + + union { nir_reg_src reg; nir_ssa_def *ssa; }; @@ -497,6 +510,20 @@ typedef struct nir_src { bool is_ssa; } nir_src; +#define NIR_SRC_INIT (nir_src) { { NULL } } + +#define nir_foreach_use(reg_or_ssa_def, src) \ + list_for_each_entry(nir_src, src, &(reg_or_ssa_def)->uses, use_link) + +#define nir_foreach_use_safe(reg_or_ssa_def, src) \ + list_for_each_entry_safe(nir_src, src, &(reg_or_ssa_def)->uses, use_link) + +#define nir_foreach_if_use(reg_or_ssa_def, src) \ + list_for_each_entry(nir_src, src, &(reg_or_ssa_def)->if_uses, use_link) + +#define nir_foreach_if_use_safe(reg_or_ssa_def, src) \ + list_for_each_entry_safe(nir_src, src, &(reg_or_ssa_def)->if_uses, use_link) + typedef struct { union { nir_reg_dest reg; @@ -506,10 +533,18 @@ typedef struct { bool is_ssa; } nir_dest; +#define NIR_DEST_INIT (nir_dest) { { { NULL } } } + +#define nir_foreach_def(reg, dest) \ + list_for_each_entry(nir_dest, dest, &(reg)->defs, reg.def_link) + +#define nir_foreach_def_safe(reg, dest) \ + list_for_each_entry_safe(nir_dest, dest, &(reg)->defs, reg.def_link) + static inline nir_src nir_src_for_ssa(nir_ssa_def *def) { - nir_src src; + nir_src src = NIR_SRC_INIT; src.is_ssa = true; src.ssa = def; @@ -520,7 +555,7 @@ nir_src_for_ssa(nir_ssa_def *def) static inline nir_src nir_src_for_reg(nir_register *reg) { - nir_src src; + nir_src src = NIR_SRC_INIT; src.is_ssa = false; src.reg.reg = reg; @@ -543,12 +578,9 @@ nir_src_get_parent_instr(const nir_src *src) static inline nir_dest nir_dest_for_reg(nir_register *reg) { - nir_dest dest; + nir_dest dest = NIR_DEST_INIT; - dest.is_ssa = false; dest.reg.reg = reg; - dest.reg.indirect = NULL; - dest.reg.base_offset = 0; return dest; } @@ -1207,7 +1239,7 @@ nir_block_last_instr(nir_block *block) #define nir_foreach_instr_safe(block, instr) \ foreach_list_typed_safe(nir_instr, instr, node, &(block)->instr_list) -typedef struct { +typedef struct nir_if { nir_cf_node cf_node; nir_src condition; @@ -1548,6 +1580,8 @@ bool nir_foreach_src(nir_instr *instr, nir_foreach_src_cb cb, void *state); nir_const_value *nir_src_as_const_value(nir_src src); bool nir_srcs_equal(nir_src src1, nir_src src2); void nir_instr_rewrite_src(nir_instr *instr, nir_src *src, nir_src new_src); +void nir_instr_move_src(nir_instr *dest_instr, nir_src *dest, nir_src *src); +void nir_if_rewrite_condition(nir_if *if_stmt, nir_src new_src); void nir_ssa_dest_init(nir_instr *instr, nir_dest *dest, unsigned num_components, const char *name); diff --git a/mesalib/src/glsl/nir/nir_builder.h b/mesalib/src/glsl/nir/nir_builder.h index d1419ee21..9223e8380 100644 --- a/mesalib/src/glsl/nir/nir_builder.h +++ b/mesalib/src/glsl/nir/nir_builder.h @@ -231,8 +231,7 @@ static inline nir_ssa_def * nir_swizzle(nir_builder *build, nir_ssa_def *src, unsigned swiz[4], unsigned num_components, bool use_fmov) { - nir_alu_src alu_src; - memset(&alu_src, 0, sizeof(alu_src)); + nir_alu_src alu_src = { NIR_SRC_INIT }; alu_src.src = nir_src_for_ssa(src); for (int i = 0; i < 4; i++) alu_src.swizzle[i] = swiz[i]; @@ -251,8 +250,7 @@ nir_ssa_for_src(nir_builder *build, nir_src src, int num_components) if (src.is_ssa && src.ssa->num_components == num_components) return src.ssa; - nir_alu_src alu; - memset(&alu, 0, sizeof(alu)); + nir_alu_src alu = { NIR_SRC_INIT }; alu.src = src; for (int j = 0; j < 4; j++) alu.swizzle[j] = j; diff --git a/mesalib/src/glsl/nir/nir_from_ssa.c b/mesalib/src/glsl/nir/nir_from_ssa.c index 6a3b141bd..67733e6da 100644 --- a/mesalib/src/glsl/nir/nir_from_ssa.c +++ b/mesalib/src/glsl/nir/nir_from_ssa.c @@ -37,7 +37,6 @@ struct from_ssa_state { void *mem_ctx; void *dead_ctx; - struct hash_table *ssa_table; struct hash_table *merge_node_table; nir_instr *instr; nir_function_impl *impl; @@ -344,45 +343,31 @@ isolate_phi_nodes_block(nir_block *block, void *void_state) get_parallel_copy_at_end_of_block(src->pred); assert(pcopy); - nir_parallel_copy_entry *entry = ralloc(state->dead_ctx, - nir_parallel_copy_entry); - exec_list_push_tail(&pcopy->entries, &entry->node); - - nir_src_copy(&entry->src, &src->src, state->dead_ctx); - _mesa_set_add(src->src.ssa->uses, &pcopy->instr); - + nir_parallel_copy_entry *entry = rzalloc(state->dead_ctx, + nir_parallel_copy_entry); nir_ssa_dest_init(&pcopy->instr, &entry->dest, phi->dest.ssa.num_components, src->src.ssa->name); + exec_list_push_tail(&pcopy->entries, &entry->node); - struct set_entry *use_entry = - _mesa_set_search(src->src.ssa->uses, instr); - if (use_entry) - /* It is possible that a phi node can use the same source twice - * but for different basic blocks. If that happens, entry will - * be NULL because we already deleted it. This is safe - * because, by the time the loop is done, we will have deleted - * all of the sources of the phi from their respective use sets - * and moved them to the parallel copy definitions. - */ - _mesa_set_remove(src->src.ssa->uses, use_entry); + assert(src->src.is_ssa); + nir_instr_rewrite_src(&pcopy->instr, &entry->src, src->src); - src->src.ssa = &entry->dest.ssa; - _mesa_set_add(entry->dest.ssa.uses, instr); + nir_instr_rewrite_src(&phi->instr, &src->src, + nir_src_for_ssa(&entry->dest.ssa)); } - nir_parallel_copy_entry *entry = ralloc(state->dead_ctx, - nir_parallel_copy_entry); - exec_list_push_tail(&block_pcopy->entries, &entry->node); - + nir_parallel_copy_entry *entry = rzalloc(state->dead_ctx, + nir_parallel_copy_entry); nir_ssa_dest_init(&block_pcopy->instr, &entry->dest, phi->dest.ssa.num_components, phi->dest.ssa.name); + exec_list_push_tail(&block_pcopy->entries, &entry->node); + nir_ssa_def_rewrite_uses(&phi->dest.ssa, nir_src_for_ssa(&entry->dest.ssa), state->mem_ctx); - entry->src.is_ssa = true; - entry->src.ssa = &phi->dest.ssa; - _mesa_set_add(phi->dest.ssa.uses, &block_pcopy->instr); + nir_instr_rewrite_src(&block_pcopy->instr, &entry->src, + nir_src_for_ssa(&phi->dest.ssa)); } return true; @@ -415,7 +400,7 @@ coalesce_phi_nodes_block(nir_block *block, void *void_state) } static void -agressive_coalesce_parallel_copy(nir_parallel_copy_instr *pcopy, +aggressive_coalesce_parallel_copy(nir_parallel_copy_instr *pcopy, struct from_ssa_state *state) { nir_foreach_parallel_copy_entry(pcopy, entry) { @@ -444,7 +429,7 @@ agressive_coalesce_parallel_copy(nir_parallel_copy_instr *pcopy, } static bool -agressive_coalesce_block(nir_block *block, void *void_state) +aggressive_coalesce_block(nir_block *block, void *void_state) { struct from_ssa_state *state = void_state; @@ -457,7 +442,7 @@ agressive_coalesce_block(nir_block *block, void *void_state) start_pcopy = nir_instr_as_parallel_copy(instr); - agressive_coalesce_parallel_copy(start_pcopy, state); + aggressive_coalesce_parallel_copy(start_pcopy, state); break; } @@ -467,17 +452,21 @@ agressive_coalesce_block(nir_block *block, void *void_state) get_parallel_copy_at_end_of_block(block); if (end_pcopy && end_pcopy != start_pcopy) - agressive_coalesce_parallel_copy(end_pcopy, state); + aggressive_coalesce_parallel_copy(end_pcopy, state); return true; } -static nir_register * -get_register_for_ssa_def(nir_ssa_def *def, struct from_ssa_state *state) +static bool +rewrite_ssa_def(nir_ssa_def *def, void *void_state) { + struct from_ssa_state *state = void_state; + nir_register *reg; + struct hash_entry *entry = _mesa_hash_table_search(state->merge_node_table, def); if (entry) { + /* In this case, we're part of a phi web. Use the web's register. */ merge_node *node = (merge_node *)entry->data; /* If it doesn't have a register yet, create one. Note that all of @@ -491,20 +480,15 @@ get_register_for_ssa_def(nir_ssa_def *def, struct from_ssa_state *state) node->set->reg->num_array_elems = 0; } - return node->set->reg; - } - - entry = _mesa_hash_table_search(state->ssa_table, def); - if (entry) { - return (nir_register *)entry->data; + reg = node->set->reg; } else { /* We leave load_const SSA values alone. They act as immediates to * the backend. If it got coalesced into a phi, that's ok. */ if (def->parent_instr->type == nir_instr_type_load_const) - return NULL; + return true; - nir_register *reg = nir_local_reg_create(state->impl); + reg = nir_local_reg_create(state->impl); reg->name = def->name; reg->num_components = def->num_components; reg->num_array_elems = 0; @@ -516,57 +500,24 @@ get_register_for_ssa_def(nir_ssa_def *def, struct from_ssa_state *state) */ if (def->parent_instr->type != nir_instr_type_ssa_undef) reg->parent_instr = def->parent_instr; - - _mesa_hash_table_insert(state->ssa_table, def, reg); - return reg; } -} - -static bool -rewrite_ssa_src(nir_src *src, void *void_state) -{ - struct from_ssa_state *state = void_state; - if (src->is_ssa) { - nir_register *reg = get_register_for_ssa_def(src->ssa, state); + nir_ssa_def_rewrite_uses(def, nir_src_for_reg(reg), state->mem_ctx); + assert(list_empty(&def->uses) && list_empty(&def->if_uses)); - if (reg == NULL) { - assert(src->ssa->parent_instr->type == nir_instr_type_load_const); - return true; - } - - memset(src, 0, sizeof *src); - src->reg.reg = reg; - - /* We don't need to remove it from the uses set because that is going - * away. We just need to add it to the one for the register. */ - _mesa_set_add(reg->uses, state->instr); - } - - return true; -} - -static bool -rewrite_ssa_dest(nir_dest *dest, void *void_state) -{ - struct from_ssa_state *state = void_state; - - if (dest->is_ssa) { - nir_register *reg = get_register_for_ssa_def(&dest->ssa, state); - - if (reg == NULL) { - assert(dest->ssa.parent_instr->type == nir_instr_type_load_const); - return true; - } + if (def->parent_instr->type == nir_instr_type_ssa_undef) + return true; - _mesa_set_destroy(dest->ssa.uses, NULL); - _mesa_set_destroy(dest->ssa.if_uses, NULL); + assert(def->parent_instr->type != nir_instr_type_load_const); - memset(dest, 0, sizeof *dest); - dest->reg.reg = reg; + /* At this point we know a priori that this SSA def is part of a + * nir_dest. We can use exec_node_data to get the dest pointer. + */ + nir_dest *dest = exec_node_data(nir_dest, def, ssa); - _mesa_set_add(reg->defs, state->instr); - } + *dest = nir_dest_for_reg(reg); + dest->reg.parent_instr = state->instr; + list_addtail(&dest->reg.def_link, ®->defs); return true; } @@ -581,8 +532,7 @@ resolve_registers_block(nir_block *block, void *void_state) nir_foreach_instr_safe(block, instr) { state->instr = instr; - nir_foreach_src(instr, rewrite_ssa_src, state); - nir_foreach_dest(instr, rewrite_ssa_dest, state); + nir_foreach_ssa_def(instr, rewrite_ssa_def, state); if (instr->type == nir_instr_type_ssa_undef || instr->type == nir_instr_type_phi) { @@ -592,23 +542,6 @@ resolve_registers_block(nir_block *block, void *void_state) } state->instr = NULL; - nir_if *following_if = nir_block_get_following_if(block); - if (following_if && following_if->condition.is_ssa) { - nir_register *reg = get_register_for_ssa_def(following_if->condition.ssa, - state); - if (reg) { - memset(&following_if->condition, 0, sizeof following_if->condition); - following_if->condition.reg.reg = reg; - - _mesa_set_add(reg->if_uses, following_if); - } else { - /* FIXME: We really shouldn't hit this. We should be doing - * constant control flow propagation. - */ - assert(following_if->condition.ssa->parent_instr->type == nir_instr_type_load_const); - } - } - return true; } @@ -853,10 +786,8 @@ nir_convert_from_ssa_impl(nir_function_impl *impl) nir_metadata_dominance); nir_foreach_block(impl, coalesce_phi_nodes_block, &state); - nir_foreach_block(impl, agressive_coalesce_block, &state); + nir_foreach_block(impl, aggressive_coalesce_block, &state); - state.ssa_table = _mesa_hash_table_create(NULL, _mesa_hash_pointer, - _mesa_key_pointer_equal); nir_foreach_block(impl, resolve_registers_block, &state); nir_foreach_block(impl, resolve_parallel_copies_block, &state); @@ -865,7 +796,6 @@ nir_convert_from_ssa_impl(nir_function_impl *impl) nir_metadata_dominance); /* Clean up dead instructions and the hash tables */ - _mesa_hash_table_destroy(state.ssa_table, NULL); _mesa_hash_table_destroy(state.merge_node_table, NULL); ralloc_free(state.dead_ctx); } diff --git a/mesalib/src/glsl/nir/nir_intrinsics.h b/mesalib/src/glsl/nir/nir_intrinsics.h index 8e28765c1..10192c531 100644 --- a/mesalib/src/glsl/nir/nir_intrinsics.h +++ b/mesalib/src/glsl/nir/nir_intrinsics.h @@ -68,6 +68,13 @@ INTRINSIC(interp_var_at_offset, 1, ARR(2), true, 0, 1, 0, #define BARRIER(name) INTRINSIC(name, 0, ARR(), false, 0, 0, 0, 0) BARRIER(discard) + +/* + * Memory barrier with semantics analogous to the memoryBarrier() GLSL + * intrinsic. + */ +BARRIER(memory_barrier) + /** A conditional discard, with a single boolean source. */ INTRINSIC(discard_if, 1, ARR(1), false, 0, 0, 0, 0) @@ -89,6 +96,33 @@ ATOMIC(inc, 0) ATOMIC(dec, 0) ATOMIC(read, NIR_INTRINSIC_CAN_ELIMINATE) +/* + * Image load, store and atomic intrinsics. + * + * All image intrinsics take an image target passed as a nir_variable. Image + * variables contain a number of memory and layout qualifiers that influence + * the semantics of the intrinsic. + * + * All image intrinsics take a four-coordinate vector and a sample index as + * first two sources, determining the location within the image that will be + * accessed by the intrinsic. Components not applicable to the image target + * in use are undefined. Image store takes an additional four-component + * argument with the value to be written, and image atomic operations take + * either one or two additional scalar arguments with the same meaning as in + * the ARB_shader_image_load_store specification. + */ +INTRINSIC(image_load, 2, ARR(4, 1), true, 4, 1, 0, + NIR_INTRINSIC_CAN_ELIMINATE) +INTRINSIC(image_store, 3, ARR(4, 1, 4), false, 0, 1, 0, 0) +INTRINSIC(image_atomic_add, 3, ARR(4, 1, 1), true, 1, 1, 0, 0) +INTRINSIC(image_atomic_min, 3, ARR(4, 1, 1), true, 1, 1, 0, 0) +INTRINSIC(image_atomic_max, 3, ARR(4, 1, 1), true, 1, 1, 0, 0) +INTRINSIC(image_atomic_and, 3, ARR(4, 1, 1), true, 1, 1, 0, 0) +INTRINSIC(image_atomic_or, 3, ARR(4, 1, 1), true, 1, 1, 0, 0) +INTRINSIC(image_atomic_xor, 3, ARR(4, 1, 1), true, 1, 1, 0, 0) +INTRINSIC(image_atomic_exchange, 3, ARR(4, 1, 1), true, 1, 1, 0, 0) +INTRINSIC(image_atomic_comp_swap, 4, ARR(4, 1, 1, 1), true, 1, 1, 0, 0) + #define SYSTEM_VALUE(name, components) \ INTRINSIC(load_##name, 0, ARR(), true, components, 0, 0, \ NIR_INTRINSIC_CAN_ELIMINATE | NIR_INTRINSIC_CAN_REORDER) diff --git a/mesalib/src/glsl/nir/nir_lower_atomics.c b/mesalib/src/glsl/nir/nir_lower_atomics.c index e82df0169..f6f89020f 100644 --- a/mesalib/src/glsl/nir/nir_lower_atomics.c +++ b/mesalib/src/glsl/nir/nir_lower_atomics.c @@ -78,7 +78,8 @@ lower_instr(nir_intrinsic_instr *instr, nir_function_impl *impl) nir_deref_as_array(instr->variables[0]->deref.child); assert(deref_array->deref.child == NULL); - offset_const->value.u[0] += deref_array->base_offset; + offset_const->value.u[0] += + deref_array->base_offset * ATOMIC_COUNTER_SIZE; if (deref_array->deref_array_type == nir_deref_array_type_indirect) { nir_load_const_instr *atomic_counter_size = diff --git a/mesalib/src/glsl/nir/nir_lower_locals_to_regs.c b/mesalib/src/glsl/nir/nir_lower_locals_to_regs.c index bc6a3d320..28fdec50e 100644 --- a/mesalib/src/glsl/nir/nir_lower_locals_to_regs.c +++ b/mesalib/src/glsl/nir/nir_lower_locals_to_regs.c @@ -269,18 +269,16 @@ lower_locals_to_regs_block(nir_block *block, void *void_state) static nir_block * compute_reg_usedef_lca(nir_register *reg) { - struct set_entry *entry; nir_block *lca = NULL; - set_foreach(reg->defs, entry) - lca = nir_dominance_lca(lca, ((nir_instr *)entry->key)->block); + list_for_each_entry(nir_dest, def_dest, ®->defs, reg.def_link) + lca = nir_dominance_lca(lca, def_dest->reg.parent_instr->block); - set_foreach(reg->uses, entry) - lca = nir_dominance_lca(lca, ((nir_instr *)entry->key)->block); + list_for_each_entry(nir_src, use_src, ®->uses, use_link) + lca = nir_dominance_lca(lca, use_src->parent_instr->block); - set_foreach(reg->if_uses, entry) { - nir_if *if_stmt = (nir_if *)entry->key; - nir_cf_node *prev_node = nir_cf_node_prev(&if_stmt->cf_node); + list_for_each_entry(nir_src, use_src, ®->if_uses, use_link) { + nir_cf_node *prev_node = nir_cf_node_prev(&use_src->parent_if->cf_node); assert(prev_node->type == nir_cf_node_block); lca = nir_dominance_lca(lca, nir_cf_node_as_block(prev_node)); } diff --git a/mesalib/src/glsl/nir/nir_lower_samplers.cpp b/mesalib/src/glsl/nir/nir_lower_samplers.cpp index cf8ab8325..7a0b0a09f 100644 --- a/mesalib/src/glsl/nir/nir_lower_samplers.cpp +++ b/mesalib/src/glsl/nir/nir_lower_samplers.cpp @@ -70,44 +70,45 @@ lower_sampler(nir_tex_instr *instr, const struct gl_shader_program *shader_progr case nir_deref_type_array: { nir_deref_array *deref_array = nir_deref_as_array(deref->child); + assert(deref_array->deref_array_type != nir_deref_array_type_wildcard); + + if (deref_array->deref.child) { + ralloc_asprintf_append(&name, "[%u]", + deref_array->deref_array_type == nir_deref_array_type_direct ? + deref_array->base_offset : 0); + } else { + assert(deref->child->type->base_type == GLSL_TYPE_SAMPLER); + instr->sampler_index = deref_array->base_offset; + } + /* XXX: We're assuming here that the indirect is the last array * thing we have. This should be ok for now as we don't support * arrays_of_arrays yet. */ - - instr->sampler_index *= glsl_get_length(deref->type); - switch (deref_array->deref_array_type) { - case nir_deref_array_type_direct: - instr->sampler_index += deref_array->base_offset; - if (deref_array->deref.child) - ralloc_asprintf_append(&name, "[%u]", deref_array->base_offset); - break; - case nir_deref_array_type_indirect: { - instr->src = reralloc(instr, instr->src, nir_tex_src, - instr->num_srcs + 1); - memset(&instr->src[instr->num_srcs], 0, sizeof *instr->src); + if (deref_array->deref_array_type == nir_deref_array_type_indirect) { + /* First, we have to resize the array of texture sources */ + nir_tex_src *new_srcs = rzalloc_array(instr, nir_tex_src, + instr->num_srcs + 1); + + for (unsigned i = 0; i < instr->num_srcs; i++) { + new_srcs[i].src_type = instr->src[i].src_type; + nir_instr_move_src(&instr->instr, &new_srcs[i].src, + &instr->src[i].src); + } + + ralloc_free(instr->src); + instr->src = new_srcs; + + /* Now we can go ahead and move the source over to being a + * first-class texture source. + */ instr->src[instr->num_srcs].src_type = nir_tex_src_sampler_offset; instr->num_srcs++; - - nir_instr_rewrite_src(&instr->instr, - &instr->src[instr->num_srcs - 1].src, - deref_array->indirect); + nir_instr_move_src(&instr->instr, + &instr->src[instr->num_srcs - 1].src, + &deref_array->indirect); instr->sampler_array_size = glsl_get_length(deref->type); - - nir_src empty; - memset(&empty, 0, sizeof empty); - nir_instr_rewrite_src(&instr->instr, &deref_array->indirect, empty); - - if (deref_array->deref.child) - ralloc_strcat(&name, "[0]"); - break; - } - - case nir_deref_array_type_wildcard: - unreachable("Cannot copy samplers"); - default: - unreachable("Invalid deref array type"); } break; } diff --git a/mesalib/src/glsl/nir/nir_lower_tex_projector.c b/mesalib/src/glsl/nir/nir_lower_tex_projector.c index 6b0e9c340..357131cd7 100644 --- a/mesalib/src/glsl/nir/nir_lower_tex_projector.c +++ b/mesalib/src/glsl/nir/nir_lower_tex_projector.c @@ -109,12 +109,12 @@ nir_lower_tex_projector_block(nir_block *block, void *void_state) /* Now move the later tex sources down the array so that the projector * disappears. */ - nir_src dead; - memset(&dead, 0, sizeof dead); - nir_instr_rewrite_src(&tex->instr, &tex->src[proj_index].src, dead); - memmove(&tex->src[proj_index], - &tex->src[proj_index + 1], - (tex->num_srcs - proj_index) * sizeof(*tex->src)); + nir_instr_rewrite_src(&tex->instr, &tex->src[proj_index].src, + NIR_SRC_INIT); + for (int i = proj_index + 1; i < tex->num_srcs; i++) { + tex->src[i-1].src_type = tex->src[i].src_type; + nir_instr_move_src(&tex->instr, &tex->src[i-1].src, &tex->src[i].src); + } tex->num_srcs--; } diff --git a/mesalib/src/glsl/nir/nir_lower_to_source_mods.c b/mesalib/src/glsl/nir/nir_lower_to_source_mods.c index 7b4a0f657..94c7e36d4 100644 --- a/mesalib/src/glsl/nir/nir_lower_to_source_mods.c +++ b/mesalib/src/glsl/nir/nir_lower_to_source_mods.c @@ -88,8 +88,8 @@ nir_lower_to_source_mods_block(nir_block *block, void *state) alu->src[i].swizzle[j] = parent->src[0].swizzle[alu->src[i].swizzle[j]]; } - if (parent->dest.dest.ssa.uses->entries == 0 && - parent->dest.dest.ssa.if_uses->entries == 0) + if (list_empty(&parent->dest.dest.ssa.uses) && + list_empty(&parent->dest.dest.ssa.if_uses)) nir_instr_remove(&parent->instr); } @@ -131,13 +131,13 @@ nir_lower_to_source_mods_block(nir_block *block, void *state) if (nir_op_infos[alu->op].output_type != nir_type_float) continue; - if (alu->dest.dest.ssa.if_uses->entries != 0) + if (!list_empty(&alu->dest.dest.ssa.if_uses)) continue; bool all_children_are_sat = true; - struct set_entry *entry; - set_foreach(alu->dest.dest.ssa.uses, entry) { - const nir_instr *child = entry->key; + nir_foreach_use(&alu->dest.dest.ssa, child_src) { + assert(child_src->is_ssa); + nir_instr *child = child_src->parent_instr; if (child->type != nir_instr_type_alu) { all_children_are_sat = false; continue; @@ -161,8 +161,12 @@ nir_lower_to_source_mods_block(nir_block *block, void *state) alu->dest.saturate = true; - set_foreach(alu->dest.dest.ssa.uses, entry) { - nir_alu_instr *child_alu = nir_instr_as_alu((nir_instr *)entry->key); + nir_foreach_use(&alu->dest.dest.ssa, child_src) { + assert(child_src->is_ssa); + nir_instr *child = child_src->parent_instr; + assert(child->type == nir_instr_type_alu); + nir_alu_instr *child_alu = nir_instr_as_alu(child); + child_alu->op = nir_op_fmov; child_alu->dest.saturate = false; /* We could propagate the dest of our instruction to the diff --git a/mesalib/src/glsl/nir/nir_lower_vars_to_ssa.c b/mesalib/src/glsl/nir/nir_lower_vars_to_ssa.c index bb60f4601..ccb8f99df 100644 --- a/mesalib/src/glsl/nir/nir_lower_vars_to_ssa.c +++ b/mesalib/src/glsl/nir/nir_lower_vars_to_ssa.c @@ -567,10 +567,11 @@ add_phi_sources(nir_block *block, nir_block *pred, nir_phi_src *src = ralloc(phi, nir_phi_src); src->pred = pred; + src->src.parent_instr = &phi->instr; src->src.is_ssa = true; src->src.ssa = get_ssa_def_for_block(node, pred, state); - _mesa_set_add(src->src.ssa->uses, instr); + list_addtail(&src->src.use_link, &src->src.ssa->uses); exec_list_push_tail(&phi->srcs, &src->node); } diff --git a/mesalib/src/glsl/nir/nir_opcodes.py b/mesalib/src/glsl/nir/nir_opcodes.py index 264806f5d..56e96d912 100644 --- a/mesalib/src/glsl/nir/nir_opcodes.py +++ b/mesalib/src/glsl/nir/nir_opcodes.py @@ -153,8 +153,6 @@ unop("fsat", tfloat, "(src0 > 1.0f) ? 1.0f : ((src0 <= 0.0f) ? 0.0f : src0)") unop("frcp", tfloat, "1.0f / src0") unop("frsq", tfloat, "1.0f / sqrtf(src0)") unop("fsqrt", tfloat, "sqrtf(src0)") -unop("fexp", tfloat, "expf(src0)") # < e^x -unop("flog", tfloat, "logf(src0)") # log base e unop("fexp2", tfloat, "exp2f(src0)") unop("flog2", tfloat, "log2f(src0)") unop_convert("f2i", tfloat, tint, "src0") # Float-to-integer conversion. diff --git a/mesalib/src/glsl/nir/nir_opt_algebraic.py b/mesalib/src/glsl/nir/nir_opt_algebraic.py index 2a2b9561e..fa039222f 100644 --- a/mesalib/src/glsl/nir/nir_opt_algebraic.py +++ b/mesalib/src/glsl/nir/nir_opt_algebraic.py @@ -83,24 +83,37 @@ optimizations = [ # Comparison simplifications (('inot', ('flt', a, b)), ('fge', a, b)), (('inot', ('fge', a, b)), ('flt', a, b)), + (('inot', ('feq', a, b)), ('fne', a, b)), + (('inot', ('fne', a, b)), ('feq', a, b)), (('inot', ('ilt', a, b)), ('ige', a, b)), (('inot', ('ige', a, b)), ('ilt', a, b)), + (('inot', ('ieq', a, b)), ('ine', a, b)), + (('inot', ('ine', a, b)), ('ieq', a, b)), (('fge', ('fneg', ('fabs', a)), 0.0), ('feq', a, 0.0)), (('bcsel', ('flt', a, b), a, b), ('fmin', a, b)), (('bcsel', ('flt', a, b), b, a), ('fmax', a, b)), (('bcsel', ('inot', 'a@bool'), b, c), ('bcsel', a, c, b)), (('bcsel', a, ('bcsel', a, b, c), d), ('bcsel', a, b, d)), + (('fmin', a, a), a), + (('fmax', a, a), a), + (('imin', a, a), a), + (('imax', a, a), a), + (('umin', a, a), a), + (('umax', a, a), a), (('fmin', ('fmax', a, 0.0), 1.0), ('fsat', a), '!options->lower_fsat'), (('fsat', a), ('fmin', ('fmax', a, 0.0), 1.0), 'options->lower_fsat'), (('fsat', ('fsat', a)), ('fsat', a)), (('fmin', ('fmax', ('fmin', ('fmax', a, 0.0), 1.0), 0.0), 1.0), ('fmin', ('fmax', a, 0.0), 1.0)), (('ior', ('flt', a, b), ('flt', a, c)), ('flt', a, ('fmax', b, c))), + (('ior', ('flt', a, c), ('flt', b, c)), ('flt', ('fmin', a, b), c)), (('ior', ('fge', a, b), ('fge', a, c)), ('fge', a, ('fmin', b, c))), + (('ior', ('fge', a, c), ('fge', b, c)), ('fge', ('fmax', a, b), c)), (('slt', a, b), ('b2f', ('flt', a, b)), 'options->lower_scmp'), (('sge', a, b), ('b2f', ('fge', a, b)), 'options->lower_scmp'), (('seq', a, b), ('b2f', ('feq', a, b)), 'options->lower_scmp'), (('sne', a, b), ('b2f', ('fne', a, b)), 'options->lower_scmp'), # Emulating booleans + (('imul', ('b2i', a), ('b2i', b)), ('b2i', ('iand', a, b))), (('fmul', ('b2f', a), ('b2f', b)), ('b2f', ('iand', a, b))), (('fsat', ('fadd', ('b2f', a), ('b2f', b))), ('b2f', ('ior', a, b))), (('iand', 'a@bool', 1.0), ('b2f', a)), @@ -136,36 +149,23 @@ optimizations = [ (('ushr', a, 0), a), # Exponential/logarithmic identities (('fexp2', ('flog2', a)), a), # 2^lg2(a) = a - (('fexp', ('flog', a)), a), # e^ln(a) = a (('flog2', ('fexp2', a)), a), # lg2(2^a) = a - (('flog', ('fexp', a)), a), # ln(e^a) = a (('fpow', a, b), ('fexp2', ('fmul', ('flog2', a), b)), 'options->lower_fpow'), # a^b = 2^(lg2(a)*b) (('fexp2', ('fmul', ('flog2', a), b)), ('fpow', a, b), '!options->lower_fpow'), # 2^(lg2(a)*b) = a^b - (('fexp', ('fmul', ('flog', a), b)), ('fpow', a, b), '!options->lower_fpow'), # e^(ln(a)*b) = a^b (('fpow', a, 1.0), a), (('fpow', a, 2.0), ('fmul', a, a)), (('fpow', a, 4.0), ('fmul', ('fmul', a, a), ('fmul', a, a))), (('fpow', 2.0, a), ('fexp2', a)), (('fsqrt', ('fexp2', a)), ('fexp2', ('fmul', 0.5, a))), - (('fsqrt', ('fexp', a)), ('fexp', ('fmul', 0.5, a))), (('frcp', ('fexp2', a)), ('fexp2', ('fneg', a))), - (('frcp', ('fexp', a)), ('fexp', ('fneg', a))), (('frsq', ('fexp2', a)), ('fexp2', ('fmul', -0.5, a))), - (('frsq', ('fexp', a)), ('fexp', ('fmul', -0.5, a))), (('flog2', ('fsqrt', a)), ('fmul', 0.5, ('flog2', a))), - (('flog', ('fsqrt', a)), ('fmul', 0.5, ('flog', a))), (('flog2', ('frcp', a)), ('fneg', ('flog2', a))), - (('flog', ('frcp', a)), ('fneg', ('flog', a))), (('flog2', ('frsq', a)), ('fmul', -0.5, ('flog2', a))), - (('flog', ('frsq', a)), ('fmul', -0.5, ('flog', a))), (('flog2', ('fpow', a, b)), ('fmul', b, ('flog2', a))), - (('flog', ('fpow', a, b)), ('fmul', b, ('flog', a))), (('fadd', ('flog2', a), ('flog2', b)), ('flog2', ('fmul', a, b))), - (('fadd', ('flog', a), ('flog', b)), ('flog', ('fmul', a, b))), (('fadd', ('flog2', a), ('fneg', ('flog2', b))), ('flog2', ('fdiv', a, b))), - (('fadd', ('flog', a), ('fneg', ('flog', b))), ('flog', ('fdiv', a, b))), (('fmul', ('fexp2', a), ('fexp2', b)), ('fexp2', ('fadd', a, b))), - (('fmul', ('fexp', a), ('fexp', b)), ('fexp', ('fadd', a, b))), # Division and reciprocal (('fdiv', 1.0, a), ('frcp', a)), (('frcp', ('frcp', a)), a), @@ -187,6 +187,7 @@ optimizations = [ (('fcsel', a, b, b), b), # Conversions + (('i2b', ('b2i', a)), a), (('f2i', ('ftrunc', a)), ('f2i', a)), (('f2u', ('ftrunc', a)), ('f2u', a)), diff --git a/mesalib/src/glsl/nir/nir_opt_copy_propagate.c b/mesalib/src/glsl/nir/nir_opt_copy_propagate.c index ee78e5aa0..71367d001 100644 --- a/mesalib/src/glsl/nir/nir_opt_copy_propagate.c +++ b/mesalib/src/glsl/nir/nir_opt_copy_propagate.c @@ -93,62 +93,6 @@ is_swizzleless_move(nir_alu_instr *instr) } } -typedef struct { - nir_ssa_def *def; - bool found; -} search_def_state; - -static bool -search_def(nir_src *src, void *_state) -{ - search_def_state *state = (search_def_state *) _state; - - if (src->is_ssa && src->ssa == state->def) - state->found = true; - - return true; -} - -static void -rewrite_src_instr(nir_src *src, nir_ssa_def *new_def, nir_instr *parent_instr) -{ - nir_ssa_def *old_def = src->ssa; - - src->ssa = new_def; - - /* - * The instruction could still use the old definition in one of its other - * sources, so only remove the instruction from the uses if there are no - * more uses left. - */ - - search_def_state search_state; - search_state.def = old_def; - search_state.found = false; - nir_foreach_src(parent_instr, search_def, &search_state); - if (!search_state.found) { - struct set_entry *entry = _mesa_set_search(old_def->uses, parent_instr); - assert(entry); - _mesa_set_remove(old_def->uses, entry); - } - - _mesa_set_add(new_def->uses, parent_instr); -} - -static void -rewrite_src_if(nir_if *if_stmt, nir_ssa_def *new_def) -{ - nir_ssa_def *old_def = if_stmt->condition.ssa; - - if_stmt->condition.ssa = new_def; - - struct set_entry *entry = _mesa_set_search(old_def->if_uses, if_stmt); - assert(entry); - _mesa_set_remove(old_def->if_uses, entry); - - _mesa_set_add(new_def->if_uses, if_stmt); -} - static bool copy_prop_src(nir_src *src, nir_instr *parent_instr, nir_if *parent_if) { @@ -178,10 +122,14 @@ copy_prop_src(nir_src *src, nir_instr *parent_instr, nir_if *parent_if) return false; } - if (parent_instr) - rewrite_src_instr(src, alu_instr->src[0].src.ssa, parent_instr); - else - rewrite_src_if(parent_if, alu_instr->src[0].src.ssa); + if (parent_instr) { + nir_instr_rewrite_src(parent_instr, src, + nir_src_for_ssa(alu_instr->src[0].src.ssa)); + } else { + assert(src == &parent_if->condition); + nir_if_rewrite_condition(parent_if, + nir_src_for_ssa(alu_instr->src[0].src.ssa)); + } return true; } @@ -234,7 +182,8 @@ copy_prop_alu_src(nir_alu_instr *parent_alu_instr, unsigned index) for (unsigned i = 0; i < 4; i++) src->swizzle[i] = new_swizzle[i]; - rewrite_src_instr(&src->src, def, &parent_alu_instr->instr); + nir_instr_rewrite_src(&parent_alu_instr->instr, &src->src, + nir_src_for_ssa(def)); return true; } diff --git a/mesalib/src/glsl/nir/nir_opt_gcm.c b/mesalib/src/glsl/nir/nir_opt_gcm.c index b4f5fd3d5..44068bf37 100644 --- a/mesalib/src/glsl/nir/nir_opt_gcm.c +++ b/mesalib/src/glsl/nir/nir_opt_gcm.c @@ -279,9 +279,8 @@ gcm_schedule_late_def(nir_ssa_def *def, void *void_state) nir_block *lca = NULL; - struct set_entry *entry; - set_foreach(def->uses, entry) { - nir_instr *use_instr = (nir_instr *)entry->key; + nir_foreach_use(def, use_src) { + nir_instr *use_instr = use_src->parent_instr; gcm_schedule_late_instr(use_instr, state); @@ -304,8 +303,8 @@ gcm_schedule_late_def(nir_ssa_def *def, void *void_state) } } - set_foreach(def->if_uses, entry) { - nir_if *if_stmt = (nir_if *)entry->key; + nir_foreach_if_use(def, use_src) { + nir_if *if_stmt = use_src->parent_if; /* For if statements, we consider the block to be the one immediately * preceding the if CF node. @@ -377,9 +376,8 @@ gcm_place_instr(nir_instr *instr, struct gcm_state *state); static bool gcm_place_instr_def(nir_ssa_def *def, void *state) { - struct set_entry *entry; - set_foreach(def->uses, entry) - gcm_place_instr((nir_instr *)entry->key, state); + nir_foreach_use(def, use_src) + gcm_place_instr(use_src->parent_instr, state); return false; } diff --git a/mesalib/src/glsl/nir/nir_opt_global_to_local.c b/mesalib/src/glsl/nir/nir_opt_global_to_local.c index 00db37ba7..bccb45b62 100644 --- a/mesalib/src/glsl/nir/nir_opt_global_to_local.c +++ b/mesalib/src/glsl/nir/nir_opt_global_to_local.c @@ -34,9 +34,8 @@ global_to_local(nir_register *reg) assert(reg->is_global); - struct set_entry *entry; - set_foreach(reg->defs, entry) { - nir_instr *instr = (nir_instr *) entry->key; + nir_foreach_def(reg, def_dest) { + nir_instr *instr = def_dest->reg.parent_instr; nir_function_impl *instr_impl = nir_cf_node_get_function(&instr->block->cf_node); if (impl != NULL) { @@ -47,8 +46,8 @@ global_to_local(nir_register *reg) } } - set_foreach(reg->uses, entry) { - nir_instr *instr = (nir_instr *) entry->key; + nir_foreach_use(reg, use_src) { + nir_instr *instr = use_src->parent_instr; nir_function_impl *instr_impl = nir_cf_node_get_function(&instr->block->cf_node); if (impl != NULL) { @@ -59,8 +58,8 @@ global_to_local(nir_register *reg) } } - set_foreach(reg->if_uses, entry) { - nir_if *if_stmt = (nir_if *) entry->key; + nir_foreach_if_use(reg, use_src) { + nir_if *if_stmt = use_src->parent_if; nir_function_impl *if_impl = nir_cf_node_get_function(&if_stmt->cf_node); if (impl != NULL) { if (impl != if_impl) diff --git a/mesalib/src/glsl/nir/nir_opt_peephole_ffma.c b/mesalib/src/glsl/nir/nir_opt_peephole_ffma.c index 9d5646fe6..b430eac8e 100644 --- a/mesalib/src/glsl/nir/nir_opt_peephole_ffma.c +++ b/mesalib/src/glsl/nir/nir_opt_peephole_ffma.c @@ -41,12 +41,11 @@ struct peephole_ffma_state { static inline bool are_all_uses_fadd(nir_ssa_def *def) { - if (def->if_uses->entries > 0) + if (!list_empty(&def->if_uses)) return false; - struct set_entry *use_iter; - set_foreach(def->uses, use_iter) { - nir_instr *use_instr = (nir_instr *)use_iter->key; + nir_foreach_use(def, use_src) { + nir_instr *use_instr = use_src->parent_instr; if (use_instr->type != nir_instr_type_alu) return false; @@ -220,7 +219,7 @@ nir_opt_peephole_ffma_block(nir_block *block, void *void_state) state->mem_ctx); nir_instr_insert_before(&add->instr, &ffma->instr); - assert(add->dest.dest.ssa.uses->entries == 0); + assert(list_empty(&add->dest.dest.ssa.uses)); nir_instr_remove(&add->instr); state->progress = true; diff --git a/mesalib/src/glsl/nir/nir_opt_peephole_select.c b/mesalib/src/glsl/nir/nir_opt_peephole_select.c index f400cfd66..82c65bb44 100644 --- a/mesalib/src/glsl/nir/nir_opt_peephole_select.c +++ b/mesalib/src/glsl/nir/nir_opt_peephole_select.c @@ -98,15 +98,13 @@ block_check_for_allowed_instrs(nir_block *block) return false; /* It cannot have any if-uses */ - if (mov->dest.dest.ssa.if_uses->entries != 0) + if (!list_empty(&mov->dest.dest.ssa.if_uses)) return false; /* The only uses of this definition must be phi's in the successor */ - struct set_entry *entry; - set_foreach(mov->dest.dest.ssa.uses, entry) { - const nir_instr *dest_instr = entry->key; - if (dest_instr->type != nir_instr_type_phi || - dest_instr->block != block->successors[0]) + nir_foreach_use(&mov->dest.dest.ssa, use) { + if (use->parent_instr->type != nir_instr_type_phi || + use->parent_instr->block != block->successors[0]) return false; } break; diff --git a/mesalib/src/glsl/nir/nir_search.c b/mesalib/src/glsl/nir/nir_search.c index 5ba016085..0c4e48ce9 100644 --- a/mesalib/src/glsl/nir/nir_search.c +++ b/mesalib/src/glsl/nir/nir_search.c @@ -73,6 +73,14 @@ match_value(const nir_search_value *value, nir_alu_instr *instr, unsigned src, { uint8_t new_swizzle[4]; + /* If the source is an explicitly sized source, then we need to reset + * both the number of components and the swizzle. + */ + if (nir_op_infos[instr->op].input_sizes[src] != 0) { + num_components = nir_op_infos[instr->op].input_sizes[src]; + swizzle = identity_swizzle; + } + for (int i = 0; i < num_components; ++i) new_swizzle[i] = instr->src[src].swizzle[swizzle[i]]; @@ -90,6 +98,7 @@ match_value(const nir_search_value *value, nir_alu_instr *instr, unsigned src, case nir_search_value_variable: { nir_search_variable *var = nir_search_value_as_variable(value); + assert(var->variable < NIR_SEARCH_MAX_VARIABLES); if (state->variables_seen & (1 << var->variable)) { if (!nir_srcs_equal(state->variables[var->variable].src, @@ -198,16 +207,13 @@ match_expression(const nir_search_expression *expr, nir_alu_instr *instr, } } + /* Stash off the current variables_seen bitmask. This way we can + * restore it prior to matching in the commutative case below. + */ + unsigned variables_seen_stash = state->variables_seen; + bool matched = true; for (unsigned i = 0; i < nir_op_infos[instr->op].num_inputs; i++) { - /* If the source is an explicitly sized source, then we need to reset - * both the number of components and the swizzle. - */ - if (nir_op_infos[instr->op].input_sizes[i] != 0) { - num_components = nir_op_infos[instr->op].input_sizes[i]; - swizzle = identity_swizzle; - } - if (!match_value(expr->srcs[i], instr, i, num_components, swizzle, state)) { matched = false; @@ -220,6 +226,13 @@ match_expression(const nir_search_expression *expr, nir_alu_instr *instr, if (nir_op_infos[instr->op].algebraic_properties & NIR_OP_IS_COMMUTATIVE) { assert(nir_op_infos[instr->op].num_inputs == 2); + + /* Restore the variables_seen bitmask. If we don't do this, then we + * could end up with an erroneous failure due to variables found in the + * first match attempt above not matching those in the second. + */ + state->variables_seen = variables_seen_stash; + if (!match_value(expr->srcs[0], instr, 1, num_components, swizzle, state)) return false; @@ -276,7 +289,7 @@ construct_value(const nir_search_value *value, nir_alu_type type, const nir_search_variable *var = nir_search_value_as_variable(value); assert(state->variables_seen & (1 << var->variable)); - nir_alu_src val; + nir_alu_src val = { NIR_SRC_INIT }; nir_alu_src_copy(&val, &state->variables[var->variable], mem_ctx); assert(!var->is_constant); diff --git a/mesalib/src/glsl/nir/nir_to_ssa.c b/mesalib/src/glsl/nir/nir_to_ssa.c index 53ff54766..a3c35fa04 100644 --- a/mesalib/src/glsl/nir/nir_to_ssa.c +++ b/mesalib/src/glsl/nir/nir_to_ssa.c @@ -89,9 +89,8 @@ insert_phi_nodes(nir_function_impl *impl) w_start = w_end = 0; iter_count++; - struct set_entry *entry; - set_foreach(reg->defs, entry) { - nir_instr *def = (nir_instr *) entry->key; + nir_foreach_def(reg, dest) { + nir_instr *def = dest->reg.parent_instr; if (work[def->block->index] < iter_count) W[w_end++] = def->block; work[def->block->index] = iter_count; @@ -99,6 +98,7 @@ insert_phi_nodes(nir_function_impl *impl) while (w_start != w_end) { nir_block *cur = W[w_start++]; + struct set_entry *entry; set_foreach(cur->dom_frontier, entry) { nir_block *next = (nir_block *) entry->key; @@ -190,13 +190,12 @@ rewrite_use(nir_src *src, void *_state) if (state->states[index].stack == NULL) return true; - src->is_ssa = true; - src->ssa = get_ssa_src(src->reg.reg, state); - + nir_ssa_def *def = get_ssa_src(src->reg.reg, state); if (state->parent_instr) - _mesa_set_add(src->ssa->uses, state->parent_instr); + nir_instr_rewrite_src(state->parent_instr, src, nir_src_for_ssa(def)); else - _mesa_set_add(src->ssa->if_uses, state->parent_if); + nir_if_rewrite_condition(state->parent_if, nir_src_for_ssa(def)); + return true; } @@ -219,6 +218,7 @@ rewrite_def_forwards(nir_dest *dest, void *_state) name = ralloc_asprintf(state->mem_ctx, "%s_%u", dest->reg.reg->name, state->states[index].num_defs); + list_del(&dest->reg.def_link); nir_ssa_dest_init(state->parent_instr, dest, reg->num_components, name); /* push our SSA destination on the stack */ @@ -270,6 +270,7 @@ rewrite_alu_instr_forward(nir_alu_instr *instr, rewrite_state *state) reg->name, state->states[index].num_defs); instr->dest.write_mask = (1 << num_components) - 1; + list_del(&instr->dest.dest.reg.def_link); nir_ssa_dest_init(&instr->instr, &instr->dest.dest, num_components, name); if (nir_op_infos[instr->op].output_size == 0) { @@ -484,7 +485,7 @@ init_rewrite_state(nir_function_impl *impl, rewrite_state *state) * called after phi nodes are inserted so we can count phi node * definitions too. */ - unsigned stack_size = reg->defs->entries; + unsigned stack_size = list_length(®->defs); state->states[reg->index].stack = ralloc_array(state->states, nir_ssa_def *, diff --git a/mesalib/src/glsl/nir/nir_validate.c b/mesalib/src/glsl/nir/nir_validate.c index a7aa79837..da92ed904 100644 --- a/mesalib/src/glsl/nir/nir_validate.c +++ b/mesalib/src/glsl/nir/nir_validate.c @@ -97,50 +97,47 @@ typedef struct { static void validate_src(nir_src *src, validate_state *state); static void -validate_reg_src(nir_reg_src *src, validate_state *state) +validate_reg_src(nir_src *src, validate_state *state) { - assert(src->reg != NULL); + assert(src->reg.reg != NULL); struct hash_entry *entry; - entry = _mesa_hash_table_search(state->regs, src->reg); + entry = _mesa_hash_table_search(state->regs, src->reg.reg); assert(entry); reg_validate_state *reg_state = (reg_validate_state *) entry->data; if (state->instr) { - _mesa_set_add(reg_state->uses, state->instr); - - assert(_mesa_set_search(src->reg->uses, state->instr)); + _mesa_set_add(reg_state->uses, src); } else { assert(state->if_stmt); - _mesa_set_add(reg_state->if_uses, state->if_stmt); - - assert(_mesa_set_search(src->reg->if_uses, state->if_stmt)); + _mesa_set_add(reg_state->if_uses, src); } - if (!src->reg->is_global) { + if (!src->reg.reg->is_global) { assert(reg_state->where_defined == state->impl && "using a register declared in a different function"); } - assert((src->reg->num_array_elems == 0 || - src->base_offset < src->reg->num_array_elems) && + assert((src->reg.reg->num_array_elems == 0 || + src->reg.base_offset < src->reg.reg->num_array_elems) && "definitely out-of-bounds array access"); - if (src->indirect) { - assert(src->reg->num_array_elems != 0); - assert((src->indirect->is_ssa || src->indirect->reg.indirect == NULL) && + if (src->reg.indirect) { + assert(src->reg.reg->num_array_elems != 0); + assert((src->reg.indirect->is_ssa || + src->reg.indirect->reg.indirect == NULL) && "only one level of indirection allowed"); - validate_src(src->indirect, state); + validate_src(src->reg.indirect, state); } } static void -validate_ssa_src(nir_ssa_def *def, validate_state *state) +validate_ssa_src(nir_src *src, validate_state *state) { - assert(def != NULL); + assert(src->ssa != NULL); - struct hash_entry *entry = _mesa_hash_table_search(state->ssa_defs, def); + struct hash_entry *entry = _mesa_hash_table_search(state->ssa_defs, src->ssa); assert(entry); @@ -150,14 +147,10 @@ validate_ssa_src(nir_ssa_def *def, validate_state *state) "using an SSA value defined in a different function"); if (state->instr) { - _mesa_set_add(def_state->uses, state->instr); - - assert(_mesa_set_search(def->uses, state->instr)); + _mesa_set_add(def_state->uses, src); } else { assert(state->if_stmt); - _mesa_set_add(def_state->if_uses, state->if_stmt); - - assert(_mesa_set_search(def->if_uses, state->if_stmt)); + _mesa_set_add(def_state->if_uses, src); } /* TODO validate that the use is dominated by the definition */ @@ -166,10 +159,15 @@ validate_ssa_src(nir_ssa_def *def, validate_state *state) static void validate_src(nir_src *src, validate_state *state) { + if (state->instr) + assert(src->parent_instr == state->instr); + else + assert(src->parent_if == state->if_stmt); + if (src->is_ssa) - validate_ssa_src(src->ssa, state); + validate_ssa_src(src, state); else - validate_reg_src(&src->reg, state); + validate_reg_src(src, state); } static void @@ -201,8 +199,7 @@ validate_reg_dest(nir_reg_dest *dest, validate_state *state) { assert(dest->reg != NULL); - struct set_entry *entry = _mesa_set_search(dest->reg->defs, state->instr); - assert(entry && "definition not in nir_register.defs"); + assert(dest->parent_instr == state->instr); struct hash_entry *entry2; entry2 = _mesa_hash_table_search(state->regs, dest->reg); @@ -210,7 +207,7 @@ validate_reg_dest(nir_reg_dest *dest, validate_state *state) assert(entry2); reg_validate_state *reg_state = (reg_validate_state *) entry2->data; - _mesa_set_add(reg_state->defs, state->instr); + _mesa_set_add(reg_state->defs, dest); if (!dest->reg->is_global) { assert(reg_state->where_defined == state->impl && @@ -236,8 +233,13 @@ validate_ssa_def(nir_ssa_def *def, validate_state *state) assert(!BITSET_TEST(state->ssa_defs_found, def->index)); BITSET_SET(state->ssa_defs_found, def->index); + assert(def->parent_instr == state->instr); + assert(def->num_components <= 4); + list_validate(&def->uses); + list_validate(&def->if_uses); + ssa_def_validate_state *def_state = ralloc(state->ssa_defs, ssa_def_validate_state); def_state->where_defined = state->impl; @@ -699,6 +701,10 @@ prevalidate_reg_decl(nir_register *reg, bool is_global, validate_state *state) assert(!BITSET_TEST(state->regs_found, reg->index)); BITSET_SET(state->regs_found, reg->index); + list_validate(®->uses); + list_validate(®->defs); + list_validate(®->if_uses); + reg_validate_state *reg_state = ralloc(state->regs, reg_validate_state); reg_state->uses = _mesa_set_create(reg_state, _mesa_hash_pointer, _mesa_key_pointer_equal); @@ -719,47 +725,47 @@ postvalidate_reg_decl(nir_register *reg, validate_state *state) reg_validate_state *reg_state = (reg_validate_state *) entry->data; - if (reg_state->uses->entries != reg->uses->entries) { + nir_foreach_use(reg, src) { + struct set_entry *entry = _mesa_set_search(reg_state->uses, src); + assert(entry); + _mesa_set_remove(reg_state->uses, entry); + } + + if (reg_state->uses->entries != 0) { printf("extra entries in register uses:\n"); struct set_entry *entry; - set_foreach(reg->uses, entry) { - struct set_entry *entry2 = - _mesa_set_search(reg_state->uses, entry->key); - - if (entry2 == NULL) { - printf("%p\n", entry->key); - } - } + set_foreach(reg_state->uses, entry) + printf("%p\n", entry->key); abort(); } - if (reg_state->if_uses->entries != reg->if_uses->entries) { + nir_foreach_if_use(reg, src) { + struct set_entry *entry = _mesa_set_search(reg_state->if_uses, src); + assert(entry); + _mesa_set_remove(reg_state->if_uses, entry); + } + + if (reg_state->if_uses->entries != 0) { printf("extra entries in register if_uses:\n"); struct set_entry *entry; - set_foreach(reg->if_uses, entry) { - struct set_entry *entry2 = - _mesa_set_search(reg_state->if_uses, entry->key); - - if (entry2 == NULL) { - printf("%p\n", entry->key); - } - } + set_foreach(reg_state->if_uses, entry) + printf("%p\n", entry->key); abort(); } - if (reg_state->defs->entries != reg->defs->entries) { + nir_foreach_def(reg, src) { + struct set_entry *entry = _mesa_set_search(reg_state->defs, src); + assert(entry); + _mesa_set_remove(reg_state->defs, entry); + } + + if (reg_state->defs->entries != 0) { printf("extra entries in register defs:\n"); struct set_entry *entry; - set_foreach(reg->defs, entry) { - struct set_entry *entry2 = - _mesa_set_search(reg_state->defs, entry->key); - - if (entry2 == NULL) { - printf("%p\n", entry->key); - } - } + set_foreach(reg_state->defs, entry) + printf("%p\n", entry->key); abort(); } @@ -788,32 +794,32 @@ postvalidate_ssa_def(nir_ssa_def *def, void *void_state) struct hash_entry *entry = _mesa_hash_table_search(state->ssa_defs, def); ssa_def_validate_state *def_state = (ssa_def_validate_state *)entry->data; - if (def_state->uses->entries != def->uses->entries) { - printf("extra entries in SSA def uses:\n"); - struct set_entry *entry; - set_foreach(def->uses, entry) { - struct set_entry *entry2 = - _mesa_set_search(def_state->uses, entry->key); + nir_foreach_use(def, src) { + struct set_entry *entry = _mesa_set_search(def_state->uses, src); + assert(entry); + _mesa_set_remove(def_state->uses, entry); + } - if (entry2 == NULL) { - printf("%p\n", entry->key); - } - } + if (def_state->uses->entries != 0) { + printf("extra entries in register uses:\n"); + struct set_entry *entry; + set_foreach(def_state->uses, entry) + printf("%p\n", entry->key); abort(); } - if (def_state->if_uses->entries != def->if_uses->entries) { - printf("extra entries in SSA def uses:\n"); - struct set_entry *entry; - set_foreach(def->if_uses, entry) { - struct set_entry *entry2 = - _mesa_set_search(def_state->if_uses, entry->key); + nir_foreach_if_use(def, src) { + struct set_entry *entry = _mesa_set_search(def_state->if_uses, src); + assert(entry); + _mesa_set_remove(def_state->if_uses, entry); + } - if (entry2 == NULL) { - printf("%p\n", entry->key); - } - } + if (def_state->if_uses->entries != 0) { + printf("extra entries in register uses:\n"); + struct set_entry *entry; + set_foreach(def_state->if_uses, entry) + printf("%p\n", entry->key); abort(); } diff --git a/mesalib/src/glsl/opt_dead_builtin_varyings.cpp b/mesalib/src/glsl/opt_dead_builtin_varyings.cpp index 92f20c71d..31719d20c 100644 --- a/mesalib/src/glsl/opt_dead_builtin_varyings.cpp +++ b/mesalib/src/glsl/opt_dead_builtin_varyings.cpp @@ -99,6 +99,16 @@ public: } else { this->fragdata_usage |= 1 << index->get_uint_component(0); + /* Don't lower fragdata array if the output variable + * is not a float variable (or float vector) because it will + * generate wrong register assignments because of different + * data types. + */ + if (var->type->gl_type != GL_FLOAT && + var->type->gl_type != GL_FLOAT_VEC2 && + var->type->gl_type != GL_FLOAT_VEC3 && + var->type->gl_type != GL_FLOAT_VEC4) + this->lower_fragdata_array = false; } /* Don't visit the leaves of ir_dereference_array. */ diff --git a/mesalib/src/hgl/GLDispatcher.cpp b/mesalib/src/hgl/GLDispatcher.cpp index 46b91d57c..a1e905361 100644 --- a/mesalib/src/hgl/GLDispatcher.cpp +++ b/mesalib/src/hgl/GLDispatcher.cpp @@ -1,6 +1,6 @@ /* * Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. - * Copyright 2000-2012 Haiku, Inc. All Rights Reserved. + * Copyright 2000-2015 Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. * * Authors: @@ -10,10 +10,11 @@ */ -extern "C" { #include "glapi/glapi.h" #include "glapi/glapi_priv.h" + +extern "C" { /* * NOTE: this file portion implements C-based dispatch of the OpenGL entrypoints * (glAccum, glBegin, etc). diff --git a/mesalib/src/hgl/GLDispatcher.h b/mesalib/src/hgl/GLDispatcher.h index 44bca8ce5..7ee095d91 100644 --- a/mesalib/src/hgl/GLDispatcher.h +++ b/mesalib/src/hgl/GLDispatcher.h @@ -1,6 +1,6 @@ /* * Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. - * Copyright 2000-2012 Haiku, Inc. All Rights Reserved. + * Copyright 2000-2015 Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. * * Authors: @@ -17,9 +17,7 @@ #include "glheader.h" -extern "C" { #include "glapi/glapi.h" -} class BGLDispatcher diff --git a/mesalib/src/hgl/SConscript b/mesalib/src/hgl/SConscript index 70db1494d..71881f504 100644 --- a/mesalib/src/hgl/SConscript +++ b/mesalib/src/hgl/SConscript @@ -6,6 +6,7 @@ Import('*') env = env.Clone() env.Append(CPPPATH = [ + '#/src', '#/src/mapi', '#/src/mesa', '#/src/mesa/main', diff --git a/mesalib/src/loader/loader.h b/mesalib/src/loader/loader.h index 810e7da7f..60c58f2f8 100644 --- a/mesalib/src/loader/loader.h +++ b/mesalib/src/loader/loader.h @@ -27,6 +27,10 @@ #ifndef LOADER_H #define LOADER_H +#ifdef __cplusplus +extern "C" { +#endif + /* Helpers to figure out driver and device name, eg. from pci-id, etc. */ #define _LOADER_DRI (1 << 0) @@ -61,4 +65,9 @@ loader_get_user_preferred_fd(int default_fd, int *different_device); void loader_set_logger(void (*logger)(int level, const char *fmt, ...)); + +#ifdef __cplusplus +} +#endif + #endif /* LOADER_H */ diff --git a/mesalib/src/mapi/glapi/gen/ARB_direct_state_access.xml b/mesalib/src/mapi/glapi/gen/ARB_direct_state_access.xml index 8a092d697..bb9baf5a3 100644 --- a/mesalib/src/mapi/glapi/gen/ARB_direct_state_access.xml +++ b/mesalib/src/mapi/glapi/gen/ARB_direct_state_access.xml @@ -152,6 +152,135 @@ <param name="data" type="GLvoid *" /> </function> + <!-- Framebuffer object functions --> + + <function name="CreateFramebuffers" offset="assign"> + <param name="n" type="GLsizei" /> + <param name="framebuffers" type="GLuint *" /> + </function> + + <function name="NamedFramebufferRenderbuffer" offset="assign"> + <param name="framebuffer" type="GLuint" /> + <param name="attachment" type="GLenum" /> + <param name="renderbuffertarget" type="GLenum" /> + <param name="renderbuffer" type="GLuint" /> + </function> + + <function name="NamedFramebufferParameteri" offset="assign"> + <param name="framebuffer" type="GLuint" /> + <param name="pname" type="GLenum" /> + <param name="param" type="GLint" /> + </function> + + <function name="NamedFramebufferTexture" offset="assign"> + <param name="framebuffer" type="GLuint" /> + <param name="attachment" type="GLenum" /> + <param name="texture" type="GLuint" /> + <param name="level" type="GLint" /> + </function> + + <function name="NamedFramebufferTextureLayer" offset="assign"> + <param name="framebuffer" type="GLuint" /> + <param name="attachment" type="GLenum" /> + <param name="texture" type="GLuint" /> + <param name="level" type="GLint" /> + <param name="layer" type="GLint" /> + </function> + + <function name="NamedFramebufferDrawBuffer" offset="assign"> + <param name="framebuffer" type="GLuint" /> + <param name="buf" type="GLenum" /> + </function> + + <function name="NamedFramebufferDrawBuffers" offset="assign"> + <param name="framebuffer" type="GLuint" /> + <param name="n" type="GLsizei" /> + <param name="bufs" type="const GLenum *" /> + </function> + + <function name="NamedFramebufferReadBuffer" offset="assign"> + <param name="framebuffer" type="GLuint" /> + <param name="buf" type="GLenum" /> + </function> + + <function name="InvalidateNamedFramebufferData" offset="assign"> + <param name="framebuffer" type="GLuint" /> + <param name="numAttachments" type="GLsizei" /> + <param name="attachments" type="const GLenum *" /> + </function> + + <function name="InvalidateNamedFramebufferSubData" offset="assign"> + <param name="framebuffer" type="GLuint" /> + <param name="numAttachments" type="GLsizei" /> + <param name="attachments" type="const GLenum *" /> + <param name="x" type="GLint" /> + <param name="y" type="GLint" /> + <param name="width" type="GLsizei" /> + <param name="height" type="GLsizei" /> + </function> + + <function name="ClearNamedFramebufferiv" offset="assign"> + <param name="framebuffer" type="GLuint" /> + <param name="buffer" type="GLenum" /> + <param name="drawbuffer" type="GLint" /> + <param name="value" type="const GLint *" /> + </function> + + <function name="ClearNamedFramebufferuiv" offset="assign"> + <param name="framebuffer" type="GLuint" /> + <param name="buffer" type="GLenum" /> + <param name="drawbuffer" type="GLint" /> + <param name="value" type="const GLuint *" /> + </function> + + <function name="ClearNamedFramebufferfv" offset="assign"> + <param name="framebuffer" type="GLuint" /> + <param name="buffer" type="GLenum" /> + <param name="drawbuffer" type="GLint" /> + <param name="value" type="const GLfloat *" /> + </function> + + <function name="ClearNamedFramebufferfi" offset="assign"> + <param name="framebuffer" type="GLuint" /> + <param name="buffer" type="GLenum" /> + <param name="depth" type="GLfloat" /> + <param name="stencil" type="GLint" /> + </function> + + <function name="BlitNamedFramebuffer" offset="assign"> + <param name="readFramebuffer" type="GLuint" /> + <param name="drawFramebuffer" type="GLuint" /> + <param name="srcX0" type="GLint" /> + <param name="srcY0" type="GLint" /> + <param name="srcX1" type="GLint" /> + <param name="srcY1" type="GLint" /> + <param name="dstX0" type="GLint" /> + <param name="dstY0" type="GLint" /> + <param name="dstX1" type="GLint" /> + <param name="dstY1" type="GLint" /> + <param name="mask" type="GLbitfield" /> + <param name="filter" type="GLenum" /> + </function> + + <function name="CheckNamedFramebufferStatus" offset="assign"> + <return type="GLenum" /> + <param name="framebuffer" type="GLuint" /> + <param name="target" type="GLenum" /> + </function> + + <function name="GetNamedFramebufferParameteriv" offset="assign"> + <param name="framebuffer" type="GLuint" /> + <param name="pname" type="GLenum" /> + <param name="param" type="GLint *" /> + </function> + + <function name="GetNamedFramebufferAttachmentParameteriv" offset="assign"> + <param name="framebuffer" type="GLuint" /> + <param name="attachment" type="GLenum" /> + <param name="pname" type="GLenum" /> + <param name="params" type="GLint *" /> + </function> + <!-- Renderbuffer object functions --> <function name="CreateRenderbuffers" offset="assign"> @@ -448,6 +577,102 @@ <param name="params" type="GLint *" /> </function> + <!-- Vertex Array object functions --> + + <function name="CreateVertexArrays" offset="assign"> + <param name="n" type="GLsizei" /> + <param name="arrays" type="GLuint *" /> + </function> + + <function name="DisableVertexArrayAttrib" offset="assign"> + <param name="vaobj" type="GLuint" /> + <param name="index" type="GLuint" /> + </function> + + <function name="EnableVertexArrayAttrib" offset="assign"> + <param name="vaobj" type="GLuint" /> + <param name="index" type="GLuint" /> + </function> + + <function name="VertexArrayElementBuffer" offset="assign"> + <param name="vaobj" type="GLuint" /> + <param name="buffer" type="GLuint" /> + </function> + + <function name="VertexArrayVertexBuffer" offset="assign"> + <param name="vaobj" type="GLuint" /> + <param name="bindingindex" type="GLuint" /> + <param name="buffer" type="GLuint" /> + <param name="offset" type="GLintptr" /> + <param name="stride" type="GLsizei" /> + </function> + + <function name="VertexArrayVertexBuffers" offset="assign"> + <param name="vaobj" type="GLuint" /> + <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> + + <function name="VertexArrayAttribFormat" offset="assign"> + <param name="vaobj" type="GLuint" /> + <param name="attribindex" type="GLuint" /> + <param name="size" type="GLint" /> + <param name="type" type="GLenum" /> + <param name="normalized" type="GLboolean" /> + <param name="relativeoffset" type="GLuint" /> + </function> + + <function name="VertexArrayAttribIFormat" offset="assign"> + <param name="vaobj" type="GLuint" /> + <param name="attribindex" type="GLuint" /> + <param name="size" type="GLint" /> + <param name="type" type="GLenum" /> + <param name="relativeoffset" type="GLuint" /> + </function> + + <function name="VertexArrayAttribLFormat" offset="assign"> + <param name="vaobj" type="GLuint" /> + <param name="attribindex" type="GLuint" /> + <param name="size" type="GLint" /> + <param name="type" type="GLenum" /> + <param name="relativeoffset" type="GLuint" /> + </function> + + <function name="VertexArrayAttribBinding" offset="assign"> + <param name="vaobj" type="GLuint" /> + <param name="attribindex" type="GLuint" /> + <param name="bindingindex" type="GLuint" /> + </function> + + <function name="VertexArrayBindingDivisor" offset="assign"> + <param name="vaobj" type="GLuint" /> + <param name="bindingindex" type="GLuint" /> + <param name="divisor" type="GLuint" /> + </function> + + <function name="GetVertexArrayiv" offset="assign"> + <param name="vaobj" type="GLuint" /> + <param name="pname" type="GLenum" /> + <param name="param" type="GLint *" /> + </function> + + <function name="GetVertexArrayIndexediv" offset="assign"> + <param name="vaobj" type="GLuint" /> + <param name="index" type="GLuint" /> + <param name="pname" type="GLenum" /> + <param name="param" type="GLint *" /> + </function> + + <function name="GetVertexArrayIndexed64iv" offset="assign"> + <param name="vaobj" type="GLuint" /> + <param name="index" type="GLuint" /> + <param name="pname" type="GLenum" /> + <param name="param" type="GLint64 *" /> + </function> + <!-- Sampler object functions --> <function name="CreateSamplers" offset="assign"> diff --git a/mesalib/src/mapi/glapi/gen/ARB_framebuffer_object.xml b/mesalib/src/mapi/glapi/gen/ARB_framebuffer_object.xml index 7c547c167..999a8ef13 100644 --- a/mesalib/src/mapi/glapi/gen/ARB_framebuffer_object.xml +++ b/mesalib/src/mapi/glapi/gen/ARB_framebuffer_object.xml @@ -247,7 +247,7 @@ <param name="textarget" type="GLenum"/> <param name="texture" type="GLuint"/> <param name="level" type="GLint"/> - <param name="zoffset" type="GLint"/> + <param name="layer" type="GLint"/> <glx rop="4323"/> </function> diff --git a/mesalib/src/mapi/glapi/gen/ARB_vertex_attrib_64bit.xml b/mesalib/src/mapi/glapi/gen/ARB_vertex_attrib_64bit.xml new file mode 100644 index 000000000..fc49f84b5 --- /dev/null +++ b/mesalib/src/mapi/glapi/gen/ARB_vertex_attrib_64bit.xml @@ -0,0 +1,70 @@ +<?xml version="1.0"?> +<!DOCTYPE OpenGLAPI SYSTEM "gl_API.dtd"> + +<OpenGLAPI> + +<category name="GL_ARB_vertex_attrib_64bit" number="99"> + + <function name="VertexAttribL1d" offset="assign"> + <param name="index" type="GLuint"/> + <param name="x" type="GLdouble"/> + </function> + + <function name="VertexAttribL2d" offset="assign"> + <param name="index" type="GLuint"/> + <param name="x" type="GLdouble"/> + <param name="y" type="GLdouble"/> + </function> + + <function name="VertexAttribL3d" offset="assign"> + <param name="index" type="GLuint"/> + <param name="x" type="GLdouble"/> + <param name="y" type="GLdouble"/> + <param name="z" type="GLdouble"/> + </function> + + <function name="VertexAttribL4d" offset="assign"> + <param name="index" type="GLuint"/> + <param name="x" type="GLdouble"/> + <param name="y" type="GLdouble"/> + <param name="z" type="GLdouble"/> + <param name="w" type="GLdouble"/> + </function> + + <function name="VertexAttribL1dv" offset="assign"> + <param name="index" type="GLuint"/> + <param name="v" type="const GLdouble *"/> + </function> + + <function name="VertexAttribL2dv" offset="assign"> + <param name="index" type="GLuint"/> + <param name="v" type="const GLdouble *"/> + </function> + + <function name="VertexAttribL3dv" offset="assign"> + <param name="index" type="GLuint"/> + <param name="v" type="const GLdouble *"/> + </function> + + <function name="VertexAttribL4dv" offset="assign"> + <param name="index" type="GLuint"/> + <param name="v" type="const GLdouble *"/> + </function> + + <function name="VertexAttribLPointer" offset="assign"> + <param name="index" type="GLuint"/> + <param name="size" type="GLint"/> + <param name="type" type="GLenum"/> + <param name="stride" type="GLsizei"/> + <param name="pointer" type="const GLvoid *"/> + </function> + + <function name="GetVertexAttribLdv" offset="assign"> + <param name="index" type="GLuint"/> + <param name="pname" type="GLenum"/> + <param name="params" type="GLdouble *"/> + </function> +</category> + +</OpenGLAPI> + diff --git a/mesalib/src/mapi/glapi/gen/Makefile.am b/mesalib/src/mapi/glapi/gen/Makefile.am index 1c4b86aab..c8d417468 100644 --- a/mesalib/src/mapi/glapi/gen/Makefile.am +++ b/mesalib/src/mapi/glapi/gen/Makefile.am @@ -163,6 +163,7 @@ API_XML = \ ARB_texture_view.xml \ ARB_uniform_buffer_object.xml \ ARB_vertex_array_object.xml \ + ARB_vertex_attrib_64bit.xml \ ARB_vertex_attrib_binding.xml \ ARB_viewport_array.xml \ AMD_draw_buffers_blend.xml \ diff --git a/mesalib/src/mapi/glapi/gen/gl_API.xml b/mesalib/src/mapi/glapi/gen/gl_API.xml index a8a6db683..d1565989c 100644 --- a/mesalib/src/mapi/glapi/gen/gl_API.xml +++ b/mesalib/src/mapi/glapi/gen/gl_API.xml @@ -8253,7 +8253,9 @@ <!-- No new functions, types, enums. --> </category> -<!-- ARB extensions #99...#108 --> +<xi:include href="ARB_vertex_attrib_64bit.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/> + +<!-- ARB extensions #100...#108 --> <xi:include href="ARB_ES2_compatibility.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/> diff --git a/mesalib/src/mapi/glapi/gen/gl_genexec.py b/mesalib/src/mapi/glapi/gen/gl_genexec.py index 7151f0de1..4e76fe3c2 100644 --- a/mesalib/src/mapi/glapi/gen/gl_genexec.py +++ b/mesalib/src/mapi/glapi/gen/gl_genexec.py @@ -183,8 +183,8 @@ class PrintCode(gl_XML.gl_print_base): if 'es1' in f.api_map: condition_parts.append('ctx->API == API_OPENGLES') if 'es2' in f.api_map: - if f.api_map['es2'] == 3: - condition_parts.append('_mesa_is_gles3(ctx)') + if f.api_map['es2'] > 2.0: + condition_parts.append('(ctx->API == API_OPENGLES2 && ctx->Version >= {0})'.format(int(f.api_map['es2'] * 10))) else: condition_parts.append('ctx->API == API_OPENGLES2') if not condition_parts: diff --git a/mesalib/src/mapi/glapi/glapi_priv.h b/mesalib/src/mapi/glapi/glapi_priv.h index 50f710edc..337913acc 100644 --- a/mesalib/src/mapi/glapi/glapi_priv.h +++ b/mesalib/src/mapi/glapi/glapi_priv.h @@ -49,6 +49,10 @@ typedef void *GLeglImageOES; #include "glapi/glapi.h" +#ifdef __cplusplus +extern "C" { +#endif + /* getproc */ extern void @@ -106,4 +110,8 @@ get_entrypoint_address(unsigned int functionOffset); #define MAX_EXTENSION_FUNCS 256 +#ifdef __cplusplus +} +#endif + #endif diff --git a/mesalib/src/mesa/Makefile.sources b/mesalib/src/mesa/Makefile.sources index 1293d4135..83f500fbf 100644 --- a/mesalib/src/mesa/Makefile.sources +++ b/mesalib/src/mesa/Makefile.sources @@ -434,6 +434,8 @@ STATETRACKER_FILES = \ state_tracker/st_cb_flush.h \ state_tracker/st_cb_msaa.c \ state_tracker/st_cb_msaa.h \ + state_tracker/st_cb_perfmon.c \ + state_tracker/st_cb_perfmon.h \ state_tracker/st_cb_program.c \ state_tracker/st_cb_program.h \ state_tracker/st_cb_queryobj.c \ diff --git a/mesalib/src/mesa/drivers/common/driverfuncs.c b/mesalib/src/mesa/drivers/common/driverfuncs.c index 0d094ddf4..71c1a7639 100644 --- a/mesalib/src/mesa/drivers/common/driverfuncs.c +++ b/mesalib/src/mesa/drivers/common/driverfuncs.c @@ -172,7 +172,7 @@ _mesa_init_driver_functions(struct dd_function_table *driver) driver->UnmapRenderbuffer = _swrast_unmap_soft_renderbuffer; driver->RenderTexture = _swrast_render_texture; driver->FinishRenderTexture = _swrast_finish_render_texture; - driver->FramebufferRenderbuffer = _mesa_framebuffer_renderbuffer; + driver->FramebufferRenderbuffer = _mesa_FramebufferRenderbuffer_sw; driver->ValidateFramebuffer = _mesa_validate_framebuffer; driver->BlitFramebuffer = _swrast_BlitFramebuffer; diff --git a/mesalib/src/mesa/drivers/common/meta.c b/mesalib/src/mesa/drivers/common/meta.c index d2ab7b8de..214a68a91 100644 --- a/mesalib/src/mesa/drivers/common/meta.c +++ b/mesalib/src/mesa/drivers/common/meta.c @@ -1211,7 +1211,8 @@ _mesa_meta_end(struct gl_context *ctx) _mesa_BindRenderbuffer(GL_RENDERBUFFER, save->RenderbufferName); if (state & MESA_META_DRAW_BUFFERS) { - _mesa_drawbuffers(ctx, ctx->Const.MaxDrawBuffers, save->ColorDrawBuffers, NULL); + _mesa_drawbuffers(ctx, ctx->DrawBuffer, ctx->Const.MaxDrawBuffers, + save->ColorDrawBuffers, NULL); } ctx->Meta->SaveStackDepth--; diff --git a/mesalib/src/mesa/drivers/dri/swrast/swrast.c b/mesalib/src/mesa/drivers/dri/swrast/swrast.c index d1bb72139..cbc946c3f 100644 --- a/mesalib/src/mesa/drivers/dri/swrast/swrast.c +++ b/mesalib/src/mesa/drivers/dri/swrast/swrast.c @@ -61,6 +61,9 @@ #include "swrast_priv.h" #include "swrast/s_context.h" +#include <sys/types.h> +#include <sys/sysctl.h> + const __DRIextension **__driDriverGetExtensions_swrast(void); const char * const swrast_vendor_string = "Mesa Project"; @@ -137,6 +140,16 @@ swrast_query_renderer_integer(__DRIscreen *psp, int param, value[0] = 0; return 0; case __DRI2_RENDERER_VIDEO_MEMORY: { + /* This should probably share code with os_get_total_physical_memory() + * from src/gallium/auxiliary/os/os_misc.c + */ +#if defined(CTL_HW) && defined(HW_MEMSIZE) + int mib[2] = { CTL_HW, HW_MEMSIZE }; + unsigned long system_memory_bytes; + size_t len = sizeof(system_memory_bytes); + if (sysctl(mib, 2, &system_memory_bytes, &len, NULL, 0) != 0) + return -1; +#elif defined(_SC_PHYS_PAGES) && defined(_SC_PAGE_SIZE) /* XXX: Do we want to return the full amount of system memory ? */ const long system_memory_pages = sysconf(_SC_PHYS_PAGES); const long system_page_size = sysconf(_SC_PAGE_SIZE); @@ -146,6 +159,9 @@ swrast_query_renderer_integer(__DRIscreen *psp, int param, const uint64_t system_memory_bytes = (uint64_t) system_memory_pages * (uint64_t) system_page_size; +#else +#error "Unsupported platform" +#endif const unsigned system_memory_megabytes = (unsigned) (system_memory_bytes / (1024 * 1024)); @@ -942,6 +958,7 @@ static const __DRIextension *swrast_driver_extensions[] = { &driCoreExtension.base, &driSWRastExtension.base, &driCopySubBufferExtension.base, + &dri2ConfigQueryExtension.base, &swrast_vtable.base, NULL }; diff --git a/mesalib/src/mesa/main/api_arrayelt.c b/mesalib/src/mesa/main/api_arrayelt.c index ea015fd65..92d8238f4 100644 --- a/mesalib/src/mesa/main/api_arrayelt.c +++ b/mesalib/src/mesa/main/api_arrayelt.c @@ -1258,12 +1258,37 @@ VertexAttribI4uiv(GLuint index, const GLuint *v) CALL_VertexAttribI4uivEXT(GET_DISPATCH(), (index, v)); } +/* GL_DOUBLE unconverted attributes */ + +static void GLAPIENTRY +VertexAttribL1dv(GLuint index, const GLdouble *v) +{ + CALL_VertexAttribL1dv(GET_DISPATCH(), (index, v)); +} + +static void GLAPIENTRY +VertexAttribL2dv(GLuint index, const GLdouble *v) +{ + CALL_VertexAttribL2dv(GET_DISPATCH(), (index, v)); +} + +static void GLAPIENTRY +VertexAttribL3dv(GLuint index, const GLdouble *v) +{ + CALL_VertexAttribL3dv(GET_DISPATCH(), (index, v)); +} + +static void GLAPIENTRY +VertexAttribL4dv(GLuint index, const GLdouble *v) +{ + CALL_VertexAttribL4dv(GET_DISPATCH(), (index, v)); +} /* * Array [unnormalized/normalized/integer][size][type] of VertexAttrib * functions */ -static attrib_func AttribFuncsARB[3][4][NUM_TYPES] = { +static attrib_func AttribFuncsARB[4][4][NUM_TYPES] = { { /* non-normalized */ { @@ -1405,7 +1430,55 @@ static attrib_func AttribFuncsARB[3][4][NUM_TYPES] = { NULL, /* GL_FLOAT */ NULL /* GL_DOUBLE */ } + }, + { + /* double-valued */ + { + /* size 1 */ + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + (attrib_func) VertexAttribL1dv, + }, + { + /* size 2 */ + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + (attrib_func) VertexAttribL2dv, + }, + { + /* size 3 */ + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + (attrib_func) VertexAttribL3dv, + }, + { + /* size 4 */ + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + (attrib_func) VertexAttribL4dv, + } } + }; @@ -1571,7 +1644,9 @@ _ae_update_state(struct gl_context *ctx) * change from one execution of _ae_ArrayElement() to * the next. Doing so caused UT to break. */ - if (at->array->Integer) + if (at->array->Doubles) + intOrNorm = 3; + else if (at->array->Integer) intOrNorm = 2; else if (at->array->Normalized) intOrNorm = 1; diff --git a/mesalib/src/mesa/main/api_loopback.c b/mesalib/src/mesa/main/api_loopback.c index d10ae15ea..9932a8373 100644 --- a/mesalib/src/mesa/main/api_loopback.c +++ b/mesalib/src/mesa/main/api_loopback.c @@ -84,6 +84,10 @@ #define ATTRIBI_4UI(index,x,y,z,w) CALL_VertexAttribI4uiEXT(GET_DISPATCH(), (index,x,y,z,w)) +#define ATTRIB1_D(index,x) CALL_VertexAttribL1d(GET_DISPATCH(), (index,x)) +#define ATTRIB2_D(index,x,y) CALL_VertexAttribL2d(GET_DISPATCH(), (index,x,y)) +#define ATTRIB3_D(index,x,y,z) CALL_VertexAttribL3d(GET_DISPATCH(), (index,x,y,z)) +#define ATTRIB4_D(index,x,y,z,w) CALL_VertexAttribL4d(GET_DISPATCH(), (index,x,y,z,w)) void GLAPIENTRY _mesa_Color3b( GLbyte red, GLbyte green, GLbyte blue ) @@ -1490,8 +1494,53 @@ _mesa_VertexAttribI4usv(GLuint index, const GLushort *v) ATTRIBI_4UI(index, v[0], v[1], v[2], v[3]); } +void GLAPIENTRY +_mesa_VertexAttribL1d(GLuint index, GLdouble x) +{ + ATTRIB1_D(index, x); +} + +void GLAPIENTRY +_mesa_VertexAttribL2d(GLuint index, GLdouble x, GLdouble y) +{ + ATTRIB2_D(index, x, y); +} +void GLAPIENTRY +_mesa_VertexAttribL3d(GLuint index, GLdouble x, GLdouble y, GLdouble z) +{ + ATTRIB3_D(index, x, y, z); +} +void GLAPIENTRY +_mesa_VertexAttribL4d(GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w) +{ + ATTRIB4_D(index, x, y, z, w); +} + +void GLAPIENTRY +_mesa_VertexAttribL1dv(GLuint index, const GLdouble *v) +{ + ATTRIB1_D(index, v[0]); +} + +void GLAPIENTRY +_mesa_VertexAttribL2dv(GLuint index, const GLdouble *v) +{ + ATTRIB2_D(index, v[0], v[1]); +} + +void GLAPIENTRY +_mesa_VertexAttribL3dv(GLuint index, const GLdouble *v) +{ + ATTRIB3_D(index, v[0], v[1], v[2]); +} + +void GLAPIENTRY +_mesa_VertexAttribL4dv(GLuint index, const GLdouble *v) +{ + ATTRIB4_D(index, v[0], v[1], v[2], v[3]); +} /* * This code never registers handlers for any of the entry points @@ -1723,5 +1772,16 @@ _mesa_loopback_init_api_table(const struct gl_context *ctx, SET_VertexAttribI4sv(dest, _mesa_VertexAttribI4sv); SET_VertexAttribI4ubv(dest, _mesa_VertexAttribI4ubv); SET_VertexAttribI4usv(dest, _mesa_VertexAttribI4usv); + + /* GL 4.1 / GL_ARB_vertex_attrib_64bit */ + SET_VertexAttribL1d(dest, _mesa_VertexAttribL1d); + SET_VertexAttribL2d(dest, _mesa_VertexAttribL2d); + SET_VertexAttribL3d(dest, _mesa_VertexAttribL3d); + SET_VertexAttribL4d(dest, _mesa_VertexAttribL4d); + + SET_VertexAttribL1dv(dest, _mesa_VertexAttribL1dv); + SET_VertexAttribL2dv(dest, _mesa_VertexAttribL2dv); + SET_VertexAttribL3dv(dest, _mesa_VertexAttribL3dv); + SET_VertexAttribL4dv(dest, _mesa_VertexAttribL4dv); } } diff --git a/mesalib/src/mesa/main/api_loopback.h b/mesalib/src/mesa/main/api_loopback.h index 44514405b..026bfd68e 100644 --- a/mesalib/src/mesa/main/api_loopback.h +++ b/mesalib/src/mesa/main/api_loopback.h @@ -464,5 +464,21 @@ _mesa_VertexAttribI4ubv(GLuint index, const GLubyte *v); void GLAPIENTRY _mesa_VertexAttribI4usv(GLuint index, const GLushort *v); +void GLAPIENTRY +_mesa_VertexAttribL1d(GLuint index, GLdouble x); +void GLAPIENTRY +_mesa_VertexAttribL2d(GLuint index, GLdouble x, GLdouble y); +void GLAPIENTRY +_mesa_VertexAttribL3d(GLuint index, GLdouble x, GLdouble y, GLdouble z); +void GLAPIENTRY +_mesa_VertexAttribL4d(GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); +void GLAPIENTRY +_mesa_VertexAttribL1dv(GLuint index, const GLdouble *v); +void GLAPIENTRY +_mesa_VertexAttribL2dv(GLuint index, const GLdouble *v); +void GLAPIENTRY +_mesa_VertexAttribL3dv(GLuint index, const GLdouble *v); +void GLAPIENTRY +_mesa_VertexAttribL4dv(GLuint index, const GLdouble *v); #endif /* API_LOOPBACK_H */ diff --git a/mesalib/src/mesa/main/arrayobj.c b/mesalib/src/mesa/main/arrayobj.c index 3c8ffb5a4..320f435ea 100644 --- a/mesalib/src/mesa/main/arrayobj.c +++ b/mesalib/src/mesa/main/arrayobj.c @@ -75,6 +75,61 @@ _mesa_lookup_vao(struct gl_context *ctx, GLuint id) /** + * Looks up the array object for the given ID. + * + * Unlike _mesa_lookup_vao, this function generates a GL_INVALID_OPERATION + * error if the array object does not exist. It also returns the default + * array object when ctx is a compatibility profile context and id is zero. + */ +struct gl_vertex_array_object * +_mesa_lookup_vao_err(struct gl_context *ctx, GLuint id, const char *caller) +{ + /* The ARB_direct_state_access specification says: + * + * "<vaobj> is [compatibility profile: + * zero, indicating the default vertex array object, or] + * the name of the vertex array object." + */ + if (id == 0) { + if (ctx->API == API_OPENGL_CORE) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(zero is not valid vaobj name in a core profile " + "context)", caller); + return NULL; + } + + return ctx->Array.DefaultVAO; + } else { + struct gl_vertex_array_object *vao; + + if (ctx->Array.LastLookedUpVAO && + ctx->Array.LastLookedUpVAO->Name == id) { + vao = ctx->Array.LastLookedUpVAO; + } else { + vao = (struct gl_vertex_array_object *) + _mesa_HashLookup(ctx->Array.Objects, id); + + /* The ARB_direct_state_access specification says: + * + * "An INVALID_OPERATION error is generated if <vaobj> is not + * [compatibility profile: zero or] the name of an existing + * vertex array object." + */ + if (!vao || !vao->EverBound) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(non-existent vaobj=%u)", caller, id); + return NULL; + } + + _mesa_reference_vao(ctx, &ctx->Array.LastLookedUpVAO, vao); + } + + return vao; + } +} + + +/** * For all the vertex binding points in the array object, unbind any pointers * to any buffer objects (VBOs). * This is done just prior to array object destruction. @@ -200,6 +255,7 @@ init_array(struct gl_context *ctx, array->Enabled = GL_FALSE; array->Normalized = GL_FALSE; array->Integer = GL_FALSE; + array->Doubles = GL_FALSE; array->_ElementSize = size * _mesa_sizeof_type(type); array->VertexBinding = index; @@ -469,6 +525,9 @@ _mesa_DeleteVertexArrays(GLsizei n, const GLuint *ids) /* The ID is immediately freed for re-use */ remove_array_object(ctx, obj); + if (ctx->Array.LastLookedUpVAO == obj) + _mesa_reference_vao(ctx, &ctx->Array.LastLookedUpVAO, NULL); + /* Unreference the array object. * If refcount hits zero, the object will be deleted. */ @@ -480,19 +539,23 @@ _mesa_DeleteVertexArrays(GLsizei n, const GLuint *ids) /** * Generate a set of unique array object IDs and store them in \c arrays. - * Helper for _mesa_GenVertexArrays[APPLE]() functions below. + * Helper for _mesa_GenVertexArrays[APPLE]() and _mesa_CreateVertexArrays() + * below. + * * \param n Number of IDs to generate. * \param arrays Array of \c n locations to store the IDs. - * \param vboOnly Will arrays have to reside in VBOs? + * \param create Indicates that the objects should also be created. + * \param func The name of the GL entry point. */ static void -gen_vertex_arrays(struct gl_context *ctx, GLsizei n, GLuint *arrays) +gen_vertex_arrays(struct gl_context *ctx, GLsizei n, GLuint *arrays, + bool create, const char *func) { GLuint first; GLint i; if (n < 0) { - _mesa_error(ctx, GL_INVALID_VALUE, "glGenVertexArrays"); + _mesa_error(ctx, GL_INVALID_VALUE, "%s(n < 0)", func); return; } @@ -502,16 +565,20 @@ gen_vertex_arrays(struct gl_context *ctx, GLsizei n, GLuint *arrays) first = _mesa_HashFindFreeKeyBlock(ctx->Array.Objects, n); - /* Allocate new, empty array objects and return identifiers */ + /* For the sake of simplicity we create the array objects in both + * the Gen* and Create* cases. The only difference is the value of + * EverBound, which is set to true in the Create* case. + */ for (i = 0; i < n; i++) { struct gl_vertex_array_object *obj; GLuint name = first + i; obj = (*ctx->Driver.NewArrayObject)( ctx, name ); if (!obj) { - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenVertexArrays"); + _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", func); return; } + obj->EverBound = create; save_array_object(ctx, obj); arrays[i] = first + i; } @@ -526,7 +593,7 @@ void GLAPIENTRY _mesa_GenVertexArrays(GLsizei n, GLuint *arrays) { GET_CURRENT_CONTEXT(ctx); - gen_vertex_arrays(ctx, n, arrays); + gen_vertex_arrays(ctx, n, arrays, false, "glGenVertexArrays"); } @@ -538,7 +605,27 @@ void GLAPIENTRY _mesa_GenVertexArraysAPPLE(GLsizei n, GLuint *arrays) { GET_CURRENT_CONTEXT(ctx); - gen_vertex_arrays(ctx, n, arrays); + gen_vertex_arrays(ctx, n, arrays, false, "glGenVertexArraysAPPLE"); +} + + +/** + * ARB_direct_state_access + * Generates ID's and creates the array objects. + */ +void GLAPIENTRY +_mesa_CreateVertexArrays(GLsizei n, GLuint *arrays) +{ + GET_CURRENT_CONTEXT(ctx); + + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glCreateVertexArrays(GL_ARB_direct_state_access " + "is not supported"); + return; + } + + gen_vertex_arrays(ctx, n, arrays, true, "glCreateVertexArrays"); } @@ -565,3 +652,92 @@ _mesa_IsVertexArray( GLuint id ) return obj->EverBound; } + + +/** + * Sets the element array buffer binding of a vertex array object. + * + * This is the ARB_direct_state_access equivalent of + * glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer). + */ +void GLAPIENTRY +_mesa_VertexArrayElementBuffer(GLuint vaobj, GLuint buffer) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_vertex_array_object *vao; + struct gl_buffer_object *bufObj; + + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glVertexArrayElementBuffer(GL_ARB_direct_state_access " + "is not supported"); + return; + } + + ASSERT_OUTSIDE_BEGIN_END(ctx); + + /* The GL_ARB_direct_state_access specification says: + * + * "An INVALID_OPERATION error is generated by VertexArrayElementBuffer + * if <vaobj> is not [compatibility profile: zero or] the name of an + * existing vertex array object." + */ + vao =_mesa_lookup_vao_err(ctx, vaobj, "glVertexArrayElementBuffer"); + if (!vao) + return; + + /* The GL_ARB_direct_state_access specification says: + * + * "An INVALID_OPERATION error is generated if <buffer> is not zero or + * the name of an existing buffer object." + */ + if (buffer != 0) + bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, + "glVertexArrayElementBuffer"); + else + bufObj = ctx->Shared->NullBufferObj; + + if (bufObj) + _mesa_reference_buffer_object(ctx, &vao->IndexBufferObj, bufObj); +} + + +void GLAPIENTRY +_mesa_GetVertexArrayiv(GLuint vaobj, GLenum pname, GLint *param) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_vertex_array_object *vao; + + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetVertexArrayiv(GL_ARB_direct_state_access " + "is not supported"); + return; + } + + /* The GL_ARB_direct_state_access specification says: + * + * "An INVALID_OPERATION error is generated if <vaobj> is not + * [compatibility profile: zero or] the name of an existing + * vertex array object." + */ + vao =_mesa_lookup_vao_err(ctx, vaobj, "glGetVertexArrayiv"); + if (!vao) + return; + + /* The GL_ARB_direct_state_access specification says: + * + * "An INVALID_ENUM error is generated if <pname> is not + * ELEMENT_ARRAY_BUFFER_BINDING." + */ + if (pname != GL_ELEMENT_ARRAY_BUFFER_BINDING) { + _mesa_error(ctx, GL_INVALID_ENUM, + "glGetVertexArrayiv(pname != " + "GL_ELEMENT_ARRAY_BUFFER_BINDING)"); + return; + } + + param[0] = vao->IndexBufferObj->Name; +} diff --git a/mesalib/src/mesa/main/arrayobj.h b/mesalib/src/mesa/main/arrayobj.h index 3c1f91835..6a4247f4a 100644 --- a/mesalib/src/mesa/main/arrayobj.h +++ b/mesalib/src/mesa/main/arrayobj.h @@ -49,6 +49,9 @@ extern struct gl_vertex_array_object * _mesa_lookup_vao(struct gl_context *ctx, GLuint id); extern struct gl_vertex_array_object * +_mesa_lookup_vao_err(struct gl_context *ctx, GLuint id, const char *caller); + +extern struct gl_vertex_array_object * _mesa_new_vao(struct gl_context *ctx, GLuint name); extern void @@ -93,6 +96,12 @@ void GLAPIENTRY _mesa_GenVertexArrays(GLsizei n, GLuint *arrays); void GLAPIENTRY _mesa_GenVertexArraysAPPLE(GLsizei n, GLuint *buffer); +void GLAPIENTRY _mesa_CreateVertexArrays(GLsizei n, GLuint *arrays); + GLboolean GLAPIENTRY _mesa_IsVertexArray( GLuint id ); +void GLAPIENTRY _mesa_VertexArrayElementBuffer(GLuint vaobj, GLuint buffer); + +void GLAPIENTRY _mesa_GetVertexArrayiv(GLuint vaobj, GLenum pname, GLint *param); + #endif /* ARRAYOBJ_H */ diff --git a/mesalib/src/mesa/main/blend.c b/mesalib/src/mesa/main/blend.c index 774fc888e..d869fa2aa 100644 --- a/mesalib/src/mesa/main/blend.c +++ b/mesalib/src/mesa/main/blend.c @@ -769,7 +769,7 @@ _mesa_ClampColor(GLenum target, GLenum clamp) } FLUSH_VERTICES(ctx, _NEW_LIGHT); ctx->Light.ClampVertexColor = clamp; - _mesa_update_clamp_vertex_color(ctx); + _mesa_update_clamp_vertex_color(ctx, ctx->DrawBuffer); break; case GL_CLAMP_FRAGMENT_COLOR_ARB: if (ctx->API == API_OPENGL_CORE && @@ -778,7 +778,7 @@ _mesa_ClampColor(GLenum target, GLenum clamp) } FLUSH_VERTICES(ctx, _NEW_FRAG_CLAMP); ctx->Color.ClampFragmentColor = clamp; - _mesa_update_clamp_fragment_color(ctx); + _mesa_update_clamp_fragment_color(ctx, ctx->DrawBuffer); break; case GL_CLAMP_READ_COLOR_ARB: ctx->Color.ClampReadColor = clamp; @@ -807,50 +807,55 @@ get_clamp_color(const struct gl_framebuffer *fb, GLenum clamp) } GLboolean -_mesa_get_clamp_fragment_color(const struct gl_context *ctx) +_mesa_get_clamp_fragment_color(const struct gl_context *ctx, + const struct gl_framebuffer *drawFb) { - return get_clamp_color(ctx->DrawBuffer, - ctx->Color.ClampFragmentColor); + return get_clamp_color(drawFb, ctx->Color.ClampFragmentColor); } GLboolean -_mesa_get_clamp_vertex_color(const struct gl_context *ctx) +_mesa_get_clamp_vertex_color(const struct gl_context *ctx, + const struct gl_framebuffer *drawFb) { - return get_clamp_color(ctx->DrawBuffer, ctx->Light.ClampVertexColor); + return get_clamp_color(drawFb, ctx->Light.ClampVertexColor); } GLboolean -_mesa_get_clamp_read_color(const struct gl_context *ctx) +_mesa_get_clamp_read_color(const struct gl_context *ctx, + const struct gl_framebuffer *readFb) { - return get_clamp_color(ctx->ReadBuffer, ctx->Color.ClampReadColor); + return get_clamp_color(readFb, ctx->Color.ClampReadColor); } /** * Update the ctx->Color._ClampFragmentColor field */ void -_mesa_update_clamp_fragment_color(struct gl_context *ctx) +_mesa_update_clamp_fragment_color(struct gl_context *ctx, + const struct gl_framebuffer *drawFb) { - struct gl_framebuffer *fb = ctx->DrawBuffer; - /* Don't clamp if: * - there is no colorbuffer * - all colorbuffers are unsigned normalized, so clamping has no effect * - there is an integer colorbuffer */ - if (!fb || !fb->_HasSNormOrFloatColorBuffer || fb->_IntegerColor) + if (!drawFb || !drawFb->_HasSNormOrFloatColorBuffer || + drawFb->_IntegerColor) ctx->Color._ClampFragmentColor = GL_FALSE; else - ctx->Color._ClampFragmentColor = _mesa_get_clamp_fragment_color(ctx); + ctx->Color._ClampFragmentColor = + _mesa_get_clamp_fragment_color(ctx, drawFb); } /** * Update the ctx->Color._ClampVertexColor field */ void -_mesa_update_clamp_vertex_color(struct gl_context *ctx) +_mesa_update_clamp_vertex_color(struct gl_context *ctx, + const struct gl_framebuffer *drawFb) { - ctx->Light._ClampVertexColor = _mesa_get_clamp_vertex_color(ctx); + ctx->Light._ClampVertexColor = + _mesa_get_clamp_vertex_color(ctx, drawFb); } /** diff --git a/mesalib/src/mesa/main/blend.h b/mesalib/src/mesa/main/blend.h index fe31a7440..8ab9e02fc 100644 --- a/mesalib/src/mesa/main/blend.h +++ b/mesalib/src/mesa/main/blend.h @@ -37,6 +37,7 @@ #include "formats.h" struct gl_context; +struct gl_framebuffer; extern void GLAPIENTRY @@ -101,19 +102,24 @@ extern void GLAPIENTRY _mesa_ClampColor(GLenum target, GLenum clamp); extern GLboolean -_mesa_get_clamp_fragment_color(const struct gl_context *ctx); +_mesa_get_clamp_fragment_color(const struct gl_context *ctx, + const struct gl_framebuffer *drawFb); extern GLboolean -_mesa_get_clamp_vertex_color(const struct gl_context *ctx); +_mesa_get_clamp_vertex_color(const struct gl_context *ctx, + const struct gl_framebuffer *drawFb); extern GLboolean -_mesa_get_clamp_read_color(const struct gl_context *ctx); +_mesa_get_clamp_read_color(const struct gl_context *ctx, + const struct gl_framebuffer *readFb); extern void -_mesa_update_clamp_fragment_color(struct gl_context *ctx); +_mesa_update_clamp_fragment_color(struct gl_context *ctx, + const struct gl_framebuffer *drawFb); extern void -_mesa_update_clamp_vertex_color(struct gl_context *ctx); +_mesa_update_clamp_vertex_color(struct gl_context *ctx, + const struct gl_framebuffer *drawFb); extern mesa_format _mesa_get_render_format(const struct gl_context *ctx, mesa_format format); diff --git a/mesalib/src/mesa/main/blit.c b/mesalib/src/mesa/main/blit.c index 0694466eb..fac972450 100644 --- a/mesalib/src/mesa/main/blit.c +++ b/mesalib/src/mesa/main/blit.c @@ -34,6 +34,7 @@ #include "enums.h" #include "blit.h" #include "fbobject.h" +#include "framebuffer.h" #include "glformats.h" #include "mtypes.h" #include "state.h" @@ -148,38 +149,25 @@ is_valid_blit_filter(const struct gl_context *ctx, GLenum filter) } -/** - * Blit rectangular region, optionally from one framebuffer to another. - * - * Note, if the src buffer is multisampled and the dest is not, this is - * when the samples must be resolved to a single color. - */ -void GLAPIENTRY -_mesa_BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, - GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, - GLbitfield mask, GLenum filter) +void +_mesa_blit_framebuffer(struct gl_context *ctx, + struct gl_framebuffer *readFb, + struct gl_framebuffer *drawFb, + GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, + GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, + GLbitfield mask, GLenum filter, const char *func) { const GLbitfield legalMaskBits = (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - const struct gl_framebuffer *readFb, *drawFb; - GET_CURRENT_CONTEXT(ctx); FLUSH_VERTICES(ctx, 0); - if (MESA_VERBOSE & VERBOSE_API) - _mesa_debug(ctx, - "glBlitFramebuffer(%d, %d, %d, %d, %d, %d, %d, %d, 0x%x, %s)\n", - srcX0, srcY0, srcX1, srcY1, - dstX0, dstY0, dstX1, dstY1, - mask, _mesa_lookup_enum_by_nr(filter)); - - if (ctx->NewState) { - _mesa_update_state(ctx); - } + /* Update completeness status of readFb and drawFb. */ + _mesa_update_framebuffer(ctx, readFb, drawFb); - readFb = ctx->ReadBuffer; - drawFb = ctx->DrawBuffer; + /* Make sure drawFb has an initialized bounding box. */ + _mesa_update_draw_buffer_bounds(ctx, drawFb); if (!readFb || !drawFb) { /* This will normally never happen but someday we may want to @@ -192,12 +180,12 @@ _mesa_BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, if (drawFb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT || readFb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { _mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT, - "glBlitFramebufferEXT(incomplete draw/read buffers)"); + "%s(incomplete draw/read buffers)", func); return; } if (!is_valid_blit_filter(ctx, filter)) { - _mesa_error(ctx, GL_INVALID_ENUM, "glBlitFramebufferEXT(%s)", + _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid filter %s)", func, _mesa_lookup_enum_by_nr(filter)); return; } @@ -205,13 +193,13 @@ _mesa_BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, if ((filter == GL_SCALED_RESOLVE_FASTEST_EXT || filter == GL_SCALED_RESOLVE_NICEST_EXT) && (readFb->Visual.samples == 0 || drawFb->Visual.samples > 0)) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glBlitFramebufferEXT(%s)", + _mesa_error(ctx, GL_INVALID_OPERATION, "%s(%s: invalid samples)", func, _mesa_lookup_enum_by_nr(filter)); return; } if (mask & ~legalMaskBits) { - _mesa_error( ctx, GL_INVALID_VALUE, "glBlitFramebufferEXT(mask)"); + _mesa_error(ctx, GL_INVALID_VALUE, "%s(invalid mask bits set)", func); return; } @@ -219,13 +207,13 @@ _mesa_BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, if ((mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) && filter != GL_NEAREST) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glBlitFramebufferEXT(depth/stencil requires GL_NEAREST filter)"); + "%s(depth/stencil requires GL_NEAREST filter)", func); return; } /* get color read/draw renderbuffers */ if (mask & GL_COLOR_BUFFER_BIT) { - const GLuint numColorDrawBuffers = ctx->DrawBuffer->_NumColorDrawBuffers; + const GLuint numColorDrawBuffers = drawFb->_NumColorDrawBuffers; const struct gl_renderbuffer *colorReadRb = readFb->_ColorReadBuffer; const struct gl_renderbuffer *colorDrawRb = NULL; GLuint i; @@ -241,7 +229,7 @@ _mesa_BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, } else { for (i = 0; i < numColorDrawBuffers; i++) { - colorDrawRb = ctx->DrawBuffer->_ColorDrawBuffers[i]; + colorDrawRb = drawFb->_ColorDrawBuffers[i]; if (!colorDrawRb) continue; @@ -257,15 +245,15 @@ _mesa_BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, */ if (_mesa_is_gles3(ctx) && (colorDrawRb == colorReadRb)) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glBlitFramebuffer(source and destination color " - "buffer cannot be the same)"); + "%s(source and destination color " + "buffer cannot be the same)", func); return; } if (!compatible_color_datatypes(colorReadRb->Format, colorDrawRb->Format)) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glBlitFramebufferEXT(color buffer datatypes mismatch)"); + "%s(color buffer datatypes mismatch)", func); return; } /* extra checks for multisample copies... */ @@ -273,7 +261,7 @@ _mesa_BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, /* color formats must match */ if (!compatible_resolve_formats(colorReadRb, colorDrawRb)) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glBlitFramebufferEXT(bad src/dst multisample pixel formats)"); + "%s(bad src/dst multisample pixel formats)", func); return; } } @@ -286,7 +274,7 @@ _mesa_BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLenum type = _mesa_get_format_datatype(colorReadRb->Format); if (type == GL_INT || type == GL_UNSIGNED_INT) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glBlitFramebufferEXT(integer color type)"); + "%s(integer color type)", func); return; } } @@ -306,15 +294,15 @@ _mesa_BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, * ignored." */ if ((readRb == NULL) || (drawRb == NULL)) { - mask &= ~GL_STENCIL_BUFFER_BIT; + mask &= ~GL_STENCIL_BUFFER_BIT; } else { int read_z_bits, draw_z_bits; if (_mesa_is_gles3(ctx) && (drawRb == readRb)) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glBlitFramebuffer(source and destination stencil " - "buffer cannot be the same)"); + "%s(source and destination stencil " + "buffer cannot be the same)", func); return; } @@ -324,7 +312,7 @@ _mesa_BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, * there is only one: GL_UNSIGNED_INT. */ _mesa_error(ctx, GL_INVALID_OPERATION, - "glBlitFramebuffer(stencil attachment format mismatch)"); + "%s(stencil attachment format mismatch)", func); return; } @@ -340,8 +328,8 @@ _mesa_BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, _mesa_get_format_datatype(readRb->Format) != _mesa_get_format_datatype(drawRb->Format))) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glBlitFramebuffer" - "(stencil attachment depth format mismatch)"); + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(stencil attachment depth format mismatch)", func); return; } } @@ -360,15 +348,15 @@ _mesa_BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, * ignored." */ if ((readRb == NULL) || (drawRb == NULL)) { - mask &= ~GL_DEPTH_BUFFER_BIT; + mask &= ~GL_DEPTH_BUFFER_BIT; } else { int read_s_bit, draw_s_bit; if (_mesa_is_gles3(ctx) && (drawRb == readRb)) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glBlitFramebuffer(source and destination depth " - "buffer cannot be the same)"); + "%s(source and destination depth " + "buffer cannot be the same)", func); return; } @@ -377,7 +365,7 @@ _mesa_BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, (_mesa_get_format_datatype(readRb->Format) != _mesa_get_format_datatype(drawRb->Format))) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glBlitFramebuffer(depth attachment format mismatch)"); + "%s(depth attachment format mismatch)", func); return; } @@ -389,8 +377,8 @@ _mesa_BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, * we should ignore the stencil format check. */ if (read_s_bit > 0 && draw_s_bit > 0 && read_s_bit != draw_s_bit) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glBlitFramebuffer" - "(depth attachment stencil bits mismatch)"); + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(depth attachment stencil bits mismatch)", func); return; } } @@ -406,7 +394,7 @@ _mesa_BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, */ if (drawFb->Visual.samples > 0) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glBlitFramebuffer(destination samples must be 0)"); + "%s(destination samples must be 0)", func); return; } @@ -426,7 +414,7 @@ _mesa_BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, && (srcX0 != dstX0 || srcY0 != dstY0 || srcX1 != dstX1 || srcY1 != dstY1)) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glBlitFramebuffer(bad src/dst multisample region)"); + "%s(bad src/dst multisample region)", func); return; } } else { @@ -434,7 +422,7 @@ _mesa_BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, drawFb->Visual.samples > 0 && readFb->Visual.samples != drawFb->Visual.samples) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glBlitFramebufferEXT(mismatched samples)"); + "%s(mismatched samples)", func); return; } @@ -445,7 +433,7 @@ _mesa_BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, if (abs(srcX1 - srcX0) != abs(dstX1 - dstX0) || abs(srcY1 - srcY0) != abs(dstY1 - dstY0)) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glBlitFramebufferEXT(bad src/dst multisample region sizes)"); + "%s(bad src/dst multisample region sizes)", func); return; } } @@ -457,43 +445,44 @@ _mesa_BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, const struct gl_renderbuffer *colorDrawRb = NULL; GLuint i = 0; - printf("glBlitFramebuffer(%d, %d, %d, %d, %d, %d, %d, %d," - " 0x%x, 0x%x)\n", - srcX0, srcY0, srcX1, srcY1, - dstX0, dstY0, dstX1, dstY1, - mask, filter); + printf("%s(%d, %d, %d, %d, %d, %d, %d, %d," + " 0x%x, 0x%x)\n", func, + srcX0, srcY0, srcX1, srcY1, + dstX0, dstY0, dstX1, dstY1, + mask, filter); + if (colorReadRb) { const struct gl_renderbuffer_attachment *att; att = find_attachment(readFb, colorReadRb); printf(" Src FBO %u RB %u (%dx%d) ", - readFb->Name, colorReadRb->Name, - colorReadRb->Width, colorReadRb->Height); + readFb->Name, colorReadRb->Name, + colorReadRb->Width, colorReadRb->Height); if (att && att->Texture) { printf("Tex %u tgt 0x%x level %u face %u", - att->Texture->Name, - att->Texture->Target, - att->TextureLevel, - att->CubeMapFace); + att->Texture->Name, + att->Texture->Target, + att->TextureLevel, + att->CubeMapFace); } printf("\n"); /* Print all active color render buffers */ - for (i = 0; i < ctx->DrawBuffer->_NumColorDrawBuffers; i++) { - colorDrawRb = ctx->DrawBuffer->_ColorDrawBuffers[i]; + for (i = 0; i < drawFb->_NumColorDrawBuffers; i++) { + colorDrawRb = drawFb->_ColorDrawBuffers[i]; if (!colorDrawRb) continue; att = find_attachment(drawFb, colorDrawRb); printf(" Dst FBO %u RB %u (%dx%d) ", - drawFb->Name, colorDrawRb->Name, - colorDrawRb->Width, colorDrawRb->Height); + drawFb->Name, colorDrawRb->Name, + colorDrawRb->Width, colorDrawRb->Height); if (att && att->Texture) { printf("Tex %u tgt 0x%x level %u face %u", - att->Texture->Name, - att->Texture->Target, - att->TextureLevel, - att->CubeMapFace); + att->Texture->Name, + att->Texture->Target, + att->TextureLevel, + att->CubeMapFace); } printf("\n"); } @@ -507,8 +496,94 @@ _mesa_BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, } assert(ctx->Driver.BlitFramebuffer); - ctx->Driver.BlitFramebuffer(ctx, ctx->ReadBuffer, ctx->DrawBuffer, + ctx->Driver.BlitFramebuffer(ctx, readFb, drawFb, srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); } + + +/** + * Blit rectangular region, optionally from one framebuffer to another. + * + * Note, if the src buffer is multisampled and the dest is not, this is + * when the samples must be resolved to a single color. + */ +void GLAPIENTRY +_mesa_BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, + GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, + GLbitfield mask, GLenum filter) +{ + GET_CURRENT_CONTEXT(ctx); + + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, + "glBlitFramebuffer(%d, %d, %d, %d, " + " %d, %d, %d, %d, 0x%x, %s)\n", + srcX0, srcY0, srcX1, srcY1, + dstX0, dstY0, dstX1, dstY1, + mask, _mesa_lookup_enum_by_nr(filter)); + + _mesa_blit_framebuffer(ctx, ctx->ReadBuffer, ctx->DrawBuffer, + srcX0, srcY0, srcX1, srcY1, + dstX0, dstY0, dstX1, dstY1, + mask, filter, "glBlitFramebuffer"); +} + + +void GLAPIENTRY +_mesa_BlitNamedFramebuffer(GLuint readFramebuffer, GLuint drawFramebuffer, + GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, + GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, + GLbitfield mask, GLenum filter) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_framebuffer *readFb, *drawFb; + + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glBlitNamedFramebuffer(GL_ARB_direct_state_access " + "is not supported)"); + return; + } + + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, + "glBlitNamedFramebuffer(%u %u %d, %d, %d, %d, " + " %d, %d, %d, %d, 0x%x, %s)\n", + readFramebuffer, drawFramebuffer, + srcX0, srcY0, srcX1, srcY1, + dstX0, dstY0, dstX1, dstY1, + mask, _mesa_lookup_enum_by_nr(filter)); + + /* + * According to PDF page 533 of the OpenGL 4.5 core spec (30.10.2014, + * Section 18.3 Copying Pixels): + * "... if readFramebuffer or drawFramebuffer is zero (for + * BlitNamedFramebuffer), then the default read or draw framebuffer is + * used as the corresponding source or destination framebuffer, + * respectively." + */ + if (readFramebuffer) { + readFb = _mesa_lookup_framebuffer_err(ctx, readFramebuffer, + "glBlitNamedFramebuffer"); + if (!readFb) + return; + } + else + readFb = ctx->WinSysReadBuffer; + + if (drawFramebuffer) { + drawFb = _mesa_lookup_framebuffer_err(ctx, drawFramebuffer, + "glBlitNamedFramebuffer"); + if (!drawFb) + return; + } + else + drawFb = ctx->WinSysDrawBuffer; + + _mesa_blit_framebuffer(ctx, readFb, drawFb, + srcX0, srcY0, srcX1, srcY1, + dstX0, dstY0, dstX1, dstY1, + mask, filter, "glBlitNamedFramebuffer"); +} diff --git a/mesalib/src/mesa/main/blit.h b/mesalib/src/mesa/main/blit.h index 01a958af5..54b946e31 100644 --- a/mesalib/src/mesa/main/blit.h +++ b/mesalib/src/mesa/main/blit.h @@ -28,11 +28,24 @@ #include "glheader.h" +extern void +_mesa_blit_framebuffer(struct gl_context *ctx, + struct gl_framebuffer *readFb, + struct gl_framebuffer *drawFb, + GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, + GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, + GLbitfield mask, GLenum filter, const char *func); extern void GLAPIENTRY _mesa_BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); +extern void GLAPIENTRY +_mesa_BlitNamedFramebuffer(GLuint readFramebuffer, GLuint drawFramebuffer, + GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, + GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, + GLbitfield mask, GLenum filter); + #endif /* BLIT_H */ diff --git a/mesalib/src/mesa/main/bufferobj.c b/mesalib/src/mesa/main/bufferobj.c index 66dee6802..660bc9489 100644 --- a/mesalib/src/mesa/main/bufferobj.c +++ b/mesalib/src/mesa/main/bufferobj.c @@ -1303,6 +1303,12 @@ create_buffers(GLsizei n, GLuint *buffers, bool dsa) const char *func = dsa ? "glCreateBuffers" : "glGenBuffers"; + if (dsa && !ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(GL_ARB_direct_state_access is not supported)", func); + return; + } + if (MESA_VERBOSE & VERBOSE_API) _mesa_debug(ctx, "%s(%d)\n", func, n); @@ -1477,6 +1483,13 @@ _mesa_NamedBufferStorage(GLuint buffer, GLsizeiptr size, const GLvoid *data, GET_CURRENT_CONTEXT(ctx); struct gl_buffer_object *bufObj; + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glNamedBufferStorage(GL_ARB_direct_state_access " + "is not supported)"); + return; + } + bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, "glNamedBufferStorage"); if (!bufObj) return; @@ -1603,6 +1616,13 @@ _mesa_NamedBufferData(GLuint buffer, GLsizeiptr size, const GLvoid *data, GET_CURRENT_CONTEXT(ctx); struct gl_buffer_object *bufObj; + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glNamedBufferData(GL_ARB_direct_state_access " + "is not supported)"); + return; + } + bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, "glNamedBufferData"); if (!bufObj) return; @@ -1673,6 +1693,13 @@ _mesa_NamedBufferSubData(GLuint buffer, GLintptr offset, GET_CURRENT_CONTEXT(ctx); struct gl_buffer_object *bufObj; + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glNamedBufferSubData(GL_ARB_direct_state_access " + "is not supported)"); + return; + } + bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, "glNamedBufferSubData"); if (!bufObj) return; @@ -1710,6 +1737,13 @@ _mesa_GetNamedBufferSubData(GLuint buffer, GLintptr offset, GET_CURRENT_CONTEXT(ctx); struct gl_buffer_object *bufObj; + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetNamedBufferSubData(GL_ARB_direct_state_access " + "is not supported)"); + return; + } + bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, "glGetNamedBufferSubData"); if (!bufObj) @@ -1805,6 +1839,13 @@ _mesa_ClearNamedBufferData(GLuint buffer, GLenum internalformat, GET_CURRENT_CONTEXT(ctx); struct gl_buffer_object *bufObj; + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glClearNamedBufferData(GL_ARB_direct_state_access " + "is not supported)"); + return; + } + bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, "glClearNamedBufferData"); if (!bufObj) return; @@ -1842,6 +1883,13 @@ _mesa_ClearNamedBufferSubData(GLuint buffer, GLenum internalformat, GET_CURRENT_CONTEXT(ctx); struct gl_buffer_object *bufObj; + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glClearNamedBufferSubData(GL_ARB_direct_state_access " + "is not supported)"); + return; + } + bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, "glClearNamedBufferSubData"); if (!bufObj) @@ -1930,6 +1978,13 @@ _mesa_UnmapNamedBuffer(GLuint buffer) GET_CURRENT_CONTEXT(ctx); struct gl_buffer_object *bufObj; + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glUnmapNamedBuffer(GL_ARB_direct_state_access " + "is not supported)"); + return GL_FALSE; + } + bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, "glUnmapNamedBuffer"); if (!bufObj) return GL_FALSE; @@ -2039,6 +2094,13 @@ _mesa_GetNamedBufferParameteriv(GLuint buffer, GLenum pname, GLint *params) struct gl_buffer_object *bufObj; GLint64 parameter; + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetNamedBufferParameteriv(GL_ARB_direct_state_access " + "is not supported)"); + return; + } + bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, "glGetNamedBufferParameteriv"); if (!bufObj) @@ -2059,6 +2121,13 @@ _mesa_GetNamedBufferParameteri64v(GLuint buffer, GLenum pname, struct gl_buffer_object *bufObj; GLint64 parameter; + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetNamedBufferParameteri64v(GL_ARB_direct_state_access " + "is not supported)"); + return; + } + bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, "glGetNamedBufferParameteri64v"); if (!bufObj) @@ -2098,6 +2167,13 @@ _mesa_GetNamedBufferPointerv(GLuint buffer, GLenum pname, GLvoid **params) GET_CURRENT_CONTEXT(ctx); struct gl_buffer_object *bufObj; + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetNamedBufferPointerv(GL_ARB_direct_state_access " + "is not supported)"); + return; + } + if (pname != GL_BUFFER_MAP_POINTER) { _mesa_error(ctx, GL_INVALID_ENUM, "glGetNamedBufferPointerv(pname != " "GL_BUFFER_MAP_POINTER)"); @@ -2212,6 +2288,13 @@ _mesa_CopyNamedBufferSubData(GLuint readBuffer, GLuint writeBuffer, GET_CURRENT_CONTEXT(ctx); struct gl_buffer_object *src, *dst; + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glCopyNamedBufferSubData(GL_ARB_direct_state_access " + "is not supported)"); + return; + } + src = _mesa_lookup_bufferobj_err(ctx, readBuffer, "glCopyNamedBufferSubData"); if (!src) @@ -2430,6 +2513,13 @@ _mesa_MapNamedBufferRange(GLuint buffer, GLintptr offset, GLsizeiptr length, GET_CURRENT_CONTEXT(ctx); struct gl_buffer_object *bufObj; + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glMapNamedBufferRange(GL_ARB_direct_state_access " + "is not supported)"); + return NULL; + } + if (!ctx->Extensions.ARB_map_buffer_range) { _mesa_error(ctx, GL_INVALID_OPERATION, "glMapNamedBufferRange(" @@ -2497,6 +2587,13 @@ _mesa_MapNamedBuffer(GLuint buffer, GLenum access) struct gl_buffer_object *bufObj; GLbitfield accessFlags; + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glMapNamedBuffer(GL_ARB_direct_state_access " + "is not supported)"); + return NULL; + } + if (!get_map_buffer_access_flags(ctx, access, &accessFlags)) { _mesa_error(ctx, GL_INVALID_ENUM, "glMapNamedBuffer(invalid access)"); return NULL; @@ -2587,6 +2684,14 @@ _mesa_FlushMappedNamedBufferRange(GLuint buffer, GLintptr offset, GET_CURRENT_CONTEXT(ctx); struct gl_buffer_object *bufObj; + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glFlushMappedNamedBufferRange(GL_ARB_direct_state_access " + "is not supported)"); + return; + } + + bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, "glFlushMappedNamedBufferRange"); if (!bufObj) diff --git a/mesalib/src/mesa/main/buffers.c b/mesalib/src/mesa/main/buffers.c index 37a979092..c83459add 100644 --- a/mesalib/src/mesa/main/buffers.c +++ b/mesalib/src/mesa/main/buffers.c @@ -242,16 +242,16 @@ read_buffer_enum_to_index(GLenum buffer) * * See the GL_EXT_framebuffer_object spec for more info. */ -void GLAPIENTRY -_mesa_DrawBuffer(GLenum buffer) +void +_mesa_draw_buffer(struct gl_context *ctx, struct gl_framebuffer *fb, + GLenum buffer, const char *caller) { GLbitfield destMask; - GET_CURRENT_CONTEXT(ctx); FLUSH_VERTICES(ctx, 0); if (MESA_VERBOSE & VERBOSE_API) { - _mesa_debug(ctx, "glDrawBuffer %s\n", _mesa_lookup_enum_by_nr(buffer)); + _mesa_debug(ctx, "%s %s\n", caller, _mesa_lookup_enum_by_nr(buffer)); } if (buffer == GL_NONE) { @@ -259,33 +259,67 @@ _mesa_DrawBuffer(GLenum buffer) } else { const GLbitfield supportedMask - = supported_buffer_bitmask(ctx, ctx->DrawBuffer); + = supported_buffer_bitmask(ctx, fb); destMask = draw_buffer_enum_to_bitmask(ctx, buffer); if (destMask == BAD_MASK) { /* totally bogus buffer */ - _mesa_error(ctx, GL_INVALID_ENUM, - "glDrawBuffer(buffer=0x%x)", buffer); + _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid buffer %s)", caller, + _mesa_lookup_enum_by_nr(buffer)); return; } destMask &= supportedMask; if (destMask == 0x0) { /* none of the named color buffers exist! */ - _mesa_error(ctx, GL_INVALID_OPERATION, - "glDrawBuffer(buffer=0x%x)", buffer); + _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid buffer %s)", + caller, _mesa_lookup_enum_by_nr(buffer)); return; } } /* if we get here, there's no error so set new state */ - _mesa_drawbuffers(ctx, 1, &buffer, &destMask); + _mesa_drawbuffers(ctx, fb, 1, &buffer, &destMask); + + /* Call device driver function only if fb is the bound draw buffer */ + if (fb == ctx->DrawBuffer) { + if (ctx->Driver.DrawBuffers) + ctx->Driver.DrawBuffers(ctx, 1, &buffer); + else if (ctx->Driver.DrawBuffer) + ctx->Driver.DrawBuffer(ctx, buffer); + } +} - /* - * Call device driver function. - */ - if (ctx->Driver.DrawBuffers) - ctx->Driver.DrawBuffers(ctx, 1, &buffer); - else if (ctx->Driver.DrawBuffer) - ctx->Driver.DrawBuffer(ctx, buffer); + +void GLAPIENTRY +_mesa_DrawBuffer(GLenum buffer) +{ + GET_CURRENT_CONTEXT(ctx); + _mesa_draw_buffer(ctx, ctx->DrawBuffer, buffer, "glDrawBuffer"); +} + + +void GLAPIENTRY +_mesa_NamedFramebufferDrawBuffer(GLuint framebuffer, GLenum buf) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_framebuffer *fb; + + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glNamedFramebufferDrawBuffer(GL_ARB_direct_state_access " + "is not supported)"); + return; + } + + if (framebuffer) { + fb = _mesa_lookup_framebuffer_err(ctx, framebuffer, + "glNamedFramebufferDrawBuffer"); + if (!fb) + return; + } + else + fb = ctx->WinSysDrawBuffer; + + _mesa_draw_buffer(ctx, fb, buf, "glNamedFramebufferDrawBuffer"); } @@ -298,13 +332,13 @@ _mesa_DrawBuffer(GLenum buffer) * names cannot specify more than one buffer. For example, * GL_FRONT_AND_BACK is illegal. */ -void GLAPIENTRY -_mesa_DrawBuffers(GLsizei n, const GLenum *buffers) +void +_mesa_draw_buffers(struct gl_context *ctx, struct gl_framebuffer *fb, + GLsizei n, const GLenum *buffers, const char *caller) { GLuint output; GLbitfield usedBufferMask, supportedMask; GLbitfield destMask[MAX_DRAW_BUFFERS]; - GET_CURRENT_CONTEXT(ctx); FLUSH_VERTICES(ctx, 0); @@ -315,12 +349,18 @@ _mesa_DrawBuffers(GLsizei n, const GLenum *buffers) * "An INVALID_VALUE error is generated if n is greater than * MAX_DRAW_BUFFERS." */ - if (n < 0 || n > (GLsizei) ctx->Const.MaxDrawBuffers) { - _mesa_error(ctx, GL_INVALID_VALUE, "glDrawBuffersARB(n)"); + if (n < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, "%s(n < 0)", caller); + return; + } + + if (n > (GLsizei) ctx->Const.MaxDrawBuffers) { + _mesa_error(ctx, GL_INVALID_VALUE, + "%s(n > maximum number of draw buffers)", caller); return; } - supportedMask = supported_buffer_bitmask(ctx, ctx->DrawBuffer); + supportedMask = supported_buffer_bitmask(ctx, fb); usedBufferMask = 0x0; /* From the ES 3.0 specification, page 180: @@ -328,9 +368,9 @@ _mesa_DrawBuffers(GLsizei n, const GLenum *buffers) * and the constant must be BACK or NONE." * (same restriction applies with GL_EXT_draw_buffers specification) */ - if (ctx->API == API_OPENGLES2 && _mesa_is_winsys_fbo(ctx->DrawBuffer) && + if (ctx->API == API_OPENGLES2 && _mesa_is_winsys_fbo(fb) && (n != 1 || (buffers[0] != GL_NONE && buffers[0] != GL_BACK))) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glDrawBuffers(buffer)"); + _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid buffers)", caller); return; } @@ -362,9 +402,11 @@ _mesa_DrawBuffers(GLsizei n, const GLenum *buffers) * or equal to the value of MAX_COLOR_ATTACHMENTS, then the error * INVALID_OPERATION results." */ - if (_mesa_is_user_fbo(ctx->DrawBuffer) && buffers[output] >= + if (_mesa_is_user_fbo(fb) && buffers[output] >= GL_COLOR_ATTACHMENT0 + ctx->Const.MaxDrawBuffers) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glDrawBuffersARB(buffer)"); + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(buffers[%d] >= maximum number of draw buffers)", + caller, output); return; } @@ -375,9 +417,10 @@ _mesa_DrawBuffers(GLsizei n, const GLenum *buffers) * 4.5 or 4.6. Otherwise, an INVALID_ENUM error is generated. */ if (destMask[output] == BAD_MASK) { - _mesa_error(ctx, GL_INVALID_ENUM, "glDrawBuffersARB(buffer)"); + _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid buffer %s)", + caller, _mesa_lookup_enum_by_nr(buffers[output])); return; - } + } /* From the OpenGL 4.0 specification, page 256: * "For both the default framebuffer and framebuffer objects, the @@ -390,7 +433,8 @@ _mesa_DrawBuffers(GLsizei n, const GLenum *buffers) * but the Khronos conformance tests expect INVALID_ENUM. */ if (_mesa_bitcount(destMask[output]) > 1) { - _mesa_error(ctx, GL_INVALID_ENUM, "glDrawBuffersARB(buffer)"); + _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid buffer %s)", + caller, _mesa_lookup_enum_by_nr(buffers[output])); return; } @@ -407,7 +451,8 @@ _mesa_DrawBuffers(GLsizei n, const GLenum *buffers) destMask[output] &= supportedMask; if (destMask[output] == 0) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glDrawBuffersARB(unsupported buffer)"); + "%s(unsupported buffer %s)", + caller, _mesa_lookup_enum_by_nr(buffers[output])); return; } @@ -416,10 +461,12 @@ _mesa_DrawBuffers(GLsizei n, const GLenum *buffers) * in bufs must be COLOR_ATTACHMENTi or NONE. [...] INVALID_OPERATION." * (same restriction applies with GL_EXT_draw_buffers specification) */ - if (ctx->API == API_OPENGLES2 && _mesa_is_user_fbo(ctx->DrawBuffer) && + if (ctx->API == API_OPENGLES2 && _mesa_is_user_fbo(fb) && buffers[output] != GL_NONE && buffers[output] != GL_COLOR_ATTACHMENT0 + output) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glDrawBuffers(buffer)"); + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(unsupported buffer %s)", + caller, _mesa_lookup_enum_by_nr(buffers[output])); return; } @@ -430,7 +477,8 @@ _mesa_DrawBuffers(GLsizei n, const GLenum *buffers) */ if (destMask[output] & usedBufferMask) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glDrawBuffersARB(duplicated buffer)"); + "%s(duplicated buffer %s)", + caller, _mesa_lookup_enum_by_nr(buffers[output])); return; } @@ -440,17 +488,55 @@ _mesa_DrawBuffers(GLsizei n, const GLenum *buffers) } /* OK, if we get here, there were no errors so set the new state */ - _mesa_drawbuffers(ctx, n, buffers, destMask); + _mesa_drawbuffers(ctx, fb, n, buffers, destMask); /* - * Call device driver function. Note that n can be equal to 0, + * Call device driver function if fb is the bound draw buffer. + * Note that n can be equal to 0, * in which case we don't want to reference buffers[0], which * may not be valid. */ - if (ctx->Driver.DrawBuffers) - ctx->Driver.DrawBuffers(ctx, n, buffers); - else if (ctx->Driver.DrawBuffer) - ctx->Driver.DrawBuffer(ctx, n > 0 ? buffers[0] : GL_NONE); + if (fb == ctx->DrawBuffer) { + if (ctx->Driver.DrawBuffers) + ctx->Driver.DrawBuffers(ctx, n, buffers); + else if (ctx->Driver.DrawBuffer) + ctx->Driver.DrawBuffer(ctx, n > 0 ? buffers[0] : GL_NONE); + } +} + + +void GLAPIENTRY +_mesa_DrawBuffers(GLsizei n, const GLenum *buffers) +{ + GET_CURRENT_CONTEXT(ctx); + _mesa_draw_buffers(ctx, ctx->DrawBuffer, n, buffers, "glDrawBuffers"); +} + + +void GLAPIENTRY +_mesa_NamedFramebufferDrawBuffers(GLuint framebuffer, GLsizei n, + const GLenum *bufs) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_framebuffer *fb; + + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glNamedFramebufferDrawBuffers(GL_ARB_direct_state_access " + "is not supported)"); + return; + } + + if (framebuffer) { + fb = _mesa_lookup_framebuffer_err(ctx, framebuffer, + "glNamedFramebufferDrawBuffers"); + if (!fb) + return; + } + else + fb = ctx->WinSysDrawBuffer; + + _mesa_draw_buffers(ctx, fb, n, bufs, "glNamedFramebufferDrawBuffers"); } @@ -459,13 +545,11 @@ _mesa_DrawBuffers(GLsizei n, const GLenum *buffers) * actual change. */ static void -updated_drawbuffers(struct gl_context *ctx) +updated_drawbuffers(struct gl_context *ctx, struct gl_framebuffer *fb) { FLUSH_VERTICES(ctx, _NEW_BUFFERS); if (ctx->API == API_OPENGL_COMPAT && !ctx->Extensions.ARB_ES2_compatibility) { - struct gl_framebuffer *fb = ctx->DrawBuffer; - /* Flag the FBO as requiring validation. */ if (_mesa_is_user_fbo(fb)) { fb->_Status = 0; @@ -482,6 +566,7 @@ updated_drawbuffers(struct gl_context *ctx) * so nothing should go wrong at this point. * * \param ctx current context + * \param fb the desired draw buffer * \param n number of color outputs to set * \param buffers array[n] of colorbuffer names, like GL_LEFT. * \param destMask array[n] of BUFFER_BIT_* bitmasks which correspond to the @@ -489,10 +574,9 @@ updated_drawbuffers(struct gl_context *ctx) * BUFFER_BIT_FRONT_LEFT | BUFFER_BIT_BACK_LEFT). */ void -_mesa_drawbuffers(struct gl_context *ctx, GLuint n, const GLenum *buffers, - const GLbitfield *destMask) +_mesa_drawbuffers(struct gl_context *ctx, struct gl_framebuffer *fb, + GLuint n, const GLenum *buffers, const GLbitfield *destMask) { - struct gl_framebuffer *fb = ctx->DrawBuffer; GLbitfield mask[MAX_DRAW_BUFFERS]; GLuint buf; @@ -518,7 +602,7 @@ _mesa_drawbuffers(struct gl_context *ctx, GLuint n, const GLenum *buffers, while (destMask0) { GLint bufIndex = ffs(destMask0) - 1; if (fb->_ColorDrawBufferIndexes[count] != bufIndex) { - updated_drawbuffers(ctx); + updated_drawbuffers(ctx, fb); fb->_ColorDrawBufferIndexes[count] = bufIndex; } count++; @@ -535,14 +619,14 @@ _mesa_drawbuffers(struct gl_context *ctx, GLuint n, const GLenum *buffers, /* only one bit should be set in the destMask[buf] field */ assert(_mesa_bitcount(destMask[buf]) == 1); if (fb->_ColorDrawBufferIndexes[buf] != bufIndex) { - updated_drawbuffers(ctx); + updated_drawbuffers(ctx, fb); fb->_ColorDrawBufferIndexes[buf] = bufIndex; } count = buf + 1; } else { if (fb->_ColorDrawBufferIndexes[buf] != -1) { - updated_drawbuffers(ctx); + updated_drawbuffers(ctx, fb); fb->_ColorDrawBufferIndexes[buf] = -1; } } @@ -554,7 +638,7 @@ _mesa_drawbuffers(struct gl_context *ctx, GLuint n, const GLenum *buffers, /* set remaining outputs to -1 (GL_NONE) */ for (buf = fb->_NumColorDrawBuffers; buf < ctx->Const.MaxDrawBuffers; buf++) { if (fb->_ColorDrawBufferIndexes[buf] != -1) { - updated_drawbuffers(ctx); + updated_drawbuffers(ctx, fb); fb->_ColorDrawBufferIndexes[buf] = -1; } } @@ -566,7 +650,7 @@ _mesa_drawbuffers(struct gl_context *ctx, GLuint n, const GLenum *buffers, /* also set context drawbuffer state */ for (buf = 0; buf < ctx->Const.MaxDrawBuffers; buf++) { if (ctx->Color.DrawBuffer[buf] != fb->ColorDrawBuffer[buf]) { - updated_drawbuffers(ctx); + updated_drawbuffers(ctx, fb); ctx->Color.DrawBuffer[buf] = fb->ColorDrawBuffer[buf]; } } @@ -585,7 +669,7 @@ _mesa_update_draw_buffers(struct gl_context *ctx) /* should be a window system FBO */ assert(_mesa_is_winsys_fbo(ctx->DrawBuffer)); - _mesa_drawbuffers(ctx, ctx->Const.MaxDrawBuffers, + _mesa_drawbuffers(ctx, ctx->DrawBuffer, ctx->Const.MaxDrawBuffers, ctx->Color.DrawBuffer, NULL); } @@ -598,11 +682,10 @@ _mesa_update_draw_buffers(struct gl_context *ctx) * \param bufferIndex the numerical index corresponding to 'buffer' */ void -_mesa_readbuffer(struct gl_context *ctx, GLenum buffer, GLint bufferIndex) +_mesa_readbuffer(struct gl_context *ctx, struct gl_framebuffer *fb, + GLenum buffer, GLint bufferIndex) { - struct gl_framebuffer *fb = ctx->ReadBuffer; - - if (_mesa_is_winsys_fbo(fb)) { + if ((fb == ctx->ReadBuffer) && _mesa_is_winsys_fbo(fb)) { /* Only update the per-context READ_BUFFER state if we're bound to * a window-system framebuffer. */ @@ -621,23 +704,17 @@ _mesa_readbuffer(struct gl_context *ctx, GLenum buffer, GLint bufferIndex) * Called by glReadBuffer to set the source renderbuffer for reading pixels. * \param mode color buffer such as GL_FRONT, GL_BACK, etc. */ -void GLAPIENTRY -_mesa_ReadBuffer(GLenum buffer) +void +_mesa_read_buffer(struct gl_context *ctx, struct gl_framebuffer *fb, + GLenum buffer, const char *caller) { - struct gl_framebuffer *fb; GLbitfield supportedMask; GLint srcBuffer; - GET_CURRENT_CONTEXT(ctx); FLUSH_VERTICES(ctx, 0); if (MESA_VERBOSE & VERBOSE_API) - _mesa_debug(ctx, "glReadBuffer %s\n", _mesa_lookup_enum_by_nr(buffer)); - - fb = ctx->ReadBuffer; - - if (MESA_VERBOSE & VERBOSE_API) - _mesa_debug(ctx, "glReadBuffer %s\n", _mesa_lookup_enum_by_nr(buffer)); + _mesa_debug(ctx, "%s %s\n", caller, _mesa_lookup_enum_by_nr(buffer)); if (buffer == GL_NONE) { /* This is legal--it means that no buffer should be bound for reading. */ @@ -648,24 +725,60 @@ _mesa_ReadBuffer(GLenum buffer) srcBuffer = read_buffer_enum_to_index(buffer); if (srcBuffer == -1) { _mesa_error(ctx, GL_INVALID_ENUM, - "glReadBuffer(buffer=0x%x)", buffer); + "%s(invalid buffer %s)", caller, + _mesa_lookup_enum_by_nr(buffer)); return; } supportedMask = supported_buffer_bitmask(ctx, fb); if (((1 << srcBuffer) & supportedMask) == 0) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glReadBuffer(buffer=0x%x)", buffer); + "%s(invalid buffer %s)", caller, + _mesa_lookup_enum_by_nr(buffer)); return; } } /* OK, all error checking has been completed now */ - _mesa_readbuffer(ctx, buffer, srcBuffer); + _mesa_readbuffer(ctx, fb, buffer, srcBuffer); - /* - * Call device driver function. - */ - if (ctx->Driver.ReadBuffer) - (*ctx->Driver.ReadBuffer)(ctx, buffer); + /* Call the device driver function only if fb is the bound read buffer */ + if (fb == ctx->ReadBuffer) { + if (ctx->Driver.ReadBuffer) + (*ctx->Driver.ReadBuffer)(ctx, buffer); + } +} + + +void GLAPIENTRY +_mesa_ReadBuffer(GLenum buffer) +{ + GET_CURRENT_CONTEXT(ctx); + _mesa_read_buffer(ctx, ctx->ReadBuffer, buffer, "glReadBuffer"); +} + + +void GLAPIENTRY +_mesa_NamedFramebufferReadBuffer(GLuint framebuffer, GLenum src) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_framebuffer *fb; + + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glNamedFramebufferReadBuffer(GL_ARB_direct_state_access " + "is not supported)"); + return; + } + + if (framebuffer) { + fb = _mesa_lookup_framebuffer_err(ctx, framebuffer, + "glNamedFramebufferReadBuffer"); + if (!fb) + return; + } + else + fb = ctx->WinSysReadBuffer; + + _mesa_read_buffer(ctx, fb, src, "glNamedFramebufferReadBuffer"); } diff --git a/mesalib/src/mesa/main/buffers.h b/mesalib/src/mesa/main/buffers.h index ebcfa1c1e..5aa79fda5 100644 --- a/mesalib/src/mesa/main/buffers.h +++ b/mesalib/src/mesa/main/buffers.h @@ -36,26 +36,51 @@ #include "glheader.h" struct gl_context; +struct gl_framebuffer; + +extern void +_mesa_draw_buffer(struct gl_context *ctx, struct gl_framebuffer *fb, + GLenum buffer, const char *caller); extern void GLAPIENTRY _mesa_DrawBuffer( GLenum mode ); extern void GLAPIENTRY +_mesa_NamedFramebufferDrawBuffer(GLuint framebuffer, GLenum buf); + +extern void +_mesa_draw_buffers(struct gl_context *ctx, struct gl_framebuffer *fb, + GLsizei n, const GLenum *buffers, const char *caller); + +extern void GLAPIENTRY _mesa_DrawBuffers(GLsizei n, const GLenum *buffers); +extern void GLAPIENTRY +_mesa_NamedFramebufferDrawBuffers(GLuint framebuffer, GLsizei n, + const GLenum *bufs); + extern void -_mesa_drawbuffers(struct gl_context *ctx, GLuint n, const GLenum *buffers, +_mesa_drawbuffers(struct gl_context *ctx, struct gl_framebuffer *fb, + GLuint n, const GLenum *buffers, const GLbitfield *destMask); extern void -_mesa_readbuffer(struct gl_context *ctx, GLenum buffer, GLint bufferIndex); +_mesa_readbuffer(struct gl_context *ctx, struct gl_framebuffer *fb, + GLenum buffer, GLint bufferIndex); extern void _mesa_update_draw_buffers(struct gl_context *ctx); +extern void +_mesa_read_buffer(struct gl_context *ctx, struct gl_framebuffer *fb, + GLenum buffer, const char *caller); + extern void GLAPIENTRY _mesa_ReadBuffer( GLenum mode ); +extern void GLAPIENTRY +_mesa_NamedFramebufferReadBuffer(GLuint framebuffer, GLenum src); + #endif diff --git a/mesalib/src/mesa/main/clear.c b/mesalib/src/mesa/main/clear.c index 8d707bc34..c6999f7fd 100644 --- a/mesalib/src/mesa/main/clear.c +++ b/mesalib/src/mesa/main/clear.c @@ -34,6 +34,8 @@ #include "clear.h" #include "context.h" #include "enums.h" +#include "fbobject.h" +#include "get.h" #include "macros.h" #include "mtypes.h" #include "state.h" @@ -400,6 +402,32 @@ _mesa_ClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint *value) /** + * The ClearBuffer framework is so complicated and so riddled with the + * assumption that the framebuffer is bound that, for now, we will just fake + * direct state access clearing for the user. + */ +void GLAPIENTRY +_mesa_ClearNamedFramebufferiv(GLuint framebuffer, GLenum buffer, + GLint drawbuffer, const GLint *value) +{ + GLint oldfb; + + GET_CURRENT_CONTEXT(ctx); + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glClearNamedFramebufferiv(GL_ARB_direct_state_access " + "is not supported)"); + return; + } + + _mesa_GetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &oldfb); + _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer); + _mesa_ClearBufferiv(buffer, drawbuffer, value); + _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER, (GLuint) oldfb); +} + + +/** * New in GL 3.0 * Clear unsigned integer color buffer (not depth, not stencil). */ @@ -472,6 +500,32 @@ _mesa_ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint *value) /** + * The ClearBuffer framework is so complicated and so riddled with the + * assumption that the framebuffer is bound that, for now, we will just fake + * direct state access clearing for the user. + */ +void GLAPIENTRY +_mesa_ClearNamedFramebufferuiv(GLuint framebuffer, GLenum buffer, + GLint drawbuffer, const GLuint *value) +{ + GLint oldfb; + + GET_CURRENT_CONTEXT(ctx); + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glClearNamedFramebufferuiv(GL_ARB_direct_state_access " + "is not supported)"); + return; + } + + _mesa_GetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &oldfb); + _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer); + _mesa_ClearBufferuiv(buffer, drawbuffer, value); + _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER, (GLuint) oldfb); +} + + +/** * New in GL 3.0 * Clear fixed-pt or float color buffer or depth buffer (not stencil). */ @@ -565,6 +619,32 @@ _mesa_ClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat *value) /** + * The ClearBuffer framework is so complicated and so riddled with the + * assumption that the framebuffer is bound that, for now, we will just fake + * direct state access clearing for the user. + */ +void GLAPIENTRY +_mesa_ClearNamedFramebufferfv(GLuint framebuffer, GLenum buffer, + GLint drawbuffer, const GLfloat *value) +{ + GLint oldfb; + + GET_CURRENT_CONTEXT(ctx); + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glClearNamedFramebufferfv(GL_ARB_direct_state_access " + "is not supported)"); + return; + } + + _mesa_GetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &oldfb); + _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer); + _mesa_ClearBufferfv(buffer, drawbuffer, value); + _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER, (GLuint) oldfb); +} + + +/** * New in GL 3.0 * Clear depth/stencil buffer only. */ @@ -626,3 +706,29 @@ _mesa_ClearBufferfi(GLenum buffer, GLint drawbuffer, ctx->Stencil.Clear = clearStencilSave; } } + + +/** + * The ClearBuffer framework is so complicated and so riddled with the + * assumption that the framebuffer is bound that, for now, we will just fake + * direct state access clearing for the user. + */ +void GLAPIENTRY +_mesa_ClearNamedFramebufferfi(GLuint framebuffer, GLenum buffer, + GLfloat depth, GLint stencil) +{ + GLint oldfb; + + GET_CURRENT_CONTEXT(ctx); + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glClearNamedFramebufferfi(GL_ARB_direct_state_access " + "is not supported)"); + return; + } + + _mesa_GetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &oldfb); + _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer); + _mesa_ClearBufferfi(buffer, 0, depth, stencil); + _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER, (GLuint) oldfb); +} diff --git a/mesalib/src/mesa/main/clear.h b/mesalib/src/mesa/main/clear.h index 96ce47b92..c29850676 100644 --- a/mesalib/src/mesa/main/clear.h +++ b/mesalib/src/mesa/main/clear.h @@ -52,13 +52,29 @@ extern void GLAPIENTRY _mesa_ClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint *value); extern void GLAPIENTRY +_mesa_ClearNamedFramebufferiv(GLuint framebuffer, GLenum buffer, + GLint drawbuffer, const GLint *value); + +extern void GLAPIENTRY _mesa_ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint *value); extern void GLAPIENTRY +_mesa_ClearNamedFramebufferuiv(GLuint framebuffer, GLenum buffer, + GLint drawbuffer, const GLuint *value); + +extern void GLAPIENTRY _mesa_ClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat *value); extern void GLAPIENTRY +_mesa_ClearNamedFramebufferfv(GLuint framebuffer, GLenum buffer, + GLint drawbuffer, const GLfloat *value); + +extern void GLAPIENTRY _mesa_ClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); +extern void GLAPIENTRY +_mesa_ClearNamedFramebufferfi(GLuint framebuffer, GLenum buffer, + GLfloat depth, GLint stencil); + #endif diff --git a/mesalib/src/mesa/main/compute.c b/mesalib/src/mesa/main/compute.c index 5756666b6..37a4ba70e 100644 --- a/mesalib/src/mesa/main/compute.c +++ b/mesalib/src/mesa/main/compute.c @@ -31,9 +31,27 @@ _mesa_DispatchCompute(GLuint num_groups_x, GLuint num_groups_z) { GET_CURRENT_CONTEXT(ctx); + int i; + struct gl_shader_program *prog; + const GLuint num_groups[3] = { num_groups_x, num_groups_y, num_groups_z }; if (ctx->Extensions.ARB_compute_shader) { - assert(!"TODO"); + for (i = 0; i < 3; i++) { + if (num_groups[i] > ctx->Const.MaxComputeWorkGroupCount[i]) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glDispatchCompute(num_groups_%c)", 'x' + i); + return; + } + } + if (!_mesa_valid_to_render(ctx, "glDispatchCompute")) + return; + prog = ctx->Shader.CurrentProgram[MESA_SHADER_COMPUTE]; + if (prog == NULL || prog->_LinkedShaders[MESA_SHADER_COMPUTE] == NULL) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glDispatchCompute(no active compute shader)"); + return; + } + ctx->Driver.DispatchCompute(ctx, num_groups); } else { _mesa_error(ctx, GL_INVALID_OPERATION, "unsupported function (glDispatchCompute) called"); diff --git a/mesalib/src/mesa/main/context.c b/mesalib/src/mesa/main/context.c index 4aaf8b1af..544cc142f 100644 --- a/mesalib/src/mesa/main/context.c +++ b/mesalib/src/mesa/main/context.c @@ -118,6 +118,7 @@ #include "scissor.h" #include "shared.h" #include "shaderobj.h" +#include "shaderimage.h" #include "util/simple_list.h" #include "state.h" #include "stencil.h" @@ -821,6 +822,7 @@ init_attrib_groups(struct gl_context *ctx) _mesa_init_feedback( ctx ); _mesa_init_fog( ctx ); _mesa_init_hint( ctx ); + _mesa_init_image_units( ctx ); _mesa_init_line( ctx ); _mesa_init_lighting( ctx ); _mesa_init_matrix( ctx ); @@ -1563,7 +1565,8 @@ handle_first_current(struct gl_context *ctx) else buffer = GL_FRONT; - _mesa_drawbuffers(ctx, 1, &buffer, NULL /* destMask */); + _mesa_drawbuffers(ctx, ctx->DrawBuffer, 1, &buffer, + NULL /* destMask */); } if (ctx->ReadBuffer != _mesa_get_incomplete_framebuffer()) { @@ -1576,7 +1579,7 @@ handle_first_current(struct gl_context *ctx) bufferIndex = BUFFER_FRONT_LEFT; } - _mesa_readbuffer(ctx, buffer, bufferIndex); + _mesa_readbuffer(ctx, ctx->ReadBuffer, buffer, bufferIndex); } } diff --git a/mesalib/src/mesa/main/context.h b/mesalib/src/mesa/main/context.h index 1cd89a84a..6f3c94101 100644 --- a/mesalib/src/mesa/main/context.h +++ b/mesalib/src/mesa/main/context.h @@ -285,7 +285,7 @@ do { \ /** * Checks if the context is for Desktop GL (Compatibility or Core) */ -static inline GLboolean +static inline bool _mesa_is_desktop_gl(const struct gl_context *ctx) { return ctx->API == API_OPENGL_COMPAT || ctx->API == API_OPENGL_CORE; @@ -295,7 +295,7 @@ _mesa_is_desktop_gl(const struct gl_context *ctx) /** * Checks if the context is for any GLES version */ -static inline GLboolean +static inline bool _mesa_is_gles(const struct gl_context *ctx) { return ctx->API == API_OPENGLES || ctx->API == API_OPENGLES2; @@ -303,9 +303,9 @@ _mesa_is_gles(const struct gl_context *ctx) /** - * Checks if the context is for GLES 3.x + * Checks if the context is for GLES 3.0 or later */ -static inline GLboolean +static inline bool _mesa_is_gles3(const struct gl_context *ctx) { return ctx->API == API_OPENGLES2 && ctx->Version >= 30; @@ -313,9 +313,19 @@ _mesa_is_gles3(const struct gl_context *ctx) /** + * Checks if the context is for GLES 3.1 or later + */ +static inline bool +_mesa_is_gles31(const struct gl_context *ctx) +{ + return ctx->API == API_OPENGLES2 && ctx->Version >= 31; +} + + +/** * Checks if the context supports geometry shaders. */ -static inline GLboolean +static inline bool _mesa_has_geometry_shaders(const struct gl_context *ctx) { return _mesa_is_desktop_gl(ctx) && diff --git a/mesalib/src/mesa/main/dd.h b/mesalib/src/mesa/main/dd.h index 0c1a13fa4..d783e3422 100644 --- a/mesalib/src/mesa/main/dd.h +++ b/mesalib/src/mesa/main/dd.h @@ -1005,6 +1005,13 @@ struct dd_function_table { void (*MemoryBarrier)(struct gl_context *ctx, GLbitfield barriers); /** @} */ + + /** + * \name GL_ARB_compute_shader interface + */ + /*@{*/ + void (*DispatchCompute)(struct gl_context *ctx, const GLuint *num_groups); + /*@}*/ }; @@ -1167,6 +1174,19 @@ typedef struct { void (GLAPIENTRYP VertexAttribP4uiv)( GLuint index, GLenum type, GLboolean normalized, const GLuint *value); + + /* GL_ARB_vertex_attrib_64bit / GL 4.1 */ + void (GLAPIENTRYP VertexAttribL1d)( GLuint index, GLdouble x); + void (GLAPIENTRYP VertexAttribL2d)( GLuint index, GLdouble x, GLdouble y); + void (GLAPIENTRYP VertexAttribL3d)( GLuint index, GLdouble x, GLdouble y, GLdouble z); + void (GLAPIENTRYP VertexAttribL4d)( GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); + + + void (GLAPIENTRYP VertexAttribL1dv)( GLuint index, const GLdouble *v); + void (GLAPIENTRYP VertexAttribL2dv)( GLuint index, const GLdouble *v); + void (GLAPIENTRYP VertexAttribL3dv)( GLuint index, const GLdouble *v); + void (GLAPIENTRYP VertexAttribL4dv)( GLuint index, const GLdouble *v); + } GLvertexformat; diff --git a/mesalib/src/mesa/main/extensions.c b/mesalib/src/mesa/main/extensions.c index 9be8993b0..c82416aa0 100644 --- a/mesalib/src/mesa/main/extensions.c +++ b/mesalib/src/mesa/main/extensions.c @@ -104,7 +104,7 @@ static const struct extension extension_table[] = { { "GL_ARB_depth_clamp", o(ARB_depth_clamp), GL, 2003 }, { "GL_ARB_depth_texture", o(ARB_depth_texture), GLL, 2001 }, { "GL_ARB_derivative_control", o(ARB_derivative_control), GL, 2014 }, - { "GL_ARB_direct_state_access", o(dummy_false), GL, 2014 }, + { "GL_ARB_direct_state_access", o(ARB_direct_state_access), GL, 2014 }, { "GL_ARB_draw_buffers", o(dummy_true), GL, 2002 }, { "GL_ARB_draw_buffers_blend", o(ARB_draw_buffers_blend), GL, 2009 }, { "GL_ARB_draw_elements_base_vertex", o(ARB_draw_elements_base_vertex), GL, 2009 }, @@ -203,6 +203,7 @@ static const struct extension extension_table[] = { { "GL_ARB_vertex_buffer_object", o(dummy_true), GLL, 2003 }, { "GL_ARB_vertex_program", o(ARB_vertex_program), GLL, 2002 }, { "GL_ARB_vertex_shader", o(ARB_vertex_shader), GL, 2002 }, + { "GL_ARB_vertex_attrib_64bit", o(ARB_vertex_attrib_64bit), GLC, 2010 }, { "GL_ARB_vertex_type_10f_11f_11f_rev", o(ARB_vertex_type_10f_11f_11f_rev), GL, 2013 }, { "GL_ARB_vertex_type_2_10_10_10_rev", o(ARB_vertex_type_2_10_10_10_rev), GL, 2009 }, { "GL_ARB_viewport_array", o(ARB_viewport_array), GLC, 2010 }, diff --git a/mesalib/src/mesa/main/fbobject.c b/mesalib/src/mesa/main/fbobject.c index 27cf97f17..8db651ca2 100644 --- a/mesalib/src/mesa/main/fbobject.c +++ b/mesalib/src/mesa/main/fbobject.c @@ -121,6 +121,27 @@ _mesa_lookup_renderbuffer(struct gl_context *ctx, GLuint id) /** + * A convenience function for direct state access that throws + * GL_INVALID_OPERATION if the renderbuffer doesn't exist. + */ +struct gl_renderbuffer * +_mesa_lookup_renderbuffer_err(struct gl_context *ctx, GLuint id, + const char *func) +{ + struct gl_renderbuffer *rb; + + rb = _mesa_lookup_renderbuffer(ctx, id); + if (!rb || rb == &DummyRenderbuffer) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(non-existent renderbuffer %u)", func, id); + return NULL; + } + + return rb; +} + + +/** * Helper routine for getting a gl_framebuffer. */ struct gl_framebuffer * @@ -138,6 +159,27 @@ _mesa_lookup_framebuffer(struct gl_context *ctx, GLuint id) /** + * A convenience function for direct state access that throws + * GL_INVALID_OPERATION if the framebuffer doesn't exist. + */ +struct gl_framebuffer * +_mesa_lookup_framebuffer_err(struct gl_context *ctx, GLuint id, + const char *func) +{ + struct gl_framebuffer *fb; + + fb = _mesa_lookup_framebuffer(ctx, id); + if (!fb || fb == &DummyFramebuffer) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(non-existent framebuffer %u)", func, id); + return NULL; + } + + return fb; +} + + +/** * Mark the given framebuffer as invalid. This will force the * test for framebuffer completeness to be done before the framebuffer * is used. @@ -423,7 +465,7 @@ set_texture_attachment(struct gl_context *ctx, struct gl_framebuffer *fb, struct gl_renderbuffer_attachment *att, struct gl_texture_object *texObj, - GLenum texTarget, GLuint level, GLuint zoffset, + GLenum texTarget, GLuint level, GLuint layer, GLboolean layered) { struct gl_renderbuffer *rb = att->Renderbuffer; @@ -447,7 +489,7 @@ set_texture_attachment(struct gl_context *ctx, /* always update these fields */ att->TextureLevel = level; att->CubeMapFace = _mesa_tex_target_to_face(texTarget); - att->Zoffset = zoffset; + att->Zoffset = layer; att->Layered = layered; att->Complete = GL_FALSE; @@ -479,9 +521,10 @@ set_renderbuffer_attachment(struct gl_context *ctx, * Attach a renderbuffer object to a framebuffer object. */ void -_mesa_framebuffer_renderbuffer(struct gl_context *ctx, - struct gl_framebuffer *fb, - GLenum attachment, struct gl_renderbuffer *rb) +_mesa_FramebufferRenderbuffer_sw(struct gl_context *ctx, + struct gl_framebuffer *fb, + GLenum attachment, + struct gl_renderbuffer *rb) { struct gl_renderbuffer_attachment *att; @@ -1446,6 +1489,14 @@ void GLAPIENTRY _mesa_CreateRenderbuffers(GLsizei n, GLuint *renderbuffers) { GET_CURRENT_CONTEXT(ctx); + + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glCreateRenderbuffers(GL_ARB_direct_state_access " + "is not supported)"); + return; + } + create_render_buffers(ctx, n, renderbuffers, true); } @@ -1886,6 +1937,12 @@ renderbuffer_storage_named(GLuint renderbuffer, GLenum internalFormat, { GET_CURRENT_CONTEXT(ctx); + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(GL_ARB_direct_state_access is not supported)", func); + return; + } + if (MESA_VERBOSE & VERBOSE_API) { if (samples == NO_SAMPLES) _mesa_debug(ctx, "%s(%u, %s, %d, %d)\n", @@ -2140,6 +2197,13 @@ _mesa_GetNamedRenderbufferParameteriv(GLuint renderbuffer, GLenum pname, { GET_CURRENT_CONTEXT(ctx); + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetNamedRenderbufferParameteriv(" + "GL_ARB_direct_state_access is not supported)"); + return; + } + struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, renderbuffer); if (!rb || rb == &DummyRenderbuffer) { /* ID was reserved, but no real renderbuffer object made yet */ @@ -2396,15 +2460,29 @@ _mesa_DeleteFramebuffers(GLsizei n, const GLuint *framebuffers) } -void GLAPIENTRY -_mesa_GenFramebuffers(GLsizei n, GLuint *framebuffers) +/** + * This is the implementation for glGenFramebuffers and glCreateFramebuffers. + * It is not exposed to the rest of Mesa to encourage the use of + * nameless buffers in driver internals. + */ +static void +create_framebuffers(GLsizei n, GLuint *framebuffers, bool dsa) { GET_CURRENT_CONTEXT(ctx); GLuint first; GLint i; + struct gl_framebuffer *fb; + + const char *func = dsa ? "glCreateFramebuffers" : "glGenFramebuffers"; + + if (dsa && !ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(GL_ARB_direct_state_access is not supported)", func); + return; + } if (n < 0) { - _mesa_error(ctx, GL_INVALID_VALUE, "glGenFramebuffersEXT(n)"); + _mesa_error(ctx, GL_INVALID_VALUE, "%s(n < 0)", func); return; } @@ -2416,31 +2494,43 @@ _mesa_GenFramebuffers(GLsizei n, GLuint *framebuffers) for (i = 0; i < n; i++) { GLuint name = first + i; framebuffers[i] = name; - /* insert dummy placeholder into hash table */ + + if (dsa) { + fb = ctx->Driver.NewFramebuffer(ctx, framebuffers[i]); + if (!fb) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", func); + return; + } + } + else + fb = &DummyFramebuffer; + mtx_lock(&ctx->Shared->Mutex); - _mesa_HashInsert(ctx->Shared->FrameBuffers, name, &DummyFramebuffer); + _mesa_HashInsert(ctx->Shared->FrameBuffers, name, fb); mtx_unlock(&ctx->Shared->Mutex); } } -GLenum GLAPIENTRY -_mesa_CheckFramebufferStatus(GLenum target) +void GLAPIENTRY +_mesa_GenFramebuffers(GLsizei n, GLuint *framebuffers) { - struct gl_framebuffer *buffer; - GET_CURRENT_CONTEXT(ctx); + create_framebuffers(n, framebuffers, false); +} - ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0); - if (MESA_VERBOSE & VERBOSE_API) - _mesa_debug(ctx, "glCheckFramebufferStatus(%s)\n", - _mesa_lookup_enum_by_nr(target)); +void GLAPIENTRY +_mesa_CreateFramebuffers(GLsizei n, GLuint *framebuffers) +{ + create_framebuffers(n, framebuffers, true); +} - buffer = get_framebuffer_target(ctx, target); - if (!buffer) { - _mesa_error(ctx, GL_INVALID_ENUM, "glCheckFramebufferStatus(target)"); - return 0; - } + +GLenum +_mesa_check_framebuffer_status(struct gl_context *ctx, + struct gl_framebuffer *buffer) +{ + ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, 0); if (_mesa_is_winsys_fbo(buffer)) { /* EGL_KHR_surfaceless_context allows the winsys FBO to be incomplete. */ @@ -2461,6 +2551,74 @@ _mesa_CheckFramebufferStatus(GLenum target) } +GLenum GLAPIENTRY +_mesa_CheckFramebufferStatus(GLenum target) +{ + struct gl_framebuffer *fb; + GET_CURRENT_CONTEXT(ctx); + + if (MESA_VERBOSE & VERBOSE_API) + _mesa_debug(ctx, "glCheckFramebufferStatus(%s)\n", + _mesa_lookup_enum_by_nr(target)); + + fb = get_framebuffer_target(ctx, target); + if (!fb) { + _mesa_error(ctx, GL_INVALID_ENUM, + "glCheckFramebufferStatus(invalid target %s)", + _mesa_lookup_enum_by_nr(target)); + return 0; + } + + return _mesa_check_framebuffer_status(ctx, fb); +} + + +GLenum GLAPIENTRY +_mesa_CheckNamedFramebufferStatus(GLuint framebuffer, GLenum target) +{ + struct gl_framebuffer *fb; + GET_CURRENT_CONTEXT(ctx); + + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glCheckNamedFramebufferStatus(GL_ARB_direct_state_access " + "is not supported)"); + return 0; + } + + /* Validate the target (for conformance's sake) and grab a reference to the + * default framebuffer in case framebuffer = 0. + * Section 9.4 Framebuffer Completeness of the OpenGL 4.5 core spec + * (30.10.2014, PDF page 336) says: + * "If framebuffer is zero, then the status of the default read or + * draw framebuffer (as determined by target) is returned." + */ + switch (target) { + case GL_DRAW_FRAMEBUFFER: + case GL_FRAMEBUFFER: + fb = ctx->WinSysDrawBuffer; + break; + case GL_READ_FRAMEBUFFER: + fb = ctx->WinSysReadBuffer; + break; + default: + _mesa_error(ctx, GL_INVALID_ENUM, + "glCheckNamedFramebufferStatus(invalid target %s)", + _mesa_lookup_enum_by_nr(target)); + return 0; + } + + if (framebuffer) { + fb = _mesa_lookup_framebuffer_err(ctx, framebuffer, + "glCheckNamedFramebufferStatus"); + if (!fb) + return 0; + } + + return _mesa_check_framebuffer_status(ctx, fb); +} + + /** * Replicate the src attachment point. Used by framebuffer_texture() when * the same texture is attached at GL_DEPTH_ATTACHMENT and @@ -2487,144 +2645,301 @@ reuse_framebuffer_texture_attachment(struct gl_framebuffer *fb, /** - * Common code called by glFramebufferTexture1D/2D/3D() and - * glFramebufferTextureLayer(). + * Common code called by gl*FramebufferTexture*() to retrieve the correct + * texture object pointer. * - * \param textarget is the textarget that was passed to the - * glFramebufferTexture...() function, or 0 if the corresponding function - * doesn't have a textarget parameter. + * \param texObj where the pointer to the texture object is returned. Note + * that a successful call may return texObj = NULL. * - * \param layered is true if this function was called from - * glFramebufferTexture(), false otherwise. + * \return true if no errors, false if errors */ -static void -framebuffer_texture(struct gl_context *ctx, const char *caller, GLenum target, - GLenum attachment, GLenum textarget, GLuint texture, - GLint level, GLuint zoffset, GLboolean layered) +static bool +get_texture_for_framebuffer(struct gl_context *ctx, GLuint texture, + bool layered, const char *caller, + struct gl_texture_object **texObj) { - struct gl_renderbuffer_attachment *att; - struct gl_texture_object *texObj = NULL; - struct gl_framebuffer *fb; - GLenum maxLevelsTarget; + *texObj = NULL; /* This will get returned if texture = 0. */ - fb = get_framebuffer_target(ctx, target); - if (!fb) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glFramebufferTexture%s(target=0x%x)", caller, target); - return; + if (!texture) + return true; + + *texObj = _mesa_lookup_texture(ctx, texture); + if (*texObj == NULL || (*texObj)->Target == 0) { + /* Can't render to a non-existent texture object. + * + * The OpenGL 4.5 core spec (02.02.2015) in Section 9.2 Binding and + * Managing Framebuffer Objects specifies a different error + * depending upon the calling function (PDF pages 325-328). + * *FramebufferTexture (where layered = GL_TRUE) throws invalid + * value, while the other commands throw invalid operation (where + * layered = GL_FALSE). + */ + const GLenum error = layered ? GL_INVALID_VALUE : + GL_INVALID_OPERATION; + _mesa_error(ctx, error, + "%s(non-existent texture %u)", caller, texture); + return false; } - /* check framebuffer binding */ - if (_mesa_is_winsys_fbo(fb)) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glFramebufferTexture%s", caller); - return; + return true; +} + + +/** + * Common code called by gl*FramebufferTexture() to verify the texture target + * and decide whether or not the attachment should truly be considered + * layered. + * + * \param layered true if attachment should be considered layered, false if + * not + * + * \return true if no errors, false if errors + */ +static bool +check_layered_texture_target(struct gl_context *ctx, GLenum target, + const char *caller, GLboolean *layered) +{ + *layered = GL_TRUE; + + switch (target) { + case GL_TEXTURE_3D: + case GL_TEXTURE_1D_ARRAY_EXT: + case GL_TEXTURE_2D_ARRAY_EXT: + case GL_TEXTURE_CUBE_MAP: + case GL_TEXTURE_CUBE_MAP_ARRAY: + case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: + return true; + case GL_TEXTURE_1D: + case GL_TEXTURE_2D: + case GL_TEXTURE_RECTANGLE: + case GL_TEXTURE_2D_MULTISAMPLE: + /* These texture types are valid to pass to + * glFramebufferTexture(), but since they aren't layered, it + * is equivalent to calling glFramebufferTexture{1D,2D}(). + */ + *layered = GL_FALSE; + return true; } - /* The textarget, level, and zoffset parameters are only validated if - * texture is non-zero. + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(invalid texture target %s)", caller, + _mesa_lookup_enum_by_nr(target)); + return false; +} + + +/** + * Common code called by gl*FramebufferTextureLayer() to verify the texture + * target. + * + * \return true if no errors, false if errors + */ +static bool +check_texture_target(struct gl_context *ctx, GLenum target, + const char *caller) +{ + /* We're being called by glFramebufferTextureLayer(). + * The only legal texture types for that function are 3D, + * cube-map, and 1D/2D/cube-map array textures. */ - if (texture) { - GLboolean err = GL_TRUE; - - texObj = _mesa_lookup_texture(ctx, texture); - if (texObj != NULL) { - if (textarget == 0) { - if (layered) { - /* We're being called by glFramebufferTexture() and textarget - * is not used. - */ - switch (texObj->Target) { - case GL_TEXTURE_3D: - case GL_TEXTURE_1D_ARRAY_EXT: - case GL_TEXTURE_2D_ARRAY_EXT: - case GL_TEXTURE_CUBE_MAP: - case GL_TEXTURE_CUBE_MAP_ARRAY: - case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: - err = false; - break; - case GL_TEXTURE_1D: - case GL_TEXTURE_2D: - case GL_TEXTURE_RECTANGLE: - case GL_TEXTURE_2D_MULTISAMPLE: - /* These texture types are valid to pass to - * glFramebufferTexture(), but since they aren't layered, it - * is equivalent to calling glFramebufferTexture{1D,2D}(). - */ - err = false; - layered = false; - textarget = texObj->Target; - break; - default: - err = true; - break; - } - } else { - /* We're being called by glFramebufferTextureLayer() and - * textarget is not used. The only legal texture types for - * that function are 3D and 1D/2D arrays textures. - */ - err = (texObj->Target != GL_TEXTURE_3D) && - (texObj->Target != GL_TEXTURE_1D_ARRAY_EXT) && - (texObj->Target != GL_TEXTURE_2D_ARRAY_EXT) && - (texObj->Target != GL_TEXTURE_CUBE_MAP_ARRAY) && - (texObj->Target != GL_TEXTURE_2D_MULTISAMPLE_ARRAY); - } - } - else { - /* Make sure textarget is consistent with the texture's type */ - err = (texObj->Target == GL_TEXTURE_CUBE_MAP) - ? !_mesa_is_cube_face(textarget) - : (texObj->Target != textarget); - } + switch (target) { + case GL_TEXTURE_3D: + case GL_TEXTURE_1D_ARRAY: + case GL_TEXTURE_2D_ARRAY: + case GL_TEXTURE_CUBE_MAP_ARRAY: + case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: + return true; + case GL_TEXTURE_CUBE_MAP: + /* This target is valid in TextureLayer when ARB_direct_state_access + * or OpenGL 4.5 is supported. + */ + return ctx->Extensions.ARB_direct_state_access; + } + + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(invalid texture target %s)", caller, + _mesa_lookup_enum_by_nr(target)); + return false; +} + + +/** + * Common code called by glFramebufferTexture*D() to verify the texture + * target. + * + * \return true if no errors, false if errors + */ +static bool +check_textarget(struct gl_context *ctx, int dims, GLenum target, + GLenum textarget, const char *caller) +{ + bool err = false; + + switch (dims) { + case 1: + switch (textarget) { + case GL_TEXTURE_1D: + break; + case GL_TEXTURE_1D_ARRAY: + err = !ctx->Extensions.EXT_texture_array; + break; + default: + err = true; } - else { - /* can't render to a non-existant texture */ - _mesa_error(ctx, GL_INVALID_OPERATION, - "glFramebufferTexture%s(non existant texture)", - caller); - return; + break; + case 2: + switch (textarget) { + case GL_TEXTURE_2D: + break; + case GL_TEXTURE_RECTANGLE: + err = _mesa_is_gles(ctx) + || !ctx->Extensions.NV_texture_rectangle; + break; + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + err = !ctx->Extensions.ARB_texture_cube_map; + break; + case GL_TEXTURE_2D_ARRAY: + err = (_mesa_is_gles(ctx) && ctx->Version < 30) + || !ctx->Extensions.EXT_texture_array; + break; + case GL_TEXTURE_2D_MULTISAMPLE: + case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: + err = _mesa_is_gles(ctx) + || !ctx->Extensions.ARB_texture_multisample; + break; + default: + err = true; } + break; + case 3: + if (textarget != GL_TEXTURE_3D) + err = true; + break; + default: + err = true; + } - if (err) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glFramebufferTexture%s(texture target mismatch)", - caller); - return; - } + if (err) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(invalid textarget %s)", + caller, _mesa_lookup_enum_by_nr(textarget)); + return false; + } - if (texObj->Target == GL_TEXTURE_3D) { - const GLuint maxSize = 1 << (ctx->Const.Max3DTextureLevels - 1); - if (zoffset >= maxSize) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glFramebufferTexture%s(zoffset)", caller); - return; - } + /* Make sure textarget is consistent with the texture's type */ + err = (target == GL_TEXTURE_CUBE_MAP) ? + !_mesa_is_cube_face(textarget): (target != textarget); + + if (err) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(mismatched texture target)", caller); + return false; + } + + return true; +} + + +/** + * Common code called by gl*FramebufferTextureLayer() and + * glFramebufferTexture3D() to validate the layer. + * + * \return true if no errors, false if errors + */ +static bool +check_layer(struct gl_context *ctx, GLenum target, GLint layer, + const char *caller) +{ + /* Page 306 (page 328 of the PDF) of the OpenGL 4.5 (Core Profile) + * spec says: + * + * "An INVALID_VALUE error is generated if texture is non-zero + * and layer is negative." + */ + if (layer < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, + "%s(layer %u < 0)", caller, layer); + return false; + } + + if (target == GL_TEXTURE_3D) { + const GLuint maxSize = 1 << (ctx->Const.Max3DTextureLevels - 1); + if (layer >= maxSize) { + _mesa_error(ctx, GL_INVALID_VALUE, + "%s(invalid layer %u)", caller, layer); + return false; } - else if ((texObj->Target == GL_TEXTURE_1D_ARRAY_EXT) || - (texObj->Target == GL_TEXTURE_2D_ARRAY_EXT) || - (texObj->Target == GL_TEXTURE_CUBE_MAP_ARRAY) || - (texObj->Target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY)) { - if (zoffset >= ctx->Const.MaxArrayTextureLayers) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glFramebufferTexture%s(layer)", caller); - return; - } + } + else if ((target == GL_TEXTURE_1D_ARRAY) || + (target == GL_TEXTURE_2D_ARRAY) || + (target == GL_TEXTURE_CUBE_MAP_ARRAY) || + (target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY)) { + if (layer >= ctx->Const.MaxArrayTextureLayers) { + _mesa_error(ctx, GL_INVALID_VALUE, + "%s(layer %u >= GL_MAX_ARRAY_TEXTURE_LAYERS)", + caller, layer); + return false; } - - maxLevelsTarget = textarget ? textarget : texObj->Target; - if ((level < 0) || - (level >= _mesa_max_texture_levels(ctx, maxLevelsTarget))) { + } + else if (target == GL_TEXTURE_CUBE_MAP) { + if (layer >= 6) { _mesa_error(ctx, GL_INVALID_VALUE, - "glFramebufferTexture%s(level)", caller); - return; + "%s(layer %u >= 6)", caller, layer); + return false; } } + return true; +} + + +/** + * Common code called by all gl*FramebufferTexture*() entry points to verify + * the level. + * + * \return true if no errors, false if errors + */ +static bool +check_level(struct gl_context *ctx, GLenum target, GLint level, + const char *caller) +{ + if ((level < 0) || + (level >= _mesa_max_texture_levels(ctx, target))) { + _mesa_error(ctx, GL_INVALID_VALUE, + "%s(invalid level %d)", caller, level); + return false; + } + + return true; +} + + +void +_mesa_framebuffer_texture(struct gl_context *ctx, struct gl_framebuffer *fb, + GLenum attachment, + struct gl_texture_object *texObj, GLenum textarget, + GLint level, GLuint layer, GLboolean layered, + const char *caller) +{ + struct gl_renderbuffer_attachment *att; + + /* The window-system framebuffer object is immutable */ + if (_mesa_is_winsys_fbo(fb)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "%s(window-system framebuffer)", + caller); + return; + } + + /* Not a hash lookup, so we can afford to get the attachment here. */ att = get_attachment(ctx, fb, attachment); if (att == NULL) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glFramebufferTexture%s(attachment)", caller); + _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid attachment %s)", caller, + _mesa_lookup_enum_by_nr(attachment)); return; } @@ -2637,7 +2952,7 @@ framebuffer_texture(struct gl_context *ctx, const char *caller, GLenum target, level == fb->Attachment[BUFFER_STENCIL].TextureLevel && _mesa_tex_target_to_face(textarget) == fb->Attachment[BUFFER_STENCIL].CubeMapFace && - zoffset == fb->Attachment[BUFFER_STENCIL].Zoffset) { + layer == fb->Attachment[BUFFER_STENCIL].Zoffset) { /* The texture object is already attached to the stencil attachment * point. Don't create a new renderbuffer; just reuse the stencil * attachment's. This is required to prevent a GL error in @@ -2650,13 +2965,14 @@ framebuffer_texture(struct gl_context *ctx, const char *caller, GLenum target, level == fb->Attachment[BUFFER_DEPTH].TextureLevel && _mesa_tex_target_to_face(textarget) == fb->Attachment[BUFFER_DEPTH].CubeMapFace && - zoffset == fb->Attachment[BUFFER_DEPTH].Zoffset) { + layer == fb->Attachment[BUFFER_DEPTH].Zoffset) { /* As above, but with depth and stencil transposed. */ reuse_framebuffer_texture_attachment(fb, BUFFER_STENCIL, BUFFER_DEPTH); } else { set_texture_attachment(ctx, fb, att, texObj, textarget, - level, zoffset, layered); + level, layer, layered); + if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) { /* Above we created a new renderbuffer and attached it to the * depth attachment point. Now attach it to the stencil attachment @@ -2692,36 +3008,50 @@ framebuffer_texture(struct gl_context *ctx, const char *caller, GLenum target, } -void GLAPIENTRY -_mesa_FramebufferTexture1D(GLenum target, GLenum attachment, - GLenum textarget, GLuint texture, GLint level) +static void +framebuffer_texture_with_dims(int dims, GLenum target, + GLenum attachment, GLenum textarget, + GLuint texture, GLint level, GLint layer, + const char *caller) { GET_CURRENT_CONTEXT(ctx); + struct gl_framebuffer *fb; + struct gl_texture_object *texObj; - if (texture != 0) { - GLboolean error; + /* Get the framebuffer object */ + fb = get_framebuffer_target(ctx, target); + if (!fb) { + _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid target %s)", caller, + _mesa_lookup_enum_by_nr(target)); + return; + } - switch (textarget) { - case GL_TEXTURE_1D: - error = GL_FALSE; - break; - case GL_TEXTURE_1D_ARRAY: - error = !ctx->Extensions.EXT_texture_array; - break; - default: - error = GL_TRUE; - } + /* Get the texture object */ + if (!get_texture_for_framebuffer(ctx, texture, false, caller, &texObj)) + return; - if (error) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glFramebufferTexture1D(textarget=%s)", - _mesa_lookup_enum_by_nr(textarget)); + if (texObj) { + if (!check_textarget(ctx, dims, texObj->Target, textarget, caller)) + return; + + if ((dims == 3) && !check_layer(ctx, texObj->Target, layer, caller)) return; - } } - framebuffer_texture(ctx, "1D", target, attachment, textarget, texture, - level, 0, GL_FALSE); + if (!check_level(ctx, textarget, level, caller)) + return; + + _mesa_framebuffer_texture(ctx, fb, attachment, texObj, textarget, level, + layer, GL_FALSE, caller); +} + + +void GLAPIENTRY +_mesa_FramebufferTexture1D(GLenum target, GLenum attachment, + GLenum textarget, GLuint texture, GLint level) +{ + framebuffer_texture_with_dims(1, target, attachment, textarget, texture, + level, 0, "glFramebufferTexture1D"); } @@ -2729,79 +3059,112 @@ void GLAPIENTRY _mesa_FramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) { + framebuffer_texture_with_dims(2, target, attachment, textarget, texture, + level, 0, "glFramebufferTexture2D"); +} + + +void GLAPIENTRY +_mesa_FramebufferTexture3D(GLenum target, GLenum attachment, + GLenum textarget, GLuint texture, + GLint level, GLint layer) +{ + framebuffer_texture_with_dims(3, target, attachment, textarget, texture, + level, layer, "glFramebufferTexture3D"); +} + + +void GLAPIENTRY +_mesa_FramebufferTextureLayer(GLenum target, GLenum attachment, + GLuint texture, GLint level, GLint layer) +{ GET_CURRENT_CONTEXT(ctx); + struct gl_framebuffer *fb; + struct gl_texture_object *texObj; + GLenum textarget = 0; - if (texture != 0) { - GLboolean error; + const char *func = "glFramebufferTextureLayer"; - switch (textarget) { - case GL_TEXTURE_2D: - error = GL_FALSE; - break; - case GL_TEXTURE_RECTANGLE: - error = _mesa_is_gles(ctx) - || !ctx->Extensions.NV_texture_rectangle; - break; - case GL_TEXTURE_CUBE_MAP_POSITIVE_X: - case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: - case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: - case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: - case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: - case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: - error = !ctx->Extensions.ARB_texture_cube_map; - break; - case GL_TEXTURE_2D_ARRAY: - error = (_mesa_is_gles(ctx) && ctx->Version < 30) - || !ctx->Extensions.EXT_texture_array; - break; - case GL_TEXTURE_2D_MULTISAMPLE: - case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: - error = _mesa_is_gles(ctx) - || !ctx->Extensions.ARB_texture_multisample; - break; - default: - error = GL_TRUE; - } + /* Get the framebuffer object */ + fb = get_framebuffer_target(ctx, target); + if (!fb) { + _mesa_error(ctx, GL_INVALID_ENUM, + "glFramebufferTextureLayer(invalid target %s)", + _mesa_lookup_enum_by_nr(target)); + return; + } - if (error) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glFramebufferTexture2D(textarget=%s)", - _mesa_lookup_enum_by_nr(textarget)); + /* Get the texture object */ + if (!get_texture_for_framebuffer(ctx, texture, false, func, &texObj)) + return; + + if (texObj) { + if (!check_texture_target(ctx, texObj->Target, func)) + return; + + if (!check_layer(ctx, texObj->Target, layer, func)) return; + + if (!check_level(ctx, texObj->Target, level, func)) + return; + + if (texObj->Target == GL_TEXTURE_CUBE_MAP) { + assert(layer >= 0 && layer < 6); + textarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + layer; + layer = 0; } } - framebuffer_texture(ctx, "2D", target, attachment, textarget, texture, - level, 0, GL_FALSE); + _mesa_framebuffer_texture(ctx, fb, attachment, texObj, textarget, level, + layer, GL_FALSE, func); } void GLAPIENTRY -_mesa_FramebufferTexture3D(GLenum target, GLenum attachment, - GLenum textarget, GLuint texture, - GLint level, GLint zoffset) +_mesa_NamedFramebufferTextureLayer(GLuint framebuffer, GLenum attachment, + GLuint texture, GLint level, GLint layer) { GET_CURRENT_CONTEXT(ctx); + struct gl_framebuffer *fb; + struct gl_texture_object *texObj; + GLenum textarget = 0; + + const char *func = "glNamedFramebufferTextureLayer"; - if ((texture != 0) && (textarget != GL_TEXTURE_3D)) { + if (!ctx->Extensions.ARB_direct_state_access) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glFramebufferTexture3D(textarget)"); + "%s(GL_ARB_direct_state_access is not supported)", func); return; } - framebuffer_texture(ctx, "3D", target, attachment, textarget, texture, - level, zoffset, GL_FALSE); -} + /* Get the framebuffer object */ + fb = _mesa_lookup_framebuffer_err(ctx, framebuffer, func); + if (!fb) + return; + /* Get the texture object */ + if (!get_texture_for_framebuffer(ctx, texture, false, func, &texObj)) + return; -void GLAPIENTRY -_mesa_FramebufferTextureLayer(GLenum target, GLenum attachment, - GLuint texture, GLint level, GLint layer) -{ - GET_CURRENT_CONTEXT(ctx); + if (texObj) { + if (!check_texture_target(ctx, texObj->Target, func)) + return; + + if (!check_layer(ctx, texObj->Target, layer, func)) + return; + + if (!check_level(ctx, texObj->Target, level, func)) + return; - framebuffer_texture(ctx, "Layer", target, attachment, 0, texture, - level, layer, GL_FALSE); + if (texObj->Target == GL_TEXTURE_CUBE_MAP) { + assert(layer >= 0 && layer < 6); + textarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + layer; + layer = 0; + } + } + + _mesa_framebuffer_texture(ctx, fb, attachment, texObj, textarget, level, + layer, GL_FALSE, func); } @@ -2810,82 +3173,121 @@ _mesa_FramebufferTexture(GLenum target, GLenum attachment, GLuint texture, GLint level) { GET_CURRENT_CONTEXT(ctx); + struct gl_framebuffer *fb; + struct gl_texture_object *texObj; + GLboolean layered; + + const char *func = "FramebufferTexture"; - if (_mesa_has_geometry_shaders(ctx)) { - framebuffer_texture(ctx, "", target, attachment, 0, texture, - level, 0, GL_TRUE); - } else { + if (!_mesa_has_geometry_shaders(ctx)) { _mesa_error(ctx, GL_INVALID_OPERATION, "unsupported function (glFramebufferTexture) called"); + return; + } + + /* Get the framebuffer object */ + fb = get_framebuffer_target(ctx, target); + if (!fb) { + _mesa_error(ctx, GL_INVALID_ENUM, + "glFramebufferTexture(invalid target %s)", + _mesa_lookup_enum_by_nr(target)); + return; } + + /* Get the texture object */ + if (!get_texture_for_framebuffer(ctx, texture, true, func, &texObj)) + return; + + if (texObj) { + if (!check_layered_texture_target(ctx, texObj->Target, func, &layered)) + return; + + if (!check_level(ctx, texObj->Target, level, func)) + return; + } + + _mesa_framebuffer_texture(ctx, fb, attachment, texObj, 0, level, + 0, layered, func); } void GLAPIENTRY -_mesa_FramebufferRenderbuffer(GLenum target, GLenum attachment, - GLenum renderbufferTarget, - GLuint renderbuffer) +_mesa_NamedFramebufferTexture(GLuint framebuffer, GLenum attachment, + GLuint texture, GLint level) { - struct gl_renderbuffer_attachment *att; - struct gl_framebuffer *fb; - struct gl_renderbuffer *rb; GET_CURRENT_CONTEXT(ctx); + struct gl_framebuffer *fb; + struct gl_texture_object *texObj; + GLboolean layered; - fb = get_framebuffer_target(ctx, target); - if (!fb) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glFramebufferRenderbuffer(target)"); + const char *func = "glNamedFramebufferTexture"; + + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(GL_ARB_direct_state_access is not supported)", func); return; } - if (renderbufferTarget != GL_RENDERBUFFER_EXT) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glFramebufferRenderbuffer(renderbufferTarget)"); + if (!_mesa_has_geometry_shaders(ctx)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "unsupported function (glNamedFramebufferTexture) called"); return; } + /* Get the framebuffer object */ + fb = _mesa_lookup_framebuffer_err(ctx, framebuffer, func); + if (!fb) + return; + + /* Get the texture object */ + if (!get_texture_for_framebuffer(ctx, texture, true, func, &texObj)) + return; + + if (texObj) { + if (!check_layered_texture_target(ctx, texObj->Target, func, + &layered)) + return; + + if (!check_level(ctx, texObj->Target, level, func)) + return; + } + + _mesa_framebuffer_texture(ctx, fb, attachment, texObj, 0, level, + 0, layered, func); +} + + +void +_mesa_framebuffer_renderbuffer(struct gl_context *ctx, + struct gl_framebuffer *fb, + GLenum attachment, + struct gl_renderbuffer *rb, + const char *func) +{ + struct gl_renderbuffer_attachment *att; + if (_mesa_is_winsys_fbo(fb)) { /* Can't attach new renderbuffers to a window system framebuffer */ - _mesa_error(ctx, GL_INVALID_OPERATION, "glFramebufferRenderbuffer"); + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(window-system framebuffer)", func); return; } att = get_attachment(ctx, fb, attachment); if (att == NULL) { _mesa_error(ctx, GL_INVALID_ENUM, - "glFramebufferRenderbuffer(invalid attachment %s)", + "%s(invalid attachment %s)", func, _mesa_lookup_enum_by_nr(attachment)); return; } - if (renderbuffer) { - rb = _mesa_lookup_renderbuffer(ctx, renderbuffer); - if (!rb) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glFramebufferRenderbuffer(non-existant" - " renderbuffer %u)", renderbuffer); - return; - } - else if (rb == &DummyRenderbuffer) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glFramebufferRenderbuffer(renderbuffer %u)", - renderbuffer); - return; - } - } - else { - /* remove renderbuffer attachment */ - rb = NULL; - } - if (attachment == GL_DEPTH_STENCIL_ATTACHMENT && rb && rb->Format != MESA_FORMAT_NONE) { /* make sure the renderbuffer is a depth/stencil format */ const GLenum baseFormat = _mesa_get_format_base_format(rb->Format); if (baseFormat != GL_DEPTH_STENCIL) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glFramebufferRenderbuffer(renderbuffer" - " is not DEPTH_STENCIL format)"); + "%s(renderbuffer is not DEPTH_STENCIL format)", func); return; } } @@ -2903,24 +3305,99 @@ _mesa_FramebufferRenderbuffer(GLenum target, GLenum attachment, void GLAPIENTRY -_mesa_GetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, - GLenum pname, GLint *params) +_mesa_FramebufferRenderbuffer(GLenum target, GLenum attachment, + GLenum renderbuffertarget, + GLuint renderbuffer) { - const struct gl_renderbuffer_attachment *att; - struct gl_framebuffer *buffer; - GLenum err; + struct gl_framebuffer *fb; + struct gl_renderbuffer *rb; GET_CURRENT_CONTEXT(ctx); - /* The error differs in GL and GLES. */ - err = _mesa_is_desktop_gl(ctx) ? GL_INVALID_OPERATION : GL_INVALID_ENUM; + fb = get_framebuffer_target(ctx, target); + if (!fb) { + _mesa_error(ctx, GL_INVALID_ENUM, + "glFramebufferRenderbuffer(invalid target %s)", + _mesa_lookup_enum_by_nr(target)); + return; + } - buffer = get_framebuffer_target(ctx, target); - if (!buffer) { + if (renderbuffertarget != GL_RENDERBUFFER) { _mesa_error(ctx, GL_INVALID_ENUM, - "glGetFramebufferAttachmentParameteriv(target)"); + "glFramebufferRenderbuffer(renderbuffertarget is not " + "GL_RENDERBUFFER)"); return; } + if (renderbuffer) { + rb = _mesa_lookup_renderbuffer_err(ctx, renderbuffer, + "glFramebufferRenderbuffer"); + if (!rb) + return; + } + else { + /* remove renderbuffer attachment */ + rb = NULL; + } + + _mesa_framebuffer_renderbuffer(ctx, fb, attachment, rb, + "glFramebufferRenderbuffer"); +} + + +void GLAPIENTRY +_mesa_NamedFramebufferRenderbuffer(GLuint framebuffer, GLenum attachment, + GLenum renderbuffertarget, + GLuint renderbuffer) +{ + struct gl_framebuffer *fb; + struct gl_renderbuffer *rb; + GET_CURRENT_CONTEXT(ctx); + + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glNamedFramebufferRenderbuffer(GL_ARB_direct_state_access " + "is not supported)"); + return; + } + + fb = _mesa_lookup_framebuffer_err(ctx, framebuffer, + "glNamedFramebufferRenderbuffer"); + + if (renderbuffertarget != GL_RENDERBUFFER) { + _mesa_error(ctx, GL_INVALID_ENUM, + "glNamedFramebufferRenderbuffer(renderbuffertarget is not " + "GL_RENDERBUFFER)"); + return; + } + + if (renderbuffer) { + rb = _mesa_lookup_renderbuffer_err(ctx, renderbuffer, + "glNamedFramebufferRenderbuffer"); + if (!rb) + return; + } + else { + /* remove renderbuffer attachment */ + rb = NULL; + } + + _mesa_framebuffer_renderbuffer(ctx, fb, attachment, rb, + "glNamedFramebufferRenderbuffer"); +} + + +void +_mesa_get_framebuffer_attachment_parameter(struct gl_context *ctx, + struct gl_framebuffer *buffer, + GLenum attachment, GLenum pname, + GLint *params, const char *caller) +{ + const struct gl_renderbuffer_attachment *att; + GLenum err; + + /* The error differs in GL and GLES. */ + err = _mesa_is_desktop_gl(ctx) ? GL_INVALID_OPERATION : GL_INVALID_ENUM; + if (_mesa_is_winsys_fbo(buffer)) { /* Page 126 (page 136 of the PDF) of the OpenGL ES 2.0.25 spec * says: @@ -2936,14 +3413,15 @@ _mesa_GetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, !ctx->Extensions.ARB_framebuffer_object) && !_mesa_is_gles3(ctx)) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glGetFramebufferAttachmentParameteriv(bound FBO = 0)"); + "%s(window-system framebuffer)", caller); return; } if (_mesa_is_gles3(ctx) && attachment != GL_BACK && attachment != GL_DEPTH && attachment != GL_STENCIL) { _mesa_error(ctx, GL_INVALID_ENUM, - "glGetFramebufferAttachmentParameteriv(attachment)"); + "%s(invalid attachment %s)", caller, + _mesa_lookup_enum_by_nr(attachment)); return; } /* the default / window-system FBO */ @@ -2955,8 +3433,8 @@ _mesa_GetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, } if (att == NULL) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glGetFramebufferAttachmentParameteriv(attachment)"); + _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid attachment %s)", caller, + _mesa_lookup_enum_by_nr(attachment)); return; } @@ -2970,9 +3448,8 @@ _mesa_GetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, * attachment, since it does not have a single format." */ _mesa_error(ctx, GL_INVALID_OPERATION, - "glGetFramebufferAttachmentParameteriv(" - "GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE" - " is invalid for depth+stencil attachment)"); + "%s(GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE" + " is invalid for depth+stencil attachment)", caller); return; } /* the depth and stencil attachments must point to the same buffer */ @@ -2980,8 +3457,7 @@ _mesa_GetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, stencilAtt = get_attachment(ctx, buffer, GL_STENCIL_ATTACHMENT); if (depthAtt->Renderbuffer != stencilAtt->Renderbuffer) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glGetFramebufferAttachmentParameteriv(DEPTH/STENCIL" - " attachments differ)"); + "%s(DEPTH/STENCIL attachments differ)", caller); return; } } @@ -3014,8 +3490,8 @@ _mesa_GetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, *params = att->TextureLevel; } else if (att->Type == GL_NONE) { - _mesa_error(ctx, err, - "glGetFramebufferAttachmentParameteriv(pname)"); + _mesa_error(ctx, err, "%s(invalid pname %s)", caller, + _mesa_lookup_enum_by_nr(pname)); } else { goto invalid_pname_enum; @@ -3031,8 +3507,8 @@ _mesa_GetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, } } else if (att->Type == GL_NONE) { - _mesa_error(ctx, err, - "glGetFramebufferAttachmentParameteriv(pname)"); + _mesa_error(ctx, err, "%s(invalid pname %s)", caller, + _mesa_lookup_enum_by_nr(pname)); } else { goto invalid_pname_enum; @@ -3042,8 +3518,8 @@ _mesa_GetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, if (ctx->API == API_OPENGLES) { goto invalid_pname_enum; } else if (att->Type == GL_NONE) { - _mesa_error(ctx, err, - "glGetFramebufferAttachmentParameteriv(pname)"); + _mesa_error(ctx, err, "%s(invalid pname %s)", caller, + _mesa_lookup_enum_by_nr(pname)); } else if (att->Type == GL_TEXTURE) { if (att->Texture && (att->Texture->Target == GL_TEXTURE_3D || att->Texture->Target == GL_TEXTURE_2D_ARRAY)) { @@ -3064,8 +3540,8 @@ _mesa_GetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, goto invalid_pname_enum; } else if (att->Type == GL_NONE) { - _mesa_error(ctx, err, - "glGetFramebufferAttachmentParameteriv(pname)"); + _mesa_error(ctx, err, "%s(invalid pname %s)", caller, + _mesa_lookup_enum_by_nr(pname)); } else { if (ctx->Extensions.EXT_framebuffer_sRGB) { @@ -3087,8 +3563,8 @@ _mesa_GetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, goto invalid_pname_enum; } else if (att->Type == GL_NONE) { - _mesa_error(ctx, err, - "glGetFramebufferAttachmentParameteriv(pname)"); + _mesa_error(ctx, err, "%s(invalid pname %s)", caller, + _mesa_lookup_enum_by_nr(pname)); } else { mesa_format format = att->Renderbuffer->Format; @@ -3103,9 +3579,9 @@ _mesa_GetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, if (_mesa_is_gles3(ctx) && attachment == GL_DEPTH_STENCIL_ATTACHMENT) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glGetFramebufferAttachmentParameteriv(cannot query " + "%s(cannot query " "GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE of " - "GL_DEPTH_STENCIL_ATTACHMENT"); + "GL_DEPTH_STENCIL_ATTACHMENT)", caller); return; } @@ -3139,8 +3615,8 @@ _mesa_GetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, goto invalid_pname_enum; } else if (att->Type == GL_NONE) { - _mesa_error(ctx, err, - "glGetFramebufferAttachmentParameteriv(pname)"); + _mesa_error(ctx, err, "%s(invalid pname %s)", caller, + _mesa_lookup_enum_by_nr(pname)); } else if (att->Texture) { const struct gl_texture_image *texImage = @@ -3159,8 +3635,7 @@ _mesa_GetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, att->Renderbuffer->Format); } else { - _mesa_problem(ctx, "glGetFramebufferAttachmentParameterivEXT:" - " invalid FBO attachment structure"); + _mesa_problem(ctx, "%s: invalid FBO attachment structure", caller); } return; case GL_FRAMEBUFFER_ATTACHMENT_LAYERED: @@ -3169,8 +3644,8 @@ _mesa_GetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, } else if (att->Type == GL_TEXTURE) { *params = att->Layered; } else if (att->Type == GL_NONE) { - _mesa_error(ctx, err, - "glGetFramebufferAttachmentParameteriv(pname)"); + _mesa_error(ctx, err, "%s(invalid pname %s)", caller, + _mesa_lookup_enum_by_nr(pname)); } else { goto invalid_pname_enum; } @@ -3182,30 +3657,145 @@ _mesa_GetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, return; invalid_pname_enum: - _mesa_error(ctx, GL_INVALID_ENUM, - "glGetFramebufferAttachmentParameteriv(pname)"); + _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid pname %s)", caller, + _mesa_lookup_enum_by_nr(pname)); return; } +void GLAPIENTRY +_mesa_GetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, + GLenum pname, GLint *params) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_framebuffer *buffer; + + buffer = get_framebuffer_target(ctx, target); + if (!buffer) { + _mesa_error(ctx, GL_INVALID_ENUM, + "glGetFramebufferAttachmentParameteriv(invalid target %s)", + _mesa_lookup_enum_by_nr(target)); + return; + } + + _mesa_get_framebuffer_attachment_parameter(ctx, buffer, attachment, pname, + params, + "glGetFramebufferAttachmentParameteriv"); +} + + +void GLAPIENTRY +_mesa_GetNamedFramebufferAttachmentParameteriv(GLuint framebuffer, + GLenum attachment, + GLenum pname, GLint *params) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_framebuffer *buffer; + + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetNamedFramebufferAttachmentParameteriv(" + "GL_ARB_direct_state_access is not supported)"); + return; + } + + if (framebuffer) { + buffer = _mesa_lookup_framebuffer_err(ctx, framebuffer, + "glGetNamedFramebufferAttachmentParameteriv"); + if (!buffer) + return; + } + else { + /* + * Section 9.2 Binding and Managing Framebuffer Objects of the OpenGL + * 4.5 core spec (30.10.2014, PDF page 314): + * "If framebuffer is zero, then the default draw framebuffer is + * queried." + */ + buffer = ctx->WinSysDrawBuffer; + } + + _mesa_get_framebuffer_attachment_parameter(ctx, buffer, attachment, pname, + params, + "glGetNamedFramebufferAttachmentParameteriv"); +} + + +void GLAPIENTRY +_mesa_NamedFramebufferParameteri(GLuint framebuffer, GLenum pname, + GLint param) +{ + GET_CURRENT_CONTEXT(ctx); + + (void) framebuffer; + (void) pname; + (void) param; + + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glNamedFramebufferParameteri(" + "GL_ARB_direct_state_access is not supported)"); + return; + } + + _mesa_error(ctx, GL_INVALID_OPERATION, + "glNamedFramebufferParameteri not supported " + "(ARB_framebuffer_no_attachments not implemented)"); +} + + +void GLAPIENTRY +_mesa_GetNamedFramebufferParameteriv(GLuint framebuffer, GLenum pname, + GLint *param) +{ + GET_CURRENT_CONTEXT(ctx); + + (void) framebuffer; + (void) pname; + (void) param; + + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glNamedFramebufferParameteriv(" + "GL_ARB_direct_state_access is not supported)"); + return; + } + + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetNamedFramebufferParameteriv not supported " + "(ARB_framebuffer_no_attachments not implemented)"); +} + + static void -invalidate_framebuffer_storage(GLenum target, GLsizei numAttachments, +invalidate_framebuffer_storage(struct gl_context *ctx, + struct gl_framebuffer *fb, + GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height, const char *name) { int i; - struct gl_framebuffer *fb; - GET_CURRENT_CONTEXT(ctx); - fb = get_framebuffer_target(ctx, target); - if (!fb) { - _mesa_error(ctx, GL_INVALID_ENUM, "%s(target)", name); + /* Section 17.4 Whole Framebuffer Operations of the OpenGL 4.5 Core + * Spec (2.2.2015, PDF page 522) says: + * "An INVALID_VALUE error is generated if numAttachments, width, or + * height is negative." + */ + if (numAttachments < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, + "%s(numAttachments < 0)", name); return; } - if (numAttachments < 0) { + if (width < 0) { _mesa_error(ctx, GL_INVALID_VALUE, - "%s(numAttachments < 0)", name); + "%s(width < 0)", name); + return; + } + + if (height < 0) { + _mesa_error(ctx, GL_INVALID_VALUE, + "%s(height < 0)", name); return; } @@ -3301,7 +3891,8 @@ invalidate_framebuffer_storage(GLenum target, GLsizei numAttachments, return; invalid_enum: - _mesa_error(ctx, GL_INVALID_ENUM, "%s(attachment)", name); + _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid attachment %s)", name, + _mesa_lookup_enum_by_nr(attachments[i])); return; } @@ -3311,16 +3902,74 @@ _mesa_InvalidateSubFramebuffer(GLenum target, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height) { - invalidate_framebuffer_storage(target, numAttachments, attachments, + struct gl_framebuffer *fb; + GET_CURRENT_CONTEXT(ctx); + + fb = get_framebuffer_target(ctx, target); + if (!fb) { + _mesa_error(ctx, GL_INVALID_ENUM, + "glInvalidateSubFramebuffer(invalid target %s)", + _mesa_lookup_enum_by_nr(target)); + return; + } + + invalidate_framebuffer_storage(ctx, fb, numAttachments, attachments, x, y, width, height, "glInvalidateSubFramebuffer"); } void GLAPIENTRY +_mesa_InvalidateNamedFramebufferSubData(GLuint framebuffer, + GLsizei numAttachments, + const GLenum *attachments, + GLint x, GLint y, + GLsizei width, GLsizei height) +{ + struct gl_framebuffer *fb; + GET_CURRENT_CONTEXT(ctx); + + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glInvalidateNamedFramebufferSubData(" + "GL_ARB_direct_state_access is not supported)"); + return; + } + + /* The OpenGL 4.5 core spec (02.02.2015) says (in Section 17.4 Whole + * Framebuffer Operations, PDF page 522): "If framebuffer is zero, the + * default draw framebuffer is affected." + */ + if (framebuffer) { + fb = _mesa_lookup_framebuffer_err(ctx, framebuffer, + "glInvalidateNamedFramebufferSubData"); + if (!fb) + return; + } + else + fb = ctx->WinSysDrawBuffer; + + invalidate_framebuffer_storage(ctx, fb, numAttachments, attachments, + x, y, width, height, + "glInvalidateNamedFramebufferSubData"); +} + + +void GLAPIENTRY _mesa_InvalidateFramebuffer(GLenum target, GLsizei numAttachments, const GLenum *attachments) { + struct gl_framebuffer *fb; + GET_CURRENT_CONTEXT(ctx); + + fb = get_framebuffer_target(ctx, target); + if (!fb) { + _mesa_error(ctx, GL_INVALID_ENUM, + "glInvalidateFramebuffer(invalid target %s)", + _mesa_lookup_enum_by_nr(target)); + return; + } + /* The GL_ARB_invalidate_subdata spec says: * * "The command @@ -3333,7 +3982,7 @@ _mesa_InvalidateFramebuffer(GLenum target, GLsizei numAttachments, * <width>, <height> equal to 0, 0, <MAX_VIEWPORT_DIMS[0]>, * <MAX_VIEWPORT_DIMS[1]> respectively." */ - invalidate_framebuffer_storage(target, numAttachments, attachments, + invalidate_framebuffer_storage(ctx, fb, numAttachments, attachments, 0, 0, MAX_VIEWPORT_WIDTH, MAX_VIEWPORT_HEIGHT, "glInvalidateFramebuffer"); @@ -3341,6 +3990,53 @@ _mesa_InvalidateFramebuffer(GLenum target, GLsizei numAttachments, void GLAPIENTRY +_mesa_InvalidateNamedFramebufferData(GLuint framebuffer, + GLsizei numAttachments, + const GLenum *attachments) +{ + struct gl_framebuffer *fb; + GET_CURRENT_CONTEXT(ctx); + + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glInvalidateNamedFramebufferData(" + "GL_ARB_direct_state_access is not supported)"); + return; + } + + /* The OpenGL 4.5 core spec (02.02.2015) says (in Section 17.4 Whole + * Framebuffer Operations, PDF page 522): "If framebuffer is zero, the + * default draw framebuffer is affected." + */ + if (framebuffer) { + fb = _mesa_lookup_framebuffer_err(ctx, framebuffer, + "glInvalidateNamedFramebufferData"); + if (!fb) + return; + } + else + fb = ctx->WinSysDrawBuffer; + + /* The GL_ARB_invalidate_subdata spec says: + * + * "The command + * + * void InvalidateFramebuffer(enum target, + * sizei numAttachments, + * const enum *attachments); + * + * is equivalent to the command InvalidateSubFramebuffer with <x>, <y>, + * <width>, <height> equal to 0, 0, <MAX_VIEWPORT_DIMS[0]>, + * <MAX_VIEWPORT_DIMS[1]> respectively." + */ + invalidate_framebuffer_storage(ctx, fb, numAttachments, attachments, + 0, 0, + MAX_VIEWPORT_WIDTH, MAX_VIEWPORT_HEIGHT, + "glInvalidateNamedFramebufferData"); +} + + +void GLAPIENTRY _mesa_DiscardFramebufferEXT(GLenum target, GLsizei numAttachments, const GLenum *attachments) { diff --git a/mesalib/src/mesa/main/fbobject.h b/mesalib/src/mesa/main/fbobject.h index 61aa1f503..9f570db3a 100644 --- a/mesalib/src/mesa/main/fbobject.h +++ b/mesalib/src/mesa/main/fbobject.h @@ -64,9 +64,17 @@ _mesa_get_incomplete_framebuffer(void); extern struct gl_renderbuffer * _mesa_lookup_renderbuffer(struct gl_context *ctx, GLuint id); +extern struct gl_renderbuffer * +_mesa_lookup_renderbuffer_err(struct gl_context *ctx, GLuint id, + const char *func); + extern struct gl_framebuffer * _mesa_lookup_framebuffer(struct gl_context *ctx, GLuint id); +extern struct gl_framebuffer * +_mesa_lookup_framebuffer_err(struct gl_context *ctx, GLuint id, + const char *func); + void _mesa_update_texture_renderbuffer(struct gl_context *ctx, @@ -74,9 +82,17 @@ _mesa_update_texture_renderbuffer(struct gl_context *ctx, struct gl_renderbuffer_attachment *att); extern void +_mesa_FramebufferRenderbuffer_sw(struct gl_context *ctx, + struct gl_framebuffer *fb, + GLenum attachment, + struct gl_renderbuffer *rb); + +extern void _mesa_framebuffer_renderbuffer(struct gl_context *ctx, struct gl_framebuffer *fb, - GLenum attachment, struct gl_renderbuffer *rb); + GLenum attachment, + struct gl_renderbuffer *rb, + const char *func); extern void _mesa_validate_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb); @@ -99,6 +115,24 @@ _mesa_detach_renderbuffer(struct gl_context *ctx, struct gl_framebuffer *fb, const void *att); +extern void +_mesa_framebuffer_texture(struct gl_context *ctx, struct gl_framebuffer *fb, + GLenum attachment, + struct gl_texture_object *texObj, GLenum textarget, + GLint level, GLuint layer, GLboolean layered, + const char *caller); + +extern GLenum +_mesa_check_framebuffer_status(struct gl_context *ctx, + struct gl_framebuffer *fb); + +extern void +_mesa_get_framebuffer_attachment_parameter(struct gl_context *ctx, + struct gl_framebuffer *buffer, + GLenum attachment, GLenum pname, + GLint *params, const char *caller); + + extern GLboolean GLAPIENTRY _mesa_IsRenderbuffer(GLuint renderbuffer); @@ -165,9 +199,15 @@ _mesa_DeleteFramebuffers(GLsizei n, const GLuint *framebuffers); extern void GLAPIENTRY _mesa_GenFramebuffers(GLsizei n, GLuint *framebuffers); +extern void GLAPIENTRY +_mesa_CreateFramebuffers(GLsizei n, GLuint *framebuffers); + extern GLenum GLAPIENTRY _mesa_CheckFramebufferStatus(GLenum target); +extern GLenum GLAPIENTRY +_mesa_CheckNamedFramebufferStatus(GLuint framebuffer, GLenum target); + extern void GLAPIENTRY _mesa_FramebufferTexture1D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); @@ -179,24 +219,49 @@ _mesa_FramebufferTexture2D(GLenum target, GLenum attachment, extern void GLAPIENTRY _mesa_FramebufferTexture3D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, - GLint level, GLint zoffset); + GLint level, GLint layer); extern void GLAPIENTRY _mesa_FramebufferTextureLayer(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); extern void GLAPIENTRY +_mesa_NamedFramebufferTextureLayer(GLuint framebuffer, GLenum attachment, + GLuint texture, GLint level, GLint layer); + +extern void GLAPIENTRY _mesa_FramebufferTexture(GLenum target, GLenum attachment, GLuint texture, GLint level); extern void GLAPIENTRY +_mesa_NamedFramebufferTexture(GLuint framebuffer, GLenum attachment, + GLuint texture, GLint level); + +extern void GLAPIENTRY _mesa_FramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); extern void GLAPIENTRY +_mesa_NamedFramebufferRenderbuffer(GLuint framebuffer, GLenum attachment, + GLenum renderbuffertarget, + GLuint renderbuffer); + +extern void GLAPIENTRY _mesa_GetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint *params); +extern void GLAPIENTRY +_mesa_GetNamedFramebufferAttachmentParameteriv(GLuint framebuffer, + GLenum attachment, + GLenum pname, GLint *params); + +extern void GLAPIENTRY +_mesa_NamedFramebufferParameteri(GLuint framebuffer, GLenum pname, + GLint param); + +extern void GLAPIENTRY +_mesa_GetNamedFramebufferParameteriv(GLuint framebuffer, GLenum pname, + GLint *param); extern void GLAPIENTRY _mesa_InvalidateSubFramebuffer(GLenum target, GLsizei numAttachments, @@ -204,10 +269,22 @@ _mesa_InvalidateSubFramebuffer(GLenum target, GLsizei numAttachments, GLsizei width, GLsizei height); extern void GLAPIENTRY +_mesa_InvalidateNamedFramebufferSubData(GLuint framebuffer, + GLsizei numAttachments, + const GLenum *attachments, + GLint x, GLint y, + GLsizei width, GLsizei height); + +extern void GLAPIENTRY _mesa_InvalidateFramebuffer(GLenum target, GLsizei numAttachments, const GLenum *attachments); extern void GLAPIENTRY +_mesa_InvalidateNamedFramebufferData(GLuint framebuffer, + GLsizei numAttachments, + const GLenum *attachments); + +extern void GLAPIENTRY _mesa_DiscardFramebufferEXT(GLenum target, GLsizei numAttachments, const GLenum *attachments); diff --git a/mesalib/src/mesa/main/ffvertex_prog.c b/mesalib/src/mesa/main/ffvertex_prog.c index 7fdd9bab6..70adaf885 100644 --- a/mesalib/src/mesa/main/ffvertex_prog.c +++ b/mesalib/src/mesa/main/ffvertex_prog.c @@ -135,7 +135,7 @@ static GLboolean check_active_shininess( struct gl_context *ctx, (key->light_color_material_mask & (1 << attr))) return GL_TRUE; - if (key->varying_vp_inputs & VERT_ATTRIB_GENERIC(attr)) + if (key->varying_vp_inputs & VERT_BIT_GENERIC(attr)) return GL_TRUE; if (ctx->Light.Material.Attrib[attr][0] != 0.0F) diff --git a/mesalib/src/mesa/main/framebuffer.c b/mesalib/src/mesa/main/framebuffer.c index 4f7736a64..665a5ba14 100644 --- a/mesalib/src/mesa/main/framebuffer.c +++ b/mesalib/src/mesa/main/framebuffer.c @@ -312,7 +312,7 @@ _mesa_resize_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb, if (ctx) { /* update scissor / window bounds */ - _mesa_update_draw_buffer_bounds(ctx); + _mesa_update_draw_buffer_bounds(ctx, ctx->DrawBuffer); /* Signal new buffer state so that swrast will update its clipping * info (the CLIP_BIT flag). */ @@ -413,9 +413,9 @@ _mesa_scissor_bounding_box(const struct gl_context *ctx, * \param ctx the GL context. */ void -_mesa_update_draw_buffer_bounds(struct gl_context *ctx) +_mesa_update_draw_buffer_bounds(struct gl_context *ctx, + struct gl_framebuffer *buffer) { - struct gl_framebuffer *buffer = ctx->DrawBuffer; int bbox[4]; if (!buffer) @@ -652,7 +652,7 @@ update_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb) * context state (GL_READ_BUFFER too). */ if (fb->ColorDrawBuffer[0] != ctx->Color.DrawBuffer[0]) { - _mesa_drawbuffers(ctx, ctx->Const.MaxDrawBuffers, + _mesa_drawbuffers(ctx, fb, ctx->Const.MaxDrawBuffers, ctx->Color.DrawBuffer, NULL); } } @@ -678,24 +678,21 @@ update_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb) /** - * Update state related to the current draw/read framebuffers. + * Update state related to the draw/read framebuffers. */ void -_mesa_update_framebuffer(struct gl_context *ctx) +_mesa_update_framebuffer(struct gl_context *ctx, + struct gl_framebuffer *readFb, + struct gl_framebuffer *drawFb) { - struct gl_framebuffer *drawFb; - struct gl_framebuffer *readFb; - assert(ctx); - drawFb = ctx->DrawBuffer; - readFb = ctx->ReadBuffer; update_framebuffer(ctx, drawFb); if (readFb != drawFb) update_framebuffer(ctx, readFb); - _mesa_update_clamp_vertex_color(ctx); - _mesa_update_clamp_fragment_color(ctx); + _mesa_update_clamp_vertex_color(ctx, drawFb); + _mesa_update_clamp_fragment_color(ctx, drawFb); } diff --git a/mesalib/src/mesa/main/framebuffer.h b/mesalib/src/mesa/main/framebuffer.h index a4274216e..d02b86f20 100644 --- a/mesalib/src/mesa/main/framebuffer.h +++ b/mesalib/src/mesa/main/framebuffer.h @@ -77,14 +77,17 @@ _mesa_scissor_bounding_box(const struct gl_context *ctx, unsigned idx, int *bbox); extern void -_mesa_update_draw_buffer_bounds(struct gl_context *ctx); +_mesa_update_draw_buffer_bounds(struct gl_context *ctx, + struct gl_framebuffer *drawFb); extern void _mesa_update_framebuffer_visual(struct gl_context *ctx, struct gl_framebuffer *fb); extern void -_mesa_update_framebuffer(struct gl_context *ctx); +_mesa_update_framebuffer(struct gl_context *ctx, + struct gl_framebuffer *readFb, + struct gl_framebuffer *drawFb); extern GLboolean _mesa_source_buffer_exists(struct gl_context *ctx, GLenum format); diff --git a/mesalib/src/mesa/main/genmipmap.c b/mesalib/src/mesa/main/genmipmap.c index 9aef09019..32b9460ad 100644 --- a/mesalib/src/mesa/main/genmipmap.c +++ b/mesalib/src/mesa/main/genmipmap.c @@ -158,6 +158,13 @@ _mesa_GenerateTextureMipmap(GLuint texture) struct gl_texture_object *texObj; GET_CURRENT_CONTEXT(ctx); + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGenerateTextureMipmap(GL_ARB_direct_state_access " + "is not supported)"); + return; + } + texObj = _mesa_lookup_texture_err(ctx, texture, "glGenerateTextureMipmap"); if (!texObj) return; diff --git a/mesalib/src/mesa/main/get.c b/mesalib/src/mesa/main/get.c index a881bc589..8a6c81aff 100644 --- a/mesalib/src/mesa/main/get.c +++ b/mesalib/src/mesa/main/get.c @@ -909,13 +909,13 @@ find_custom_value(struct gl_context *ctx, const struct value_desc *d, union valu break; case GL_FOG_COLOR: - if (_mesa_get_clamp_fragment_color(ctx)) + if (_mesa_get_clamp_fragment_color(ctx, ctx->DrawBuffer)) COPY_4FV(v->value_float_4, ctx->Fog.Color); else COPY_4FV(v->value_float_4, ctx->Fog.ColorUnclamped); break; case GL_COLOR_CLEAR_VALUE: - if (_mesa_get_clamp_fragment_color(ctx)) { + if (_mesa_get_clamp_fragment_color(ctx, ctx->DrawBuffer)) { v->value_float_4[0] = CLAMP(ctx->Color.ClearColor.f[0], 0.0F, 1.0F); v->value_float_4[1] = CLAMP(ctx->Color.ClearColor.f[1], 0.0F, 1.0F); v->value_float_4[2] = CLAMP(ctx->Color.ClearColor.f[2], 0.0F, 1.0F); @@ -924,13 +924,13 @@ find_custom_value(struct gl_context *ctx, const struct value_desc *d, union valu COPY_4FV(v->value_float_4, ctx->Color.ClearColor.f); break; case GL_BLEND_COLOR_EXT: - if (_mesa_get_clamp_fragment_color(ctx)) + if (_mesa_get_clamp_fragment_color(ctx, ctx->DrawBuffer)) COPY_4FV(v->value_float_4, ctx->Color.BlendColor); else COPY_4FV(v->value_float_4, ctx->Color.BlendColorUnclamped); break; case GL_ALPHA_TEST_REF: - if (_mesa_get_clamp_fragment_color(ctx)) + if (_mesa_get_clamp_fragment_color(ctx, ctx->DrawBuffer)) v->value_float = ctx->Color.AlphaRef; else v->value_float = ctx->Color.AlphaRefUnclamped; @@ -1911,6 +1911,7 @@ find_value_indexed(const char *func, GLenum pname, GLuint index, union value *v) if (index >= ctx->Const.Program[MESA_SHADER_VERTEX].MaxAttribs) goto invalid_value; v->value_int = ctx->Array.VAO->VertexBinding[VERT_ATTRIB_GENERIC(index)].Stride; + return TYPE_INT; /* ARB_shader_image_load_store */ case GL_IMAGE_BINDING_NAME: { diff --git a/mesalib/src/mesa/main/mtypes.h b/mesalib/src/mesa/main/mtypes.h index fb4143086..83425176a 100644 --- a/mesalib/src/mesa/main/mtypes.h +++ b/mesalib/src/mesa/main/mtypes.h @@ -695,7 +695,8 @@ struct gl_current_attrib * \note Index and Edgeflag current values are stored as floats in the * SIX and SEVEN attribute slots. */ - GLfloat Attrib[VERT_ATTRIB_MAX][4]; /**< Position, color, texcoords, etc */ + /* we need double storage for this for vertex attrib 64bit */ + GLfloat Attrib[VERT_ATTRIB_MAX][4*2]; /**< Position, color, texcoords, etc */ /** * \name Current raster position attributes (always valid). @@ -1523,6 +1524,7 @@ struct gl_client_array GLboolean Enabled; /**< Enabled flag is a boolean */ GLboolean Normalized; /**< GL_ARB_vertex_program */ GLboolean Integer; /**< Integer-valued? */ + GLboolean Doubles; /**< double precision values are not converted to floats */ GLuint InstanceDivisor; /**< GL_ARB_instanced_arrays */ struct gl_buffer_object *BufferObj;/**< GL_ARB_vertex_buffer_object */ @@ -1553,6 +1555,7 @@ struct gl_vertex_attrib_array GLboolean Enabled; /**< Whether the array is enabled */ GLboolean Normalized; /**< Fixed-point values are normalized when converted to floats */ GLboolean Integer; /**< Fixed-point values are not converted to floats */ + GLboolean Doubles; /**< double precision values are not converted to floats */ GLuint _ElementSize; /**< Size of each element in bytes */ GLuint VertexBinding; /**< Vertex buffer binding */ }; @@ -1671,6 +1674,9 @@ struct gl_array_attrib /** The default vertex array object */ struct gl_vertex_array_object *DefaultVAO; + /** The last VAO accessed by a DSA function */ + struct gl_vertex_array_object *LastLookedUpVAO; + /** Array objects (GL_ARB/APPLE_vertex_array_object) */ struct _mesa_HashTable *Objects; @@ -2090,6 +2096,7 @@ struct gl_program struct nir_shader *nir; GLbitfield64 InputsRead; /**< Bitmask of which input regs are read */ + GLbitfield64 DoubleInputsRead; /**< Bitmask of which input regs are read and are doubles */ GLbitfield64 OutputsWritten; /**< Bitmask of which output regs are written */ GLbitfield SystemValuesRead; /**< Bitmask of SYSTEM_VALUE_x inputs used */ GLbitfield InputFlags[MAX_PROGRAM_INPUTS]; /**< PROG_PARAM_BIT_x flags */ @@ -2499,6 +2506,12 @@ struct gl_shader GLuint NumImages; /** + * Whether early fragment tests are enabled as defined by + * ARB_shader_image_load_store. + */ + bool EarlyFragmentTests; + + /** * Compute shader state from ARB_compute_shader layout qualifiers. */ struct { @@ -3608,6 +3621,7 @@ struct gl_extensions GLboolean ARB_depth_clamp; GLboolean ARB_depth_texture; GLboolean ARB_derivative_control; + GLboolean ARB_direct_state_access; GLboolean ARB_draw_buffers_blend; GLboolean ARB_draw_elements_base_vertex; GLboolean ARB_draw_indirect; @@ -3672,6 +3686,7 @@ struct gl_extensions GLboolean ARB_transform_feedback3; GLboolean ARB_transform_feedback_instanced; GLboolean ARB_uniform_buffer_object; + GLboolean ARB_vertex_attrib_64bit; GLboolean ARB_vertex_program; GLboolean ARB_vertex_shader; GLboolean ARB_vertex_type_10f_11f_11f_rev; diff --git a/mesalib/src/mesa/main/pipelineobj.c b/mesalib/src/mesa/main/pipelineobj.c index 0fefa7d56..a33cdd139 100644 --- a/mesalib/src/mesa/main/pipelineobj.c +++ b/mesalib/src/mesa/main/pipelineobj.c @@ -553,6 +553,12 @@ _mesa_CreateProgramPipelines(GLsizei n, GLuint *pipelines) { GET_CURRENT_CONTEXT(ctx); + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glCreateProgramPipelines(" + "GL_ARB_direct_state_access is not supported)"); + return; + } + create_program_pipelines(ctx, n, pipelines, true); } diff --git a/mesalib/src/mesa/main/queryobj.c b/mesalib/src/mesa/main/queryobj.c index fbccf3fe6..2784b4c05 100644 --- a/mesalib/src/mesa/main/queryobj.c +++ b/mesalib/src/mesa/main/queryobj.c @@ -284,6 +284,13 @@ _mesa_CreateQueries(GLenum target, GLsizei n, GLuint *ids) { GET_CURRENT_CONTEXT(ctx); + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glCreateQueries(GL_ARB_direct_state_access " + "is not supported)"); + return; + } + switch (target) { case GL_SAMPLES_PASSED: case GL_ANY_SAMPLES_PASSED: @@ -776,6 +783,9 @@ _mesa_GetQueryObjectiv(GLuint id, GLenum pname, GLint *params) ctx->Driver.CheckQuery( ctx, q ); *params = q->Ready; break; + case GL_QUERY_TARGET: + *params = q->Target; + break; default: _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjectivARB(pname)"); return; @@ -827,6 +837,9 @@ _mesa_GetQueryObjectuiv(GLuint id, GLenum pname, GLuint *params) ctx->Driver.CheckQuery( ctx, q ); *params = q->Ready; break; + case GL_QUERY_TARGET: + *params = q->Target; + break; default: _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjectuivARB(pname)"); return; @@ -867,6 +880,9 @@ _mesa_GetQueryObjecti64v(GLuint id, GLenum pname, GLint64EXT *params) ctx->Driver.CheckQuery( ctx, q ); *params = q->Ready; break; + case GL_QUERY_TARGET: + *params = q->Target; + break; default: _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjecti64vARB(pname)"); return; @@ -907,6 +923,9 @@ _mesa_GetQueryObjectui64v(GLuint id, GLenum pname, GLuint64EXT *params) ctx->Driver.CheckQuery( ctx, q ); *params = q->Ready; break; + case GL_QUERY_TARGET: + *params = q->Target; + break; default: _mesa_error(ctx, GL_INVALID_ENUM, "glGetQueryObjectui64vARB(pname)"); return; diff --git a/mesalib/src/mesa/main/readpix.c b/mesalib/src/mesa/main/readpix.c index ed0104c9e..df46f8361 100644 --- a/mesalib/src/mesa/main/readpix.c +++ b/mesalib/src/mesa/main/readpix.c @@ -83,7 +83,7 @@ get_readpixels_transfer_ops(const struct gl_context *ctx, mesa_format texFormat, if (uses_blit) { /* For blit-based ReadPixels packing, the clamping is done automatically * unless the type is float. */ - if (_mesa_get_clamp_read_color(ctx) && + if (_mesa_get_clamp_read_color(ctx, ctx->ReadBuffer) && (type == GL_FLOAT || type == GL_HALF_FLOAT)) { transferOps |= IMAGE_CLAMP_BIT; } @@ -91,7 +91,7 @@ get_readpixels_transfer_ops(const struct gl_context *ctx, mesa_format texFormat, else { /* For CPU-based ReadPixels packing, the clamping must always be done * for non-float types, */ - if (_mesa_get_clamp_read_color(ctx) || + if (_mesa_get_clamp_read_color(ctx, ctx->ReadBuffer) || (type != GL_FLOAT && type != GL_HALF_FLOAT)) { transferOps |= IMAGE_CLAMP_BIT; } diff --git a/mesalib/src/mesa/main/samplerobj.c b/mesalib/src/mesa/main/samplerobj.c index a3aacc66a..60711a5b5 100644 --- a/mesalib/src/mesa/main/samplerobj.c +++ b/mesalib/src/mesa/main/samplerobj.c @@ -221,6 +221,13 @@ void GLAPIENTRY _mesa_CreateSamplers(GLsizei count, GLuint *samplers) { GET_CURRENT_CONTEXT(ctx); + + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glCreateSamplers(" + "GL_ARB_direct_state_access is not supported)"); + return; + } + create_samplers(ctx, count, samplers, "glCreateSamplers"); } diff --git a/mesalib/src/mesa/main/shader_query.cpp b/mesalib/src/mesa/main/shader_query.cpp index d2ca49b43..3445f89a3 100644 --- a/mesalib/src/mesa/main/shader_query.cpp +++ b/mesalib/src/mesa/main/shader_query.cpp @@ -28,6 +28,7 @@ * \author Ian Romanick <ian.d.romanick@intel.com> */ +#include "main/context.h" #include "main/core.h" #include "glsl_symbol_table.h" #include "ir.h" @@ -809,6 +810,8 @@ stage_from_enum(GLenum ref) return MESA_SHADER_GEOMETRY; case GL_REFERENCED_BY_FRAGMENT_SHADER: return MESA_SHADER_FRAGMENT; + case GL_REFERENCED_BY_COMPUTE_SHADER: + return MESA_SHADER_COMPUTE; default: assert(!"shader stage not supported"); return MESA_SHADER_STAGES; @@ -824,6 +827,10 @@ is_resource_referenced(struct gl_shader_program *shProg, struct gl_program_resource *res, GLuint index, uint8_t stage) { + /* First, check if we even have such a stage active. */ + if (!shProg->_LinkedShaders[stage]) + return false; + if (res->Type == GL_ATOMIC_COUNTER_BUFFER) return RESOURCE_ATC(res)->StageReferences[stage]; @@ -979,6 +986,10 @@ _mesa_program_resource_prop(struct gl_shader_program *shProg, case GL_NUM_ACTIVE_VARIABLES: case GL_ACTIVE_VARIABLES: return get_buffer_property(shProg, res, prop, val, caller); + case GL_REFERENCED_BY_COMPUTE_SHADER: + if (!_mesa_has_compute_shaders(ctx)) + goto invalid_enum; + /* fallthrough */ case GL_REFERENCED_BY_VERTEX_SHADER: case GL_REFERENCED_BY_GEOMETRY_SHADER: case GL_REFERENCED_BY_FRAGMENT_SHADER: @@ -1015,17 +1026,18 @@ _mesa_program_resource_prop(struct gl_shader_program *shProg, case GL_IS_PER_PATCH: case GL_REFERENCED_BY_TESS_CONTROL_SHADER: case GL_REFERENCED_BY_TESS_EVALUATION_SHADER: - /* GL_ARB_compute_shader */ - case GL_REFERENCED_BY_COMPUTE_SHADER: default: - _mesa_error(ctx, GL_INVALID_ENUM, "%s(%s prop %s)", caller, - _mesa_lookup_enum_by_nr(res->Type), - _mesa_lookup_enum_by_nr(prop)); - return 0; + goto invalid_enum; } #undef VALIDATE_TYPE +invalid_enum: + _mesa_error(ctx, GL_INVALID_ENUM, "%s(%s prop %s)", caller, + _mesa_lookup_enum_by_nr(res->Type), + _mesa_lookup_enum_by_nr(prop)); + return 0; + invalid_operation: _mesa_error(ctx, GL_INVALID_OPERATION, "%s(%s prop %s)", caller, _mesa_lookup_enum_by_nr(res->Type), diff --git a/mesalib/src/mesa/main/shaderimage.c b/mesalib/src/mesa/main/shaderimage.c index dcbcca623..80b77275f 100644 --- a/mesalib/src/mesa/main/shaderimage.c +++ b/mesalib/src/mesa/main/shaderimage.c @@ -58,8 +58,8 @@ # define MESA_FORMAT_SIGNED_RG_8 MESA_FORMAT_R8G8_SNORM #endif -static mesa_format -get_image_format(GLenum format) +mesa_format +_mesa_get_shader_image_format(GLenum format) { switch (format) { case GL_RGBA32F: @@ -331,19 +331,33 @@ get_image_format_class(mesa_format format) } } +void +_mesa_init_image_units(struct gl_context *ctx) +{ + unsigned i; + + for (i = 0; i < ARRAY_SIZE(ctx->ImageUnits); ++i) { + struct gl_image_unit *u = &ctx->ImageUnits[i]; + u->Access = GL_READ_ONLY; + u->Format = GL_R8; + u->_ActualFormat = _mesa_get_shader_image_format(u->Format); + } +} + static GLboolean validate_image_unit(struct gl_context *ctx, struct gl_image_unit *u) { struct gl_texture_object *t = u->TexObj; - struct gl_texture_image *img; + mesa_format tex_format; - if (!t || u->Level < t->BaseLevel || - u->Level > t->_MaxLevel) + if (!t) return GL_FALSE; _mesa_test_texobj_completeness(ctx, t); - if ((u->Level == t->BaseLevel && !t->_BaseComplete) || + if (u->Level < t->BaseLevel || + u->Level > t->_MaxLevel || + (u->Level == t->BaseLevel && !t->_BaseComplete) || (u->Level != t->BaseLevel && !t->_MipmapComplete)) return GL_FALSE; @@ -351,25 +365,32 @@ validate_image_unit(struct gl_context *ctx, struct gl_image_unit *u) u->Layer >= _mesa_get_texture_layers(t, u->Level)) return GL_FALSE; - if (t->Target == GL_TEXTURE_CUBE_MAP) - img = t->Image[u->Layer][u->Level]; - else - img = t->Image[0][u->Level]; + if (t->Target == GL_TEXTURE_BUFFER) { + tex_format = _mesa_get_shader_image_format(t->BufferObjectFormat); + + } else { + struct gl_texture_image *img = (t->Target == GL_TEXTURE_CUBE_MAP ? + t->Image[u->Layer][u->Level] : + t->Image[0][u->Level]); - if (!img || img->Border || - get_image_format_class(img->TexFormat) == IMAGE_FORMAT_CLASS_NONE || - img->NumSamples > ctx->Const.MaxImageSamples) + if (!img || img->Border || img->NumSamples > ctx->Const.MaxImageSamples) + return GL_FALSE; + + tex_format = _mesa_get_shader_image_format(img->InternalFormat); + } + + if (!tex_format) return GL_FALSE; switch (t->ImageFormatCompatibilityType) { case GL_IMAGE_FORMAT_COMPATIBILITY_BY_SIZE: - if (_mesa_get_format_bytes(img->TexFormat) != + if (_mesa_get_format_bytes(tex_format) != _mesa_get_format_bytes(u->_ActualFormat)) return GL_FALSE; break; case GL_IMAGE_FORMAT_COMPATIBILITY_BY_CLASS: - if (get_image_format_class(img->TexFormat) != + if (get_image_format_class(tex_format) != get_image_format_class(u->_ActualFormat)) return GL_FALSE; break; @@ -421,7 +442,7 @@ validate_bind_image_texture(struct gl_context *ctx, GLuint unit, return GL_FALSE; } - if (!get_image_format(format)) { + if (!_mesa_get_shader_image_format(format)) { _mesa_error(ctx, GL_INVALID_VALUE, "glBindImageTexture(format)"); return GL_FALSE; } @@ -435,7 +456,6 @@ _mesa_BindImageTexture(GLuint unit, GLuint texture, GLint level, GLenum format) { GET_CURRENT_CONTEXT(ctx); - struct gl_texture_object *t = NULL; struct gl_image_unit *u; if (!validate_bind_image_texture(ctx, unit, texture, level, @@ -448,34 +468,34 @@ _mesa_BindImageTexture(GLuint unit, GLuint texture, GLint level, ctx->NewDriverState |= ctx->DriverFlags.NewImageUnits; if (texture) { - t = _mesa_lookup_texture(ctx, texture); + struct gl_texture_object *t = _mesa_lookup_texture(ctx, texture); + if (!t) { _mesa_error(ctx, GL_INVALID_VALUE, "glBindImageTexture(texture)"); return; } _mesa_reference_texobj(&u->TexObj, t); - u->Level = level; - u->Access = access; - u->Format = format; - u->_ActualFormat = get_image_format(format); - - if (_mesa_tex_target_is_layered(t->Target)) { - u->Layered = layered; - u->Layer = (layered ? 0 : layer); - } else { - u->Layered = GL_FALSE; - u->Layer = 0; - } - } else { _mesa_reference_texobj(&u->TexObj, NULL); } + u->Level = level; + u->Access = access; + u->Format = format; + u->_ActualFormat = _mesa_get_shader_image_format(format); u->_Valid = validate_image_unit(ctx, u); + if (u->TexObj && _mesa_tex_target_is_layered(u->TexObj->Target)) { + u->Layered = layered; + u->Layer = (layered ? 0 : layer); + } else { + u->Layered = GL_FALSE; + u->Layer = 0; + } + if (ctx->Driver.BindImageTexture) - ctx->Driver.BindImageTexture(ctx, u, t, level, layered, + ctx->Driver.BindImageTexture(ctx, u, u->TexObj, level, layered, layer, access, format); } @@ -535,8 +555,7 @@ _mesa_BindImageTextures(GLuint first, GLsizei count, const GLuint *textures) if (texture != 0) { struct gl_texture_object *texObj; - struct gl_texture_image *image; - mesa_format actualFormat; + GLenum tex_format; if (!u->TexObj || u->TexObj->Name != texture) { texObj = _mesa_lookup_texture_locked(ctx, texture); @@ -557,25 +576,30 @@ _mesa_BindImageTextures(GLuint first, GLsizei count, const GLuint *textures) texObj = u->TexObj; } - image = texObj->Image[0][0]; + if (texObj->Target == GL_TEXTURE_BUFFER) { + tex_format = texObj->BufferObjectFormat; + } else { + struct gl_texture_image *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; - } + 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); + tex_format = image->InternalFormat; + } - if (actualFormat == MESA_FORMAT_NONE) { + if (_mesa_get_shader_image_format(tex_format) == MESA_FORMAT_NONE) { /* The ARB_multi_bind spec says: * * "An INVALID_OPERATION error is generated if the internal @@ -586,7 +610,7 @@ _mesa_BindImageTextures(GLuint first, GLsizei count, const GLuint *textures) "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), + _mesa_lookup_enum_by_nr(tex_format), i, texture); continue; } @@ -597,8 +621,8 @@ _mesa_BindImageTextures(GLuint first, GLsizei count, const GLuint *textures) 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->Format = tex_format; + u->_ActualFormat = _mesa_get_shader_image_format(tex_format); u->_Valid = validate_image_unit(ctx, u); } else { /* Unbind the texture from the unit */ diff --git a/mesalib/src/mesa/main/shaderimage.h b/mesalib/src/mesa/main/shaderimage.h index 733ac7747..33d8a1eff 100644 --- a/mesalib/src/mesa/main/shaderimage.h +++ b/mesalib/src/mesa/main/shaderimage.h @@ -28,10 +28,27 @@ #define SHADERIMAGE_H #include "glheader.h" +#include "formats.h" + +#ifdef __cplusplus +extern "C" { +#endif struct gl_context; /** + * Get the matching mesa_format for a shader image format GL enum. + */ +mesa_format +_mesa_get_shader_image_format(GLenum format); + +/** + * Initialize a context's shader image units to the default state. + */ +void +_mesa_init_image_units(struct gl_context *ctx); + +/** * Recalculate the \c _Valid flag of a context's shader image units. * * To be called when the state of any texture bound to an image unit @@ -51,4 +68,8 @@ _mesa_BindImageTextures(GLuint first, GLsizei count, const GLuint *textures); void GLAPIENTRY _mesa_MemoryBarrier(GLbitfield barriers); +#ifdef __cplusplus +} +#endif + #endif diff --git a/mesalib/src/mesa/main/state.c b/mesalib/src/mesa/main/state.c index cc84c6148..2657c532f 100644 --- a/mesalib/src/mesa/main/state.c +++ b/mesalib/src/mesa/main/state.c @@ -101,9 +101,12 @@ update_program(struct gl_context *ctx) ctx->_Shader->CurrentProgram[MESA_SHADER_GEOMETRY]; struct gl_shader_program *fsProg = ctx->_Shader->CurrentProgram[MESA_SHADER_FRAGMENT]; + const struct gl_shader_program *csProg = + ctx->_Shader->CurrentProgram[MESA_SHADER_COMPUTE]; const struct gl_vertex_program *prevVP = ctx->VertexProgram._Current; const struct gl_fragment_program *prevFP = ctx->FragmentProgram._Current; const struct gl_geometry_program *prevGP = ctx->GeometryProgram._Current; + const struct gl_compute_program *prevCP = ctx->ComputeProgram._Current; GLbitfield new_state = 0x0; /* @@ -199,6 +202,16 @@ update_program(struct gl_context *ctx) _mesa_reference_vertprog(ctx, &ctx->VertexProgram._Current, NULL); } + if (csProg && csProg->LinkStatus + && csProg->_LinkedShaders[MESA_SHADER_COMPUTE]) { + /* Use GLSL compute shader */ + _mesa_reference_compprog(ctx, &ctx->ComputeProgram._Current, + gl_compute_program(csProg->_LinkedShaders[MESA_SHADER_COMPUTE]->Program)); + } else { + /* no compute program */ + _mesa_reference_compprog(ctx, &ctx->ComputeProgram._Current, NULL); + } + /* Let the driver know what's happening: */ if (ctx->FragmentProgram._Current != prevFP) { @@ -225,6 +238,14 @@ update_program(struct gl_context *ctx) } } + if (ctx->ComputeProgram._Current != prevCP) { + new_state |= _NEW_PROGRAM; + if (ctx->Driver.BindProgram) { + ctx->Driver.BindProgram(ctx, GL_COMPUTE_PROGRAM_NV, + (struct gl_program *) ctx->ComputeProgram._Current); + } + } + return new_state; } @@ -368,10 +389,10 @@ _mesa_update_state_locked( struct gl_context *ctx ) update_frontbit( ctx ); if (new_state & _NEW_BUFFERS) - _mesa_update_framebuffer(ctx); + _mesa_update_framebuffer(ctx, ctx->ReadBuffer, ctx->DrawBuffer); if (new_state & (_NEW_SCISSOR | _NEW_BUFFERS | _NEW_VIEWPORT)) - _mesa_update_draw_buffer_bounds( ctx ); + _mesa_update_draw_buffer_bounds(ctx, ctx->DrawBuffer); if (new_state & _NEW_LIGHT) _mesa_update_lighting( ctx ); diff --git a/mesalib/src/mesa/main/texenv.c b/mesalib/src/mesa/main/texenv.c index ec521e6c6..3edafc0f7 100644 --- a/mesalib/src/mesa/main/texenv.c +++ b/mesalib/src/mesa/main/texenv.c @@ -646,7 +646,7 @@ _mesa_GetTexEnvfv( GLenum target, GLenum pname, GLfloat *params ) if (pname == GL_TEXTURE_ENV_COLOR) { if(ctx->NewState & (_NEW_BUFFERS | _NEW_FRAG_CLAMP)) _mesa_update_state(ctx); - if (_mesa_get_clamp_fragment_color(ctx)) + if (_mesa_get_clamp_fragment_color(ctx, ctx->DrawBuffer)) COPY_4FV( params, texUnit->EnvColor ); else COPY_4FV( params, texUnit->EnvColorUnclamped ); diff --git a/mesalib/src/mesa/main/texgetimage.c b/mesalib/src/mesa/main/texgetimage.c index 92b4d6795..f582a7f78 100644 --- a/mesalib/src/mesa/main/texgetimage.c +++ b/mesalib/src/mesa/main/texgetimage.c @@ -1108,6 +1108,13 @@ _mesa_GetTextureImage(GLuint texture, GLint level, GLenum format, GLenum err; GET_CURRENT_CONTEXT(ctx); + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetTextureImage(GL_ARB_direct_state_access " + "is not supported)"); + return; + } + /* * This has been moved here because a format/type mismatch can cause a NULL * texImage object, which in turn causes the mismatch error to be @@ -1344,6 +1351,13 @@ _mesa_GetCompressedTextureImage(GLuint texture, GLint level, GLint image_stride; GET_CURRENT_CONTEXT(ctx); + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetCompressedTextureImage(GL_ARB_direct_state_access " + "is not supported)"); + return; + } + texObj = _mesa_lookup_texture_err(ctx, texture, "glGetCompressedTextureImage"); if (!texObj) diff --git a/mesalib/src/mesa/main/teximage.c b/mesalib/src/mesa/main/teximage.c index 7bc1da7f8..7616fd7ce 100644 --- a/mesalib/src/mesa/main/teximage.c +++ b/mesalib/src/mesa/main/teximage.c @@ -3624,6 +3624,13 @@ texturesubimage(struct gl_context *ctx, GLuint dims, _mesa_lookup_enum_by_nr(format), _mesa_lookup_enum_by_nr(type), pixels); + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glTextureSubImage%uD(GL_ARB_direct_state_access " + "is not supported)", dims); + return; + } + /* Get the texture object by Name. */ texObj = _mesa_lookup_texture(ctx, texture); if (!texObj) { @@ -4183,6 +4190,12 @@ _mesa_CopyTextureSubImage1D(GLuint texture, GLint level, const char *self = "glCopyTextureSubImage1D"; GET_CURRENT_CONTEXT(ctx); + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(GL_ARB_direct_state_access is not supported)", self); + return; + } + texObj = _mesa_lookup_texture_err(ctx, texture, self); if (!texObj) return; @@ -4207,6 +4220,12 @@ _mesa_CopyTextureSubImage2D(GLuint texture, GLint level, const char *self = "glCopyTextureSubImage2D"; GET_CURRENT_CONTEXT(ctx); + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(GL_ARB_direct_state_access is not supported)", self); + return; + } + texObj = _mesa_lookup_texture_err(ctx, texture, self); if (!texObj) return; @@ -4234,6 +4253,12 @@ _mesa_CopyTextureSubImage3D(GLuint texture, GLint level, const char *self = "glCopyTextureSubImage3D"; GET_CURRENT_CONTEXT(ctx); + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(GL_ARB_direct_state_access is not supported)", self); + return; + } + texObj = _mesa_lookup_texture_err(ctx, texture, self); if (!texObj) return; @@ -4829,6 +4854,13 @@ _mesa_CompressedTextureSubImage1D(GLuint texture, GLint level, GLint xoffset, GET_CURRENT_CONTEXT(ctx); + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glCompressedTextureSubImage1D(GL_ARB_direct_state_access " + "is not supported)"); + return; + } + texObj = _mesa_lookup_texture_err(ctx, texture, "glCompressedTextureSubImage1D"); if (!texObj) @@ -4907,6 +4939,13 @@ _mesa_CompressedTextureSubImage2D(GLuint texture, GLint level, GLint xoffset, GET_CURRENT_CONTEXT(ctx); + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glCompressedTextureSubImage2D(GL_ARB_direct_state_access " + "is not supported)"); + return; + } + texObj = _mesa_lookup_texture_err(ctx, texture, "glCompressedTextureSubImage2D"); if (!texObj) @@ -4985,6 +5024,13 @@ _mesa_CompressedTextureSubImage3D(GLuint texture, GLint level, GLint xoffset, GET_CURRENT_CONTEXT(ctx); + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glCompressedTextureSubImage3D(GL_ARB_direct_state_access " + "is not supported)"); + return; + } + texObj = _mesa_lookup_texture_err(ctx, texture, "glCompressedTextureSubImage3D"); if (!texObj) @@ -5469,6 +5515,13 @@ _mesa_TextureBuffer(GLuint texture, GLenum internalFormat, GLuint buffer) GET_CURRENT_CONTEXT(ctx); + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glTextureBuffer(GL_ARB_direct_state_access " + "is not supported)"); + return; + } + if (buffer) { bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, "glTextureBuffer"); if (!bufObj) @@ -5497,6 +5550,13 @@ _mesa_TextureBufferRange(GLuint texture, GLenum internalFormat, GLuint buffer, GET_CURRENT_CONTEXT(ctx); + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glTextureBufferRange(GL_ARB_direct_state_access " + "is not supported)"); + return; + } + if (buffer) { bufObj = _mesa_lookup_bufferobj_err(ctx, buffer, "glTextureBufferRange"); @@ -5801,6 +5861,13 @@ _mesa_TextureStorage2DMultisample(GLuint texture, GLsizei samples, struct gl_texture_object *texObj; GET_CURRENT_CONTEXT(ctx); + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glTextureStorage2DMultisample(GL_ARB_direct_state_access " + "is not supported)"); + return; + } + texObj = _mesa_lookup_texture_err(ctx, texture, "glTextureStorage2DMultisample"); if (!texObj) @@ -5821,6 +5888,13 @@ _mesa_TextureStorage3DMultisample(GLuint texture, GLsizei samples, struct gl_texture_object *texObj; GET_CURRENT_CONTEXT(ctx); + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glTextureStorage3DMultisample(GL_ARB_direct_state_access " + "is not supported)"); + return; + } + /* Get the texture object by Name. */ texObj = _mesa_lookup_texture_err(ctx, texture, "glTextureStorage3DMultisample"); diff --git a/mesalib/src/mesa/main/texobj.c b/mesalib/src/mesa/main/texobj.c index c563f1e74..d51e6954b 100644 --- a/mesalib/src/mesa/main/texobj.c +++ b/mesalib/src/mesa/main/texobj.c @@ -1317,6 +1317,13 @@ _mesa_CreateTextures(GLenum target, GLsizei n, GLuint *textures) GLint targetIndex; GET_CURRENT_CONTEXT(ctx); + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glCreateTextures(GL_ARB_direct_state_access " + "is not supported)"); + return; + } + /* * The 4.5 core profile spec (30.10.2014) doesn't specify what * glCreateTextures should do with invalid targets, which was probably an @@ -1808,6 +1815,13 @@ _mesa_BindTextureUnit(GLuint unit, GLuint texture) _mesa_debug(ctx, "glBindTextureUnit %s %d\n", _mesa_lookup_enum_by_nr(GL_TEXTURE0+unit), (GLint) texture); + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glBindTextureUnit(GL_ARB_direct_state_access " + "is not supported)"); + return; + } + /* Section 8.1 (Texture Objects) of the OpenGL 4.5 core profile spec * (20141030) says: * "When texture is zero, each of the targets enumerated at the diff --git a/mesalib/src/mesa/main/texparam.c b/mesalib/src/mesa/main/texparam.c index b5d42d304..1fa583002 100644 --- a/mesalib/src/mesa/main/texparam.c +++ b/mesalib/src/mesa/main/texparam.c @@ -1108,6 +1108,13 @@ _mesa_TextureParameterfv(GLuint texture, GLenum pname, const GLfloat *params) struct gl_texture_object *texObj; GET_CURRENT_CONTEXT(ctx); + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glTextureParameterfv(GL_ARB_direct_state_access " + "is not supported)"); + return; + } + texObj = get_texobj_by_name(ctx, texture, GL_FALSE); if (!texObj) { /* User passed a non-generated name. */ @@ -1124,6 +1131,13 @@ _mesa_TextureParameterf(GLuint texture, GLenum pname, GLfloat param) struct gl_texture_object *texObj; GET_CURRENT_CONTEXT(ctx); + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glTextureParameterf(GL_ARB_direct_state_access " + "is not supported)"); + return; + } + texObj = get_texobj_by_name(ctx, texture, GL_FALSE); if (!texObj) { /* User passed a non-generated name. */ @@ -1140,6 +1154,13 @@ _mesa_TextureParameteri(GLuint texture, GLenum pname, GLint param) struct gl_texture_object *texObj; GET_CURRENT_CONTEXT(ctx); + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glTextureParameteri(GL_ARB_direct_state_access " + "is not supported)"); + return; + } + texObj = get_texobj_by_name(ctx, texture, GL_FALSE); if (!texObj) { /* User passed a non-generated name. */ @@ -1157,6 +1178,13 @@ _mesa_TextureParameteriv(GLuint texture, GLenum pname, struct gl_texture_object *texObj; GET_CURRENT_CONTEXT(ctx); + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glTextureParameteriv(GL_ARB_direct_state_access " + "is not supported)"); + return; + } + texObj = get_texobj_by_name(ctx, texture, GL_FALSE); if (!texObj) { /* User passed a non-generated name. */ @@ -1174,6 +1202,13 @@ _mesa_TextureParameterIiv(GLuint texture, GLenum pname, const GLint *params) struct gl_texture_object *texObj; GET_CURRENT_CONTEXT(ctx); + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glTextureParameterIiv(GL_ARB_direct_state_access " + "is not supported)"); + return; + } + texObj = get_texobj_by_name(ctx, texture, GL_FALSE); if (!texObj) { /* User passed a non-generated name. */ @@ -1191,6 +1226,13 @@ _mesa_TextureParameterIuiv(GLuint texture, GLenum pname, const GLuint *params) struct gl_texture_object *texObj; GET_CURRENT_CONTEXT(ctx); + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glTextureParameterIuiv(GL_ARB_direct_state_access " + "is not supported)"); + return; + } + texObj = get_texobj_by_name(ctx, texture, GL_FALSE); if (!texObj) { /* User passed a non-generated name. */ @@ -1650,6 +1692,13 @@ _mesa_GetTextureLevelParameterfv(GLuint texture, GLint level, GLint iparam; GET_CURRENT_CONTEXT(ctx); + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetTextureLevelParameterfv(GL_ARB_direct_state_access " + "is not supported)"); + return; + } + texObj = _mesa_lookup_texture_err(ctx, texture, "glGetTextureLevelParameterfv"); if (!texObj) @@ -1668,6 +1717,13 @@ _mesa_GetTextureLevelParameteriv(GLuint texture, GLint level, struct gl_texture_object *texObj; GET_CURRENT_CONTEXT(ctx); + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetTextureLevelParameteriv(GL_ARB_direct_state_access " + "is not supported)"); + return; + } + texObj = _mesa_lookup_texture_err(ctx, texture, "glGetTextureLevelParameteriv"); if (!texObj) @@ -1709,7 +1765,7 @@ get_tex_parameterfv(struct gl_context *ctx, if (ctx->NewState & (_NEW_BUFFERS | _NEW_FRAG_CLAMP)) _mesa_update_state_locked(ctx); - if (_mesa_get_clamp_fragment_color(ctx)) { + if (_mesa_get_clamp_fragment_color(ctx, ctx->DrawBuffer)) { params[0] = CLAMP(obj->Sampler.BorderColor.f[0], 0.0F, 1.0F); params[1] = CLAMP(obj->Sampler.BorderColor.f[1], 0.0F, 1.0F); params[2] = CLAMP(obj->Sampler.BorderColor.f[2], 0.0F, 1.0F); @@ -2227,6 +2283,13 @@ _mesa_GetTextureParameterfv(GLuint texture, GLenum pname, GLfloat *params) struct gl_texture_object *obj; GET_CURRENT_CONTEXT(ctx); + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetTextureParameterfv(GL_ARB_direct_state_access " + "is not supported)"); + return; + } + obj = get_texobj_by_name(ctx, texture, GL_TRUE); if (!obj) { /* User passed a non-generated name. */ @@ -2244,6 +2307,13 @@ _mesa_GetTextureParameteriv(GLuint texture, GLenum pname, GLint *params) struct gl_texture_object *obj; GET_CURRENT_CONTEXT(ctx); + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetTextureParameteriv(GL_ARB_direct_state_access " + "is not supported)"); + return; + } + obj = get_texobj_by_name(ctx, texture, GL_TRUE); if (!obj) { /* User passed a non-generated name. */ @@ -2261,6 +2331,13 @@ _mesa_GetTextureParameterIiv(GLuint texture, GLenum pname, GLint *params) struct gl_texture_object *texObj; GET_CURRENT_CONTEXT(ctx); + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetTextureParameterIiv(GL_ARB_direct_state_access " + "is not supported)"); + return; + } + texObj = get_texobj_by_name(ctx, texture, GL_TRUE); if (!texObj) { /* User passed a non-generated name. */ @@ -2279,6 +2356,13 @@ _mesa_GetTextureParameterIuiv(GLuint texture, GLenum pname, GLuint *params) struct gl_texture_object *texObj; GET_CURRENT_CONTEXT(ctx); + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetTextureParameterIuiv(GL_ARB_direct_state_access " + "is not supported)"); + return; + } + texObj = get_texobj_by_name(ctx, texture, GL_TRUE); if (!texObj) { /* User passed a non-generated name. */ diff --git a/mesalib/src/mesa/main/texstorage.c b/mesalib/src/mesa/main/texstorage.c index 53cb2c091..dee74a825 100644 --- a/mesalib/src/mesa/main/texstorage.c +++ b/mesalib/src/mesa/main/texstorage.c @@ -507,6 +507,13 @@ texturestorage(GLuint dims, GLuint texture, GLsizei levels, _mesa_lookup_enum_by_nr(internalformat), width, height, depth); + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glTextureStorage%uD(GL_ARB_direct_state_access " + "is not supported)", dims); + return; + } + /* Check the format to make sure it is sized. */ if (!_mesa_is_legal_tex_storage_format(ctx, internalformat)) { _mesa_error(ctx, GL_INVALID_ENUM, diff --git a/mesalib/src/mesa/main/transformfeedback.c b/mesalib/src/mesa/main/transformfeedback.c index 103011ce5..642fa9647 100644 --- a/mesalib/src/mesa/main/transformfeedback.c +++ b/mesalib/src/mesa/main/transformfeedback.c @@ -706,6 +706,13 @@ _mesa_TransformFeedbackBufferBase(GLuint xfb, GLuint index, GLuint buffer) struct gl_transform_feedback_object *obj; struct gl_buffer_object *bufObj; + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glTransformFeedbackBufferBase(GL_ARB_direct_state_access " + "is not supported)"); + return; + } + obj = lookup_transform_feedback_object_err(ctx, xfb, "glTransformFeedbackBufferBase"); if(!obj) { @@ -729,6 +736,13 @@ _mesa_TransformFeedbackBufferRange(GLuint xfb, GLuint index, GLuint buffer, struct gl_transform_feedback_object *obj; struct gl_buffer_object *bufObj; + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glTransformFeedbackBufferRange(GL_ARB_direct_state_access " + "is not supported)"); + return; + } + obj = lookup_transform_feedback_object_err(ctx, xfb, "glTransformFeedbackBufferRange"); if(!obj) { @@ -1045,6 +1059,13 @@ _mesa_CreateTransformFeedbacks(GLsizei n, GLuint *names) { GET_CURRENT_CONTEXT(ctx); + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glCreateTransformFeedbacks(GL_ARB_direct_state_access " + "is not supported)"); + return; + } + create_transform_feedbacks(ctx, n, names, true); } @@ -1215,6 +1236,13 @@ _mesa_GetTransformFeedbackiv(GLuint xfb, GLenum pname, GLint *param) struct gl_transform_feedback_object *obj; GET_CURRENT_CONTEXT(ctx); + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetTransformFeedbackiv(GL_ARB_direct_state_access " + "is not supported)"); + return; + } + obj = lookup_transform_feedback_object_err(ctx, xfb, "glGetTransformFeedbackiv"); if(!obj) { @@ -1241,6 +1269,13 @@ _mesa_GetTransformFeedbacki_v(GLuint xfb, GLenum pname, GLuint index, struct gl_transform_feedback_object *obj; GET_CURRENT_CONTEXT(ctx); + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetTransformFeedbacki_v(GL_ARB_direct_state_access " + "is not supported)"); + return; + } + obj = lookup_transform_feedback_object_err(ctx, xfb, "glGetTransformFeedbacki_v"); if(!obj) { @@ -1270,6 +1305,13 @@ _mesa_GetTransformFeedbacki64_v(GLuint xfb, GLenum pname, GLuint index, struct gl_transform_feedback_object *obj; GET_CURRENT_CONTEXT(ctx); + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetTransformFeedbacki64_v(GL_ARB_direct_state_access " + "is not supported)"); + return; + } + obj = lookup_transform_feedback_object_err(ctx, xfb, "glGetTransformFeedbacki64_v"); if(!obj) { diff --git a/mesalib/src/mesa/main/uniform_query.cpp b/mesalib/src/mesa/main/uniform_query.cpp index 3e857ed10..728bd1bac 100644 --- a/mesalib/src/mesa/main/uniform_query.cpp +++ b/mesalib/src/mesa/main/uniform_query.cpp @@ -347,7 +347,8 @@ _mesa_get_uniform(struct gl_context *ctx, GLuint program, GLint location, && (uni->type->base_type == GLSL_TYPE_INT || uni->type->base_type == GLSL_TYPE_UINT - || uni->type->base_type == GLSL_TYPE_SAMPLER))) { + || uni->type->base_type == GLSL_TYPE_SAMPLER + || uni->type->base_type == GLSL_TYPE_IMAGE))) { memcpy(paramsOut, src, bytes); } else { union gl_constant_value *const dst = @@ -366,6 +367,7 @@ _mesa_get_uniform(struct gl_context *ctx, GLuint program, GLint location, break; case GLSL_TYPE_INT: case GLSL_TYPE_SAMPLER: + case GLSL_TYPE_IMAGE: dst[i].f = (float) src[i].i; break; case GLSL_TYPE_BOOL: diff --git a/mesalib/src/mesa/main/varray.c b/mesalib/src/mesa/main/varray.c index 42e7f89b2..da6bbce52 100644 --- a/mesalib/src/mesa/main/varray.c +++ b/mesalib/src/mesa/main/varray.c @@ -66,6 +66,21 @@ #define UNSIGNED_INT_10F_11F_11F_REV_BIT (1 << 14) #define ALL_TYPE_BITS ((1 << 15) - 1) +#define ATTRIB_FORMAT_TYPES_MASK (BYTE_BIT | UNSIGNED_BYTE_BIT | \ + SHORT_BIT | UNSIGNED_SHORT_BIT | \ + INT_BIT | UNSIGNED_INT_BIT | \ + HALF_BIT | FLOAT_BIT | DOUBLE_BIT | \ + FIXED_GL_BIT | \ + UNSIGNED_INT_2_10_10_10_REV_BIT | \ + INT_2_10_10_10_REV_BIT | \ + UNSIGNED_INT_10F_11F_11F_REV_BIT) + +#define ATTRIB_IFORMAT_TYPES_MASK (BYTE_BIT | UNSIGNED_BYTE_BIT | \ + SHORT_BIT | UNSIGNED_SHORT_BIT | \ + INT_BIT | UNSIGNED_INT_BIT) + +#define ATTRIB_LFORMAT_TYPES_MASK DOUBLE_BIT + /** Convert GL datatype enum into a <type>_BIT value seen above */ static GLbitfield @@ -113,10 +128,11 @@ type_to_bit(const struct gl_context *ctx, GLenum type) * Sets the VertexBinding field in the vertex attribute given by attribIndex. */ static void -vertex_attrib_binding(struct gl_context *ctx, GLuint attribIndex, +vertex_attrib_binding(struct gl_context *ctx, + struct gl_vertex_array_object *vao, + GLuint attribIndex, GLuint bindingIndex) { - struct gl_vertex_array_object *vao = ctx->Array.VAO; struct gl_vertex_attrib_array *array = &vao->VertexAttrib[attribIndex]; if (array->VertexBinding != bindingIndex) { @@ -139,11 +155,12 @@ vertex_attrib_binding(struct gl_context *ctx, GLuint attribIndex, * and sets the Offset and Stride fields. */ static void -bind_vertex_buffer(struct gl_context *ctx, GLuint index, +bind_vertex_buffer(struct gl_context *ctx, + struct gl_vertex_array_object *vao, + GLuint index, struct gl_buffer_object *vbo, GLintptr offset, GLsizei stride) { - struct gl_vertex_array_object *vao = ctx->Array.VAO; struct gl_vertex_buffer_binding *binding = &vao->VertexBinding[index]; if (binding->BufferObj != vbo || @@ -167,10 +184,11 @@ bind_vertex_buffer(struct gl_context *ctx, GLuint index, * given by bindingIndex. */ static void -vertex_binding_divisor(struct gl_context *ctx, GLuint bindingIndex, +vertex_binding_divisor(struct gl_context *ctx, + struct gl_vertex_array_object *vao, + GLuint bindingIndex, GLuint divisor) { - struct gl_vertex_array_object *vao = ctx->Array.VAO; struct gl_vertex_buffer_binding *binding = &vao->VertexBinding[bindingIndex]; @@ -243,15 +261,17 @@ get_legal_types_mask(const struct gl_context *ctx) * \param type Datatype of each component (GL_FLOAT, GL_INT, etc) * \param normalized Whether integer types are converted to floats in [-1, 1] * \param integer Integer-valued values (will not be normalized to [-1, 1]) + * \param doubles Double values not reduced to floats * \param relativeOffset Offset of the first element relative to the binding offset. */ static bool update_array_format(struct gl_context *ctx, const char *func, + struct gl_vertex_array_object *vao, GLuint attrib, GLbitfield legalTypesMask, GLint sizeMin, GLint sizeMax, GLint size, GLenum type, - GLboolean normalized, GLboolean integer, + GLboolean normalized, GLboolean integer, GLboolean doubles, GLuint relativeOffset) { struct gl_vertex_attrib_array *array; @@ -362,16 +382,17 @@ update_array_format(struct gl_context *ctx, elementSize = _mesa_bytes_per_vertex_attrib(size, type); assert(elementSize != -1); - array = &ctx->Array.VAO->VertexAttrib[attrib]; + array = &vao->VertexAttrib[attrib]; array->Size = size; array->Type = type; array->Format = format; array->Normalized = normalized; array->Integer = integer; + array->Doubles = doubles; array->RelativeOffset = relativeOffset; array->_ElementSize = elementSize; - ctx->Array.VAO->NewArrays |= VERT_BIT(attrib); + vao->NewArrays |= VERT_BIT(attrib); ctx->NewState |= _NEW_ARRAY; return true; @@ -392,6 +413,7 @@ update_array_format(struct gl_context *ctx, * \param stride stride between elements, in elements * \param normalized are integer types converted to floats in [-1, 1]? * \param integer integer-valued values (will not be normalized to [-1,1]) + * \param doubles Double values not reduced to floats * \param ptr the address (or offset inside VBO) of the array data */ static void @@ -400,7 +422,7 @@ update_array(struct gl_context *ctx, GLuint attrib, GLbitfield legalTypesMask, GLint sizeMin, GLint sizeMax, GLint size, GLenum type, GLsizei stride, - GLboolean normalized, GLboolean integer, + GLboolean normalized, GLboolean integer, GLboolean doubles, const GLvoid *ptr) { struct gl_vertex_attrib_array *array; @@ -453,13 +475,14 @@ update_array(struct gl_context *ctx, return; } - if (!update_array_format(ctx, func, attrib, legalTypesMask, sizeMin, - sizeMax, size, type, normalized, integer, 0)) { + if (!update_array_format(ctx, func, ctx->Array.VAO, attrib, + legalTypesMask, sizeMin, sizeMax, + size, type, normalized, integer, doubles, 0)) { return; } /* Reset the vertex attrib binding */ - vertex_attrib_binding(ctx, attrib, attrib); + vertex_attrib_binding(ctx, ctx->Array.VAO, attrib, attrib); /* The Stride and Ptr fields are not set by update_array_format() */ array = &ctx->Array.VAO->VertexAttrib[attrib]; @@ -468,7 +491,7 @@ update_array(struct gl_context *ctx, /* Update the vertex buffer binding */ effectiveStride = stride != 0 ? stride : array->_ElementSize; - bind_vertex_buffer(ctx, attrib, ctx->Array.ArrayBufferObj, + bind_vertex_buffer(ctx, ctx->Array.VAO, attrib, ctx->Array.ArrayBufferObj, (GLintptr) ptr, effectiveStride); } @@ -488,7 +511,7 @@ _mesa_VertexPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr) update_array(ctx, "glVertexPointer", VERT_ATTRIB_POS, legalTypes, 2, 4, - size, type, stride, GL_FALSE, GL_FALSE, ptr); + size, type, stride, GL_FALSE, GL_FALSE, GL_FALSE, ptr); } @@ -507,7 +530,7 @@ _mesa_NormalPointer(GLenum type, GLsizei stride, const GLvoid *ptr ) update_array(ctx, "glNormalPointer", VERT_ATTRIB_NORMAL, legalTypes, 3, 3, - 3, type, stride, GL_TRUE, GL_FALSE, ptr); + 3, type, stride, GL_TRUE, GL_FALSE, GL_FALSE, ptr); } @@ -529,7 +552,7 @@ _mesa_ColorPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *ptr) update_array(ctx, "glColorPointer", VERT_ATTRIB_COLOR0, legalTypes, sizeMin, BGRA_OR_4, - size, type, stride, GL_TRUE, GL_FALSE, ptr); + size, type, stride, GL_TRUE, GL_FALSE, GL_FALSE, ptr); } @@ -543,7 +566,7 @@ _mesa_FogCoordPointer(GLenum type, GLsizei stride, const GLvoid *ptr) update_array(ctx, "glFogCoordPointer", VERT_ATTRIB_FOG, legalTypes, 1, 1, - 1, type, stride, GL_FALSE, GL_FALSE, ptr); + 1, type, stride, GL_FALSE, GL_FALSE, GL_FALSE, ptr); } @@ -558,7 +581,7 @@ _mesa_IndexPointer(GLenum type, GLsizei stride, const GLvoid *ptr) update_array(ctx, "glIndexPointer", VERT_ATTRIB_COLOR_INDEX, legalTypes, 1, 1, - 1, type, stride, GL_FALSE, GL_FALSE, ptr); + 1, type, stride, GL_FALSE, GL_FALSE, GL_FALSE, ptr); } @@ -578,7 +601,7 @@ _mesa_SecondaryColorPointer(GLint size, GLenum type, update_array(ctx, "glSecondaryColorPointer", VERT_ATTRIB_COLOR1, legalTypes, 3, BGRA_OR_4, - size, type, stride, GL_TRUE, GL_FALSE, ptr); + size, type, stride, GL_TRUE, GL_FALSE, GL_FALSE, ptr); } @@ -600,7 +623,7 @@ _mesa_TexCoordPointer(GLint size, GLenum type, GLsizei stride, update_array(ctx, "glTexCoordPointer", VERT_ATTRIB_TEX(unit), legalTypes, sizeMin, 4, - size, type, stride, GL_FALSE, GL_FALSE, + size, type, stride, GL_FALSE, GL_FALSE, GL_FALSE, ptr); } @@ -617,7 +640,7 @@ _mesa_EdgeFlagPointer(GLsizei stride, const GLvoid *ptr) update_array(ctx, "glEdgeFlagPointer", VERT_ATTRIB_EDGEFLAG, legalTypes, 1, 1, - 1, GL_UNSIGNED_BYTE, stride, GL_FALSE, integer, ptr); + 1, GL_UNSIGNED_BYTE, stride, GL_FALSE, integer, GL_FALSE, ptr); } @@ -637,7 +660,7 @@ _mesa_PointSizePointerOES(GLenum type, GLsizei stride, const GLvoid *ptr) update_array(ctx, "glPointSizePointer", VERT_ATTRIB_POINT_SIZE, legalTypes, 1, 1, - 1, type, stride, GL_FALSE, GL_FALSE, ptr); + 1, type, stride, GL_FALSE, GL_FALSE, GL_FALSE, ptr); } @@ -668,7 +691,7 @@ _mesa_VertexAttribPointer(GLuint index, GLint size, GLenum type, update_array(ctx, "glVertexAttribPointer", VERT_ATTRIB_GENERIC(index), legalTypes, 1, BGRA_OR_4, - size, type, stride, normalized, GL_FALSE, ptr); + size, type, stride, normalized, GL_FALSE, GL_FALSE, ptr); } @@ -696,24 +719,36 @@ _mesa_VertexAttribIPointer(GLuint index, GLint size, GLenum type, update_array(ctx, "glVertexAttribIPointer", VERT_ATTRIB_GENERIC(index), legalTypes, 1, 4, - size, type, stride, normalized, integer, ptr); + size, type, stride, normalized, integer, GL_FALSE, ptr); } - - void GLAPIENTRY -_mesa_EnableVertexAttribArray(GLuint index) +_mesa_VertexAttribLPointer(GLuint index, GLint size, GLenum type, + GLsizei stride, const GLvoid *ptr) { - struct gl_vertex_array_object *vao; GET_CURRENT_CONTEXT(ctx); - + const GLbitfield legalTypes = (DOUBLE_BIT); if (index >= ctx->Const.Program[MESA_SHADER_VERTEX].MaxAttribs) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glEnableVertexAttribArrayARB(index)"); + _mesa_error(ctx, GL_INVALID_VALUE, "glVertexAttribLPointer(index)"); return; } - vao = ctx->Array.VAO; + update_array(ctx, "glVertexAttribLPointer", VERT_ATTRIB_GENERIC(index), + legalTypes, 1, 4, + size, type, stride, GL_TRUE, GL_FALSE, GL_TRUE, ptr); +} + + +static void +enable_vertex_array_attrib(struct gl_context *ctx, + struct gl_vertex_array_object *vao, + GLuint index, + const char *func) +{ + if (index >= ctx->Const.Program[MESA_SHADER_VERTEX].MaxAttribs) { + _mesa_error(ctx, GL_INVALID_VALUE, "%s(index)", func); + return; + } assert(VERT_ATTRIB_GENERIC(index) < ARRAY_SIZE(vao->VertexAttrib)); @@ -728,18 +763,52 @@ _mesa_EnableVertexAttribArray(GLuint index) void GLAPIENTRY -_mesa_DisableVertexAttribArray(GLuint index) +_mesa_EnableVertexAttribArray(GLuint index) { - struct gl_vertex_array_object *vao; GET_CURRENT_CONTEXT(ctx); + enable_vertex_array_attrib(ctx, ctx->Array.VAO, index, + "glEnableVertexAttribArray"); +} - if (index >= ctx->Const.Program[MESA_SHADER_VERTEX].MaxAttribs) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glDisableVertexAttribArrayARB(index)"); + +void GLAPIENTRY +_mesa_EnableVertexArrayAttrib(GLuint vaobj, GLuint index) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_vertex_array_object *vao; + + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glEnableVertexArrayAttrib(GL_ARB_direct_state_access " + "is not supported"); return; } - vao = ctx->Array.VAO; + /* The ARB_direct_state_access specification says: + * + * "An INVALID_OPERATION error is generated by EnableVertexArrayAttrib + * and DisableVertexArrayAttrib if <vaobj> is not + * [compatibility profile: zero or] the name of an existing vertex + * array object." + */ + vao = _mesa_lookup_vao_err(ctx, vaobj, "glEnableVertexArrayAttrib"); + if (!vao) + return; + + enable_vertex_array_attrib(ctx, vao, index, "glEnableVertexArrayAttrib"); +} + + +static void +disable_vertex_array_attrib(struct gl_context *ctx, + struct gl_vertex_array_object *vao, + GLuint index, + const char *func) +{ + if (index >= ctx->Const.Program[MESA_SHADER_VERTEX].MaxAttribs) { + _mesa_error(ctx, GL_INVALID_VALUE, "%s(index)", func); + return; + } assert(VERT_ATTRIB_GENERIC(index) < ARRAY_SIZE(vao->VertexAttrib)); @@ -753,16 +822,54 @@ _mesa_DisableVertexAttribArray(GLuint index) } +void GLAPIENTRY +_mesa_DisableVertexAttribArray(GLuint index) +{ + GET_CURRENT_CONTEXT(ctx); + disable_vertex_array_attrib(ctx, ctx->Array.VAO, index, + "glDisableVertexAttribArray"); +} + + +void GLAPIENTRY +_mesa_DisableVertexArrayAttrib(GLuint vaobj, GLuint index) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_vertex_array_object *vao; + + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glDisableVertexArrayAttrib(GL_ARB_direct_state_access " + "is not supported"); + return; + } + + /* The ARB_direct_state_access specification says: + * + * "An INVALID_OPERATION error is generated by EnableVertexArrayAttrib + * and DisableVertexArrayAttrib if <vaobj> is not + * [compatibility profile: zero or] the name of an existing vertex + * array object." + */ + vao = _mesa_lookup_vao_err(ctx, vaobj, "glDisableVertexArrayAttrib"); + if (!vao) + return; + + disable_vertex_array_attrib(ctx, vao, index, "glDisableVertexArrayAttrib"); +} + + /** * Return info for a vertex attribute array (no alias with legacy * vertex attributes (pos, normal, color, etc)). This function does * not handle the 4-element GL_CURRENT_VERTEX_ATTRIB_ARB query. */ static GLuint -get_vertex_array_attrib(struct gl_context *ctx, GLuint index, GLenum pname, - const char *caller) +get_vertex_array_attrib(struct gl_context *ctx, + const struct gl_vertex_array_object *vao, + GLuint index, GLenum pname, + const char *caller) { - const struct gl_vertex_array_object *vao = ctx->Array.VAO; const struct gl_vertex_attrib_array *array; if (index >= ctx->Const.Program[MESA_SHADER_VERTEX].MaxAttribs) { @@ -794,6 +901,11 @@ get_vertex_array_attrib(struct gl_context *ctx, GLuint index, GLenum pname, return array->Integer; } goto error; + case GL_VERTEX_ATTRIB_ARRAY_LONG: + if (_mesa_is_desktop_gl(ctx)) { + return array->Doubles; + } + goto error; case GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ARB: if ((_mesa_is_desktop_gl(ctx) && ctx->Extensions.ARB_instanced_arrays) || _mesa_is_gles3(ctx)) { @@ -853,7 +965,8 @@ _mesa_GetVertexAttribfv(GLuint index, GLenum pname, GLfloat *params) } } else { - params[0] = (GLfloat) get_vertex_array_attrib(ctx, index, pname, + params[0] = (GLfloat) get_vertex_array_attrib(ctx, ctx->Array.VAO, + index, pname, "glGetVertexAttribfv"); } } @@ -874,11 +987,32 @@ _mesa_GetVertexAttribdv(GLuint index, GLenum pname, GLdouble *params) } } else { - params[0] = (GLdouble) get_vertex_array_attrib(ctx, index, pname, + params[0] = (GLdouble) get_vertex_array_attrib(ctx, ctx->Array.VAO, + index, pname, "glGetVertexAttribdv"); } } +void GLAPIENTRY +_mesa_GetVertexAttribLdv(GLuint index, GLenum pname, GLdouble *params) +{ + GET_CURRENT_CONTEXT(ctx); + + if (pname == GL_CURRENT_VERTEX_ATTRIB_ARB) { + const GLdouble *v = (const GLdouble *)get_current_attrib(ctx, index, "glGetVertexAttribLdv"); + if (v != NULL) { + params[0] = v[0]; + params[1] = v[1]; + params[2] = v[2]; + params[3] = v[3]; + } + } + else { + params[0] = (GLdouble) get_vertex_array_attrib(ctx, ctx->Array.VAO, + index, pname, + "glGetVertexAttribLdv"); + } +} void GLAPIENTRY _mesa_GetVertexAttribiv(GLuint index, GLenum pname, GLint *params) @@ -896,7 +1030,8 @@ _mesa_GetVertexAttribiv(GLuint index, GLenum pname, GLint *params) } } else { - params[0] = (GLint) get_vertex_array_attrib(ctx, index, pname, + params[0] = (GLint) get_vertex_array_attrib(ctx, ctx->Array.VAO, + index, pname, "glGetVertexAttribiv"); } } @@ -916,7 +1051,8 @@ _mesa_GetVertexAttribIiv(GLuint index, GLenum pname, GLint *params) } } else { - params[0] = (GLint) get_vertex_array_attrib(ctx, index, pname, + params[0] = (GLint) get_vertex_array_attrib(ctx, ctx->Array.VAO, + index, pname, "glGetVertexAttribIiv"); } } @@ -936,7 +1072,8 @@ _mesa_GetVertexAttribIuiv(GLuint index, GLenum pname, GLuint *params) } } else { - params[0] = get_vertex_array_attrib(ctx, index, pname, + params[0] = get_vertex_array_attrib(ctx, ctx->Array.VAO, + index, pname, "glGetVertexAttribIuiv"); } } @@ -963,6 +1100,138 @@ _mesa_GetVertexAttribPointerv(GLuint index, GLenum pname, GLvoid **pointer) } +/** ARB_direct_state_access */ +void GLAPIENTRY +_mesa_GetVertexArrayIndexediv(GLuint vaobj, GLuint index, + GLenum pname, GLint *params) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_vertex_array_object *vao; + + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetVertexArrayIndexediv(GL_ARB_direct_state_access " + "is not supported"); + return; + } + + /* The ARB_direct_state_access specification says: + * + * "An INVALID_OPERATION error is generated if <vaobj> is not + * [compatibility profile: zero or] the name of an existing + * vertex array object." + */ + vao = _mesa_lookup_vao_err(ctx, vaobj, "glGetVertexArrayIndexediv"); + if (!vao) + return; + + /* The ARB_direct_state_access specification says: + * + * "For GetVertexArrayIndexediv, <pname> must be one of + * VERTEX_ATTRIB_ARRAY_ENABLED, VERTEX_ATTRIB_ARRAY_SIZE, + * VERTEX_ATTRIB_ARRAY_STRIDE, VERTEX_ATTRIB_ARRAY_TYPE, + * VERTEX_ATTRIB_ARRAY_NORMALIZED, VERTEX_ATTRIB_ARRAY_INTEGER, + * VERTEX_ATTRIB_ARRAY_LONG, VERTEX_ATTRIB_ARRAY_DIVISOR, or + * VERTEX_ATTRIB_RELATIVE_OFFSET." + * + * and: + * + * "Add GetVertexArrayIndexediv in 'Get Command' for + * VERTEX_ATTRIB_ARRAY_BUFFER_BINDING + * VERTEX_ATTRIB_BINDING, + * VERTEX_ATTRIB_RELATIVE_OFFSET, + * VERTEX_BINDING_OFFSET, and + * VERTEX_BINDING_STRIDE states" + * + * The only parameter name common to both lists is + * VERTEX_ATTRIB_RELATIVE_OFFSET. Also note that VERTEX_BINDING_BUFFER + * and VERTEX_BINDING_DIVISOR are missing from both lists. It seems + * pretty clear however that the intent is that it should be possible + * to query all vertex attrib and binding states that can be set with + * a DSA function. + */ + switch (pname) { + case GL_VERTEX_BINDING_OFFSET: + params[0] = vao->VertexBinding[VERT_ATTRIB_GENERIC(index)].Offset; + break; + case GL_VERTEX_BINDING_STRIDE: + params[0] = vao->VertexBinding[VERT_ATTRIB_GENERIC(index)].Stride; + break; + case GL_VERTEX_BINDING_DIVISOR: + params[0] = vao->VertexBinding[VERT_ATTRIB_GENERIC(index)].InstanceDivisor; + break; + case GL_VERTEX_BINDING_BUFFER: + params[0] = vao->VertexBinding[VERT_ATTRIB_GENERIC(index)].BufferObj->Name; + break; + default: + params[0] = get_vertex_array_attrib(ctx, vao, index, pname, + "glGetVertexArrayIndexediv"); + break; + } +} + + +void GLAPIENTRY +_mesa_GetVertexArrayIndexed64iv(GLuint vaobj, GLuint index, + GLenum pname, GLint64 *params) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_vertex_array_object *vao; + + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetVertexArrayIndexed64iv(GL_ARB_direct_state_access " + "is not supported"); + return; + } + + + /* The ARB_direct_state_access specification says: + * + * "An INVALID_OPERATION error is generated if <vaobj> is not + * [compatibility profile: zero or] the name of an existing + * vertex array object." + */ + vao = _mesa_lookup_vao_err(ctx, vaobj, "glGetVertexArrayIndexed64iv"); + if (!vao) + return; + + /* The ARB_direct_state_access specification says: + * + * "For GetVertexArrayIndexed64iv, <pname> must be + * VERTEX_BINDING_OFFSET." + * + * and: + * + * "An INVALID_ENUM error is generated if <pname> is not one of + * the valid values listed above for the corresponding command." + */ + if (pname != GL_VERTEX_BINDING_OFFSET) { + _mesa_error(ctx, GL_INVALID_ENUM, "glGetVertexArrayIndexed64iv(" + "pname != GL_VERTEX_BINDING_OFFSET)"); + return; + } + + /* The ARB_direct_state_access specification says: + * + * "An INVALID_VALUE error is generated if <index> is greater than + * or equal to the value of MAX_VERTEX_ATTRIBS." + * + * Since the index refers to a buffer binding in this case, the intended + * limit must be MAX_VERTEX_ATTRIB_BINDINGS. Both limits are currently + * required to be the same, so in practice this doesn't matter. + */ + if (index >= ctx->Const.MaxVertexAttribBindings) { + _mesa_error(ctx, GL_INVALID_VALUE, "glGetVertexArrayIndexed64iv(" + "index %d >= the value of GL_MAX_VERTEX_ATTRIB_BINDINGS (%d))", + index, ctx->Const.MaxVertexAttribBindings); + return; + } + + params[0] = vao->VertexBinding[VERT_ATTRIB_GENERIC(index)].Offset; +} + + void GLAPIENTRY _mesa_VertexPointerEXT(GLint size, GLenum type, GLsizei stride, GLsizei count, const GLvoid *ptr) @@ -1337,6 +1606,7 @@ _mesa_VertexAttribDivisor(GLuint index, GLuint divisor) GET_CURRENT_CONTEXT(ctx); const GLuint genericIndex = VERT_ATTRIB_GENERIC(index); + struct gl_vertex_array_object * const vao = ctx->Array.VAO; if (!ctx->Extensions.ARB_instanced_arrays) { _mesa_error(ctx, GL_INVALID_OPERATION, "glVertexAttribDivisor()"); @@ -1349,7 +1619,7 @@ _mesa_VertexAttribDivisor(GLuint index, GLuint divisor) return; } - assert(genericIndex < ARRAY_SIZE(ctx->Array.VAO->VertexAttrib)); + assert(genericIndex < ARRAY_SIZE(vao->VertexAttrib)); /* The ARB_vertex_attrib_binding spec says: * @@ -1362,8 +1632,8 @@ _mesa_VertexAttribDivisor(GLuint index, GLuint divisor) * VertexAttribBinding(index, index); * VertexBindingDivisor(index, divisor);" */ - vertex_attrib_binding(ctx, genericIndex, genericIndex); - vertex_binding_divisor(ctx, genericIndex, divisor); + vertex_attrib_binding(ctx, vao, genericIndex, genericIndex); + vertex_binding_divisor(ctx, vao, genericIndex, divisor); } @@ -1395,38 +1665,25 @@ _mesa_primitive_restart_index(const struct gl_context *ctx, GLenum ib_type) /** * GL_ARB_vertex_attrib_binding */ -void GLAPIENTRY -_mesa_BindVertexBuffer(GLuint bindingIndex, GLuint buffer, GLintptr offset, - GLsizei stride) +static void +vertex_array_vertex_buffer(struct gl_context *ctx, struct gl_vertex_array_object *vao, + GLuint bindingIndex, GLuint buffer, GLintptr offset, + GLsizei stride, const char *func) { - GET_CURRENT_CONTEXT(ctx); - const struct gl_vertex_array_object *vao = ctx->Array.VAO; struct gl_buffer_object *vbo; 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, - "glBindVertexBuffer(No array object bound)"); - return; - } - - /* The ARB_vertex_attrib_binding spec says: - * * "An INVALID_VALUE error is generated if <bindingindex> is greater than * the value of MAX_VERTEX_ATTRIB_BINDINGS." */ if (bindingIndex >= ctx->Const.MaxVertexAttribBindings) { _mesa_error(ctx, GL_INVALID_VALUE, - "glBindVertexBuffer(bindingindex=%u > " + "%s(bindingindex=%u > " "GL_MAX_VERTEX_ATTRIB_BINDINGS)", - bindingIndex); + func, bindingIndex); return; } @@ -1437,21 +1694,21 @@ _mesa_BindVertexBuffer(GLuint bindingIndex, GLuint buffer, GLintptr offset, */ if (offset < 0) { _mesa_error(ctx, GL_INVALID_VALUE, - "glBindVertexBuffer(offset=%" PRId64 " < 0)", - (int64_t) offset); + "%s(offset=%" PRId64 " < 0)", + func, (int64_t) offset); return; } if (stride < 0) { _mesa_error(ctx, GL_INVALID_VALUE, - "glBindVertexBuffer(stride=%d < 0)", stride); + "%s(stride=%d < 0)", func, stride); return; } if (ctx->API == API_OPENGL_CORE && ctx->Version >= 44 && stride > ctx->Const.MaxVertexAttribStride) { - _mesa_error(ctx, GL_INVALID_VALUE, "glBindVertexBuffer(stride=%d > " - "GL_MAX_VERTEX_ATTRIB_STRIDE)", stride); + _mesa_error(ctx, GL_INVALID_VALUE, "%s(stride=%d > " + "GL_MAX_VERTEX_ATTRIB_STRIDE)", func, stride); return; } @@ -1471,7 +1728,7 @@ _mesa_BindVertexBuffer(GLuint bindingIndex, GLuint buffer, GLintptr offset, * object references (automatically gen it). */ if (!_mesa_handle_bind_buffer_gen(ctx, GL_ARRAY_BUFFER, buffer, - &vbo, "glBindVertexBuffer")) + &vbo, func)) return; } else { /* The ARB_vertex_attrib_binding spec says: @@ -1482,33 +1739,75 @@ _mesa_BindVertexBuffer(GLuint bindingIndex, GLuint buffer, GLintptr offset, vbo = ctx->Shared->NullBufferObj; } - bind_vertex_buffer(ctx, VERT_ATTRIB_GENERIC(bindingIndex), + bind_vertex_buffer(ctx, vao, VERT_ATTRIB_GENERIC(bindingIndex), vbo, offset, stride); } void GLAPIENTRY -_mesa_BindVertexBuffers(GLuint first, GLsizei count, const GLuint *buffers, - const GLintptr *offsets, const GLsizei *strides) +_mesa_BindVertexBuffer(GLuint bindingIndex, GLuint buffer, GLintptr offset, + GLsizei stride) { 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." + * "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)"); + "glBindVertexBuffer(No array object bound)"); return; } + vertex_array_vertex_buffer(ctx, ctx->Array.VAO, bindingIndex, + buffer, offset, stride, "glBindVertexBuffer"); +} + + +void GLAPIENTRY +_mesa_VertexArrayVertexBuffer(GLuint vaobj, GLuint bindingIndex, GLuint buffer, + GLintptr offset, GLsizei stride) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_vertex_array_object *vao; + + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glVertexArrayVertexBuffer(GL_ARB_direct_state_access " + "is not supported"); + return; + } + + /* The ARB_direct_state_access specification says: + * + * "An INVALID_OPERATION error is generated by VertexArrayVertexBuffer + * if <vaobj> is not [compatibility profile: zero or] the name of an + * existing vertex array object." + */ + vao = _mesa_lookup_vao_err(ctx, vaobj, "glVertexArrayVertexBuffer"); + if (!vao) + return; + + vertex_array_vertex_buffer(ctx, vao, bindingIndex, + buffer, offset, stride, + "glVertexArrayVertexBuffer"); +} + + +static void +vertex_array_vertex_buffers(struct gl_context *ctx, + struct gl_vertex_array_object *vao, + GLuint first, GLsizei count, const GLuint *buffers, + const GLintptr *offsets, const GLsizei *strides, + const char *func) +{ + GLuint i; + + ASSERT_OUTSIDE_BEGIN_END(ctx); + /* The ARB_multi_bind spec says: * * "An INVALID_OPERATION error is generated if <first> + <count> @@ -1516,9 +1815,9 @@ _mesa_BindVertexBuffers(GLuint first, GLsizei count, const GLuint *buffers, */ if (first + count > ctx->Const.MaxVertexAttribBindings) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glBindVertexBuffers(first=%u + count=%d > the value of " + "%s(first=%u + count=%d > the value of " "GL_MAX_VERTEX_ATTRIB_BINDINGS=%u)", - first, count, ctx->Const.MaxVertexAttribBindings); + func, first, count, ctx->Const.MaxVertexAttribBindings); return; } @@ -1535,7 +1834,8 @@ _mesa_BindVertexBuffers(GLuint first, GLsizei count, const GLuint *buffers, 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); + bind_vertex_buffer(ctx, vao, VERT_ATTRIB_GENERIC(first + i), + vbo, 0, 16); return; } @@ -1571,23 +1871,23 @@ _mesa_BindVertexBuffers(GLuint first, GLsizei count, const GLuint *buffers, */ if (offsets[i] < 0) { _mesa_error(ctx, GL_INVALID_VALUE, - "glBindVertexBuffers(offsets[%u]=%" PRId64 " < 0)", - i, (int64_t) offsets[i]); + "%s(offsets[%u]=%" PRId64 " < 0)", + func, i, (int64_t) offsets[i]); continue; } if (strides[i] < 0) { _mesa_error(ctx, GL_INVALID_VALUE, - "glBindVertexBuffers(strides[%u]=%d < 0)", - i, strides[i]); + "%s(strides[%u]=%d < 0)", + func, i, strides[i]); continue; } if (ctx->API == API_OPENGL_CORE && ctx->Version >= 44 && strides[i] > ctx->Const.MaxVertexAttribStride) { _mesa_error(ctx, GL_INVALID_VALUE, - "glBindVertexBuffers(strides[%u]=%d > " - "GL_MAX_VERTEX_ATTRIB_STRIDE)", i, strides[i]); + "%s(strides[%u]=%d > " + "GL_MAX_VERTEX_ATTRIB_STRIDE)", func, i, strides[i]); continue; } @@ -1598,8 +1898,7 @@ _mesa_BindVertexBuffers(GLuint first, GLsizei count, const GLuint *buffers, if (buffers[i] == binding->BufferObj->Name) vbo = binding->BufferObj; else - vbo = _mesa_multi_bind_lookup_bufferobj(ctx, buffers, i, - "glBindVertexBuffers"); + vbo = _mesa_multi_bind_lookup_bufferobj(ctx, buffers, i, func); if (!vbo) continue; @@ -1607,8 +1906,8 @@ _mesa_BindVertexBuffers(GLuint first, GLsizei count, const GLuint *buffers, vbo = ctx->Shared->NullBufferObj; } - bind_vertex_buffer(ctx, VERT_ATTRIB_GENERIC(first + i), vbo, - offsets[i], strides[i]); + bind_vertex_buffer(ctx, vao, VERT_ATTRIB_GENERIC(first + i), + vbo, offsets[i], strides[i]); } _mesa_end_bufferobj_lookups(ctx); @@ -1616,65 +1915,68 @@ _mesa_BindVertexBuffers(GLuint first, GLsizei count, const GLuint *buffers, void GLAPIENTRY -_mesa_VertexAttribFormat(GLuint attribIndex, GLint size, GLenum type, - GLboolean normalized, GLuint relativeOffset) +_mesa_BindVertexBuffers(GLuint first, GLsizei count, const GLuint *buffers, + const GLintptr *offsets, const GLsizei *strides) { - const GLbitfield legalTypes = (BYTE_BIT | UNSIGNED_BYTE_BIT | - SHORT_BIT | UNSIGNED_SHORT_BIT | - INT_BIT | UNSIGNED_INT_BIT | - HALF_BIT | FLOAT_BIT | DOUBLE_BIT | - FIXED_GL_BIT | - UNSIGNED_INT_2_10_10_10_REV_BIT | - INT_2_10_10_10_REV_BIT | - UNSIGNED_INT_10F_11F_11F_REV_BIT); - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); /* The ARB_vertex_attrib_binding spec says: * - * "An INVALID_OPERATION error is generated under any of the following - * conditions: - * - if no vertex array object is currently bound (see section 2.10); - * - ..." + * "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, - "glVertexAttribFormat(No array object bound)"); + "glBindVertexBuffers(No array object bound)"); return; } - /* The ARB_vertex_attrib_binding spec says: - * - * "The error INVALID_VALUE is generated if index is greater than or equal - * to the value of MAX_VERTEX_ATTRIBS." - */ - if (attribIndex >= ctx->Const.Program[MESA_SHADER_VERTEX].MaxAttribs) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glVertexAttribFormat(attribindex=%u > " - "GL_MAX_VERTEX_ATTRIBS)", - attribIndex); + vertex_array_vertex_buffers(ctx, ctx->Array.VAO, first, count, + buffers, offsets, strides, + "glBindVertexBuffers"); +} + + +void GLAPIENTRY +_mesa_VertexArrayVertexBuffers(GLuint vaobj, GLuint first, GLsizei count, + const GLuint *buffers, + const GLintptr *offsets, const GLsizei *strides) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_vertex_array_object *vao; + + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glVertexArrayVertexBuffers(GL_ARB_direct_state_access " + "is not supported"); return; } - FLUSH_VERTICES(ctx, 0); - update_array_format(ctx, "glVertexAttribFormat", - VERT_ATTRIB_GENERIC(attribIndex), - legalTypes, 1, BGRA_OR_4, size, type, normalized, - GL_FALSE, relativeOffset); + /* The ARB_direct_state_access specification says: + * + * "An INVALID_OPERATION error is generated by VertexArrayVertexBuffer + * if <vaobj> is not [compatibility profile: zero or] the name of an + * existing vertex array object." + */ + vao = _mesa_lookup_vao_err(ctx, vaobj, "glVertexArrayVertexBuffers"); + if (!vao) + return; + + vertex_array_vertex_buffers(ctx, vao, first, count, + buffers, offsets, strides, + "glVertexArrayVertexBuffers"); } -void GLAPIENTRY -_mesa_VertexAttribIFormat(GLuint attribIndex, GLint size, GLenum type, - GLuint relativeOffset) +static void +vertex_attrib_format(GLuint attribIndex, GLint size, GLenum type, + GLboolean normalized, GLboolean integer, + GLboolean doubles, GLbitfield legalTypes, + GLsizei maxSize, GLuint relativeOffset, + const char *func) { - const GLbitfield legalTypes = (BYTE_BIT | UNSIGNED_BYTE_BIT | - SHORT_BIT | UNSIGNED_SHORT_BIT | - INT_BIT | UNSIGNED_INT_BIT); - GET_CURRENT_CONTEXT(ctx); ASSERT_OUTSIDE_BEGIN_END(ctx); @@ -1684,33 +1986,59 @@ _mesa_VertexAttribIFormat(GLuint attribIndex, GLint size, GLenum type, * conditions: * - if no vertex array object is currently bound (see section 2.10); * - ..." + * + * This error condition only applies to VertexAttribFormat and + * VertexAttribIFormat in the extension spec, but we assume that this + * is an oversight. In the OpenGL 4.3 (Core Profile) spec, it applies + * to all three functions. */ if (ctx->API == API_OPENGL_CORE && ctx->Array.VAO == ctx->Array.DefaultVAO) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glVertexAttribIFormat(No array object bound)"); + "%s(No array object bound)", func); return; } /* The ARB_vertex_attrib_binding spec says: * - * "The error INVALID_VALUE is generated if index is greater than - * or equal to the value of MAX_VERTEX_ATTRIBS." + * "The error INVALID_VALUE is generated if index is greater than or equal + * to the value of MAX_VERTEX_ATTRIBS." */ if (attribIndex >= ctx->Const.Program[MESA_SHADER_VERTEX].MaxAttribs) { _mesa_error(ctx, GL_INVALID_VALUE, - "glVertexAttribIFormat(attribindex=%u > " + "%s(attribindex=%u > " "GL_MAX_VERTEX_ATTRIBS)", - attribIndex); + func, attribIndex); return; } FLUSH_VERTICES(ctx, 0); - update_array_format(ctx, "glVertexAttribIFormat", + update_array_format(ctx, func, ctx->Array.VAO, VERT_ATTRIB_GENERIC(attribIndex), - legalTypes, 1, 4, size, type, GL_FALSE, GL_TRUE, - relativeOffset); + legalTypes, 1, maxSize, size, type, + normalized, integer, doubles, relativeOffset); +} + + +void GLAPIENTRY +_mesa_VertexAttribFormat(GLuint attribIndex, GLint size, GLenum type, + GLboolean normalized, GLuint relativeOffset) +{ + vertex_attrib_format(attribIndex, size, type, normalized, + GL_FALSE, GL_FALSE, ATTRIB_FORMAT_TYPES_MASK, + BGRA_OR_4, relativeOffset, + "glVertexAttribFormat"); +} + + +void GLAPIENTRY +_mesa_VertexAttribIFormat(GLuint attribIndex, GLint size, GLenum type, + GLuint relativeOffset) +{ + vertex_attrib_format(attribIndex, size, type, GL_FALSE, + GL_TRUE, GL_FALSE, ATTRIB_IFORMAT_TYPES_MASK, 4, + relativeOffset, "glVertexAttribIFormat"); } @@ -1718,67 +2046,104 @@ void GLAPIENTRY _mesa_VertexAttribLFormat(GLuint attribIndex, GLint size, GLenum type, GLuint relativeOffset) { - const GLbitfield legalTypes = DOUBLE_BIT; + vertex_attrib_format(attribIndex, size, type, GL_FALSE, GL_FALSE, + GL_TRUE, ATTRIB_LFORMAT_TYPES_MASK, 4, + relativeOffset, "glVertexAttribLFormat"); +} + +static void +vertex_array_attrib_format(GLuint vaobj, GLuint attribIndex, GLint size, + GLenum type, GLboolean normalized, + GLboolean integer, GLboolean doubles, + GLbitfield legalTypes, GLsizei maxSize, + GLuint relativeOffset, const char *func) +{ GET_CURRENT_CONTEXT(ctx); + struct gl_vertex_array_object *vao; + + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(GL_ARB_direct_state_access is not supported", func); + return; + } + ASSERT_OUTSIDE_BEGIN_END(ctx); - /* Page 298 of the PDF of the OpenGL 4.3 (Core Profile) spec says: - * - * "An INVALID_OPERATION error is generated under any of the following - * conditions: - * • if no vertex array object is currently bound (see section 10.4); - * • ..." + /* The ARB_direct_state_access spec says: * - * This language is missing from the extension spec, but we assume - * that this is an oversight. + * "An INVALID_OPERATION error is generated by VertexArrayAttrib*Format + * if <vaobj> is not [compatibility profile: zero or] the name of an + * existing vertex array object." */ - if (ctx->API == API_OPENGL_CORE && - ctx->Array.VAO == ctx->Array.DefaultVAO) { - _mesa_error(ctx, GL_INVALID_OPERATION, - "glVertexAttribLFormat(No array object bound)"); + vao = _mesa_lookup_vao_err(ctx, vaobj, func); + if (!vao) return; - } /* The ARB_vertex_attrib_binding spec says: * - * "The error INVALID_VALUE is generated if <attribindex> is greater than - * or equal to the value of MAX_VERTEX_ATTRIBS." + * "The error INVALID_VALUE is generated if index is greater than or equal + * to the value of MAX_VERTEX_ATTRIBS." */ if (attribIndex >= ctx->Const.Program[MESA_SHADER_VERTEX].MaxAttribs) { _mesa_error(ctx, GL_INVALID_VALUE, - "glVertexAttribLFormat(attribindex=%u > " - "GL_MAX_VERTEX_ATTRIBS)", - attribIndex); + "%s(attribindex=%u > GL_MAX_VERTEX_ATTRIBS)", + func, attribIndex); return; } FLUSH_VERTICES(ctx, 0); - update_array_format(ctx, "glVertexAttribLFormat", + update_array_format(ctx, func, vao, VERT_ATTRIB_GENERIC(attribIndex), - legalTypes, 1, 4, size, type, GL_FALSE, GL_FALSE, - relativeOffset); + legalTypes, 1, maxSize, size, type, normalized, + integer, doubles, relativeOffset); } void GLAPIENTRY -_mesa_VertexAttribBinding(GLuint attribIndex, GLuint bindingIndex) +_mesa_VertexArrayAttribFormat(GLuint vaobj, GLuint attribIndex, GLint size, + GLenum type, GLboolean normalized, + GLuint relativeOffset) { - GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); + vertex_array_attrib_format(vaobj, attribIndex, size, type, normalized, + GL_FALSE, GL_FALSE, ATTRIB_FORMAT_TYPES_MASK, + BGRA_OR_4, relativeOffset, + "glVertexArrayAttribFormat"); +} - /* 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, - "glVertexAttribBinding(No array object bound)"); - return; - } + +void GLAPIENTRY +_mesa_VertexArrayAttribIFormat(GLuint vaobj, GLuint attribIndex, + GLint size, GLenum type, + GLuint relativeOffset) +{ + vertex_array_attrib_format(vaobj, attribIndex, size, type, GL_FALSE, + GL_TRUE, GL_FALSE, ATTRIB_IFORMAT_TYPES_MASK, + 4, relativeOffset, + "glVertexArrayAttribIFormat"); +} + + +void GLAPIENTRY +_mesa_VertexArrayAttribLFormat(GLuint vaobj, GLuint attribIndex, + GLint size, GLenum type, + GLuint relativeOffset) +{ + vertex_array_attrib_format(vaobj, attribIndex, size, type, GL_FALSE, + GL_FALSE, GL_TRUE, ATTRIB_LFORMAT_TYPES_MASK, + 4, relativeOffset, + "glVertexArrayAttribLFormat"); +} + + +static void +vertex_array_attrib_binding(struct gl_context *ctx, + struct gl_vertex_array_object *vao, + GLuint attribIndex, GLuint bindingIndex, + const char *func) +{ + ASSERT_OUTSIDE_BEGIN_END(ctx); /* The ARB_vertex_attrib_binding spec says: * @@ -1789,38 +2154,32 @@ _mesa_VertexAttribBinding(GLuint attribIndex, GLuint bindingIndex) */ if (attribIndex >= ctx->Const.Program[MESA_SHADER_VERTEX].MaxAttribs) { _mesa_error(ctx, GL_INVALID_VALUE, - "glVertexAttribBinding(attribindex=%u >= " + "%s(attribindex=%u >= " "GL_MAX_VERTEX_ATTRIBS)", - attribIndex); + func, attribIndex); return; } if (bindingIndex >= ctx->Const.MaxVertexAttribBindings) { _mesa_error(ctx, GL_INVALID_VALUE, - "glVertexAttribBinding(bindingindex=%u >= " + "%s(bindingindex=%u >= " "GL_MAX_VERTEX_ATTRIB_BINDINGS)", - bindingIndex); + func, bindingIndex); return; } - assert(VERT_ATTRIB_GENERIC(attribIndex) < - ARRAY_SIZE(ctx->Array.VAO->VertexAttrib)); + assert(VERT_ATTRIB_GENERIC(attribIndex) < ARRAY_SIZE(vao->VertexAttrib)); - vertex_attrib_binding(ctx, VERT_ATTRIB_GENERIC(attribIndex), + vertex_attrib_binding(ctx, vao, + VERT_ATTRIB_GENERIC(attribIndex), VERT_ATTRIB_GENERIC(bindingIndex)); } void GLAPIENTRY -_mesa_VertexBindingDivisor(GLuint bindingIndex, GLuint divisor) +_mesa_VertexAttribBinding(GLuint attribIndex, GLuint bindingIndex) { GET_CURRENT_CONTEXT(ctx); - ASSERT_OUTSIDE_BEGIN_END(ctx); - - if (!ctx->Extensions.ARB_instanced_arrays) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glVertexBindingDivisor()"); - return; - } /* The ARB_vertex_attrib_binding spec says: * @@ -1830,7 +2189,54 @@ _mesa_VertexBindingDivisor(GLuint bindingIndex, GLuint divisor) if (ctx->API == API_OPENGL_CORE && ctx->Array.VAO == ctx->Array.DefaultVAO) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glVertexBindingDivisor(No array object bound)"); + "glVertexAttribBinding(No array object bound)"); + return; + } + + vertex_array_attrib_binding(ctx, ctx->Array.VAO, + attribIndex, bindingIndex, + "glVertexAttribBinding"); +} + + +void GLAPIENTRY +_mesa_VertexArrayAttribBinding(GLuint vaobj, GLuint attribIndex, GLuint bindingIndex) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_vertex_array_object *vao; + + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glVertexArrayAttribBinding(GL_ARB_direct_state_access " + "is not supported"); + return; + } + + /* The ARB_direct_state_access specification says: + * + * "An INVALID_OPERATION error is generated by VertexArrayAttribBinding + * if <vaobj> is not [compatibility profile: zero or] the name of an + * existing vertex array object." + */ + vao = _mesa_lookup_vao_err(ctx, vaobj, "glVertexArrayAttribBinding"); + if (!vao) + return; + + vertex_array_attrib_binding(ctx, vao, attribIndex, bindingIndex, + "glVertexArrayAttribBinding"); +} + + +static void +vertex_array_binding_divisor(struct gl_context *ctx, + struct gl_vertex_array_object *vao, + GLuint bindingIndex, GLuint divisor, + const char *func) +{ + ASSERT_OUTSIDE_BEGIN_END(ctx); + + if (!ctx->Extensions.ARB_instanced_arrays) { + _mesa_error(ctx, GL_INVALID_OPERATION, "%s()", func); return; } @@ -1841,13 +2247,64 @@ _mesa_VertexBindingDivisor(GLuint bindingIndex, GLuint divisor) */ if (bindingIndex >= ctx->Const.MaxVertexAttribBindings) { _mesa_error(ctx, GL_INVALID_VALUE, - "glVertexBindingDivisor(bindingindex=%u > " + "%s(bindingindex=%u > " "GL_MAX_VERTEX_ATTRIB_BINDINGS)", - bindingIndex); + func, bindingIndex); return; } - vertex_binding_divisor(ctx, VERT_ATTRIB_GENERIC(bindingIndex), divisor); + vertex_binding_divisor(ctx, vao, VERT_ATTRIB_GENERIC(bindingIndex), divisor); +} + + +void GLAPIENTRY +_mesa_VertexBindingDivisor(GLuint bindingIndex, GLuint divisor) +{ + GET_CURRENT_CONTEXT(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, + "glVertexBindingDivisor(No array object bound)"); + return; + } + + vertex_array_binding_divisor(ctx, ctx->Array.VAO, + bindingIndex, divisor, + "glVertexBindingDivisor"); +} + + +void GLAPIENTRY +_mesa_VertexArrayBindingDivisor(GLuint vaobj, GLuint bindingIndex, GLuint divisor) +{ + struct gl_vertex_array_object *vao; + GET_CURRENT_CONTEXT(ctx); + + if (!ctx->Extensions.ARB_direct_state_access) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glVertexArrayBindingDivisor(GL_ARB_direct_state_access " + "is not supported"); + return; + } + + /* The ARB_direct_state_access specification says: + * + * "An INVALID_OPERATION error is generated by VertexArrayBindingDivisor + * if <vaobj> is not [compatibility profile: zero or] the name of an + * existing vertex array object." + */ + vao = _mesa_lookup_vao_err(ctx, vaobj, "glVertexArrayBindingDivisor"); + if (!vao) + return; + + vertex_array_binding_divisor(ctx, vao, bindingIndex, divisor, + "glVertexArrayBindingDivisor"); } @@ -1868,6 +2325,7 @@ _mesa_copy_client_array(struct gl_context *ctx, dst->Enabled = src->Enabled; dst->Normalized = src->Normalized; dst->Integer = src->Integer; + dst->Doubles = src->Doubles; dst->InstanceDivisor = src->InstanceDivisor; dst->_ElementSize = src->_ElementSize; _mesa_reference_buffer_object(ctx, &dst->BufferObj, src->BufferObj); @@ -1885,6 +2343,7 @@ _mesa_copy_vertex_attrib_array(struct gl_context *ctx, dst->RelativeOffset = src->RelativeOffset; dst->Format = src->Format; dst->Integer = src->Integer; + dst->Doubles = src->Doubles; dst->Normalized = src->Normalized; dst->Ptr = src->Ptr; dst->Enabled = src->Enabled; diff --git a/mesalib/src/mesa/main/varray.h b/mesalib/src/mesa/main/varray.h index 4e4bd5f80..5583ed5a1 100644 --- a/mesalib/src/mesa/main/varray.h +++ b/mesalib/src/mesa/main/varray.h @@ -68,6 +68,7 @@ _mesa_update_client_array(struct gl_context *ctx, dst->Enabled = src->Enabled; dst->Normalized = src->Normalized; dst->Integer = src->Integer; + dst->Doubles = src->Doubles; dst->InstanceDivisor = binding->InstanceDivisor; dst->_ElementSize = src->_ElementSize; _mesa_reference_buffer_object(ctx, &dst->BufferObj, binding->BufferObj); @@ -166,22 +167,34 @@ void GLAPIENTRY _mesa_VertexAttribIPointer(GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *ptr); +extern void GLAPIENTRY +_mesa_VertexAttribLPointer(GLuint index, GLint size, GLenum type, + GLsizei stride, const GLvoid *pointer); extern void GLAPIENTRY _mesa_EnableVertexAttribArray(GLuint index); extern void GLAPIENTRY +_mesa_EnableVertexArrayAttrib(GLuint vaobj, GLuint index); + + +extern void GLAPIENTRY _mesa_DisableVertexAttribArray(GLuint index); extern void GLAPIENTRY -_mesa_GetVertexAttribdv(GLuint index, GLenum pname, GLdouble *params); +_mesa_DisableVertexArrayAttrib(GLuint vaobj, GLuint index); + +extern void GLAPIENTRY +_mesa_GetVertexAttribdv(GLuint index, GLenum pname, GLdouble *params); extern void GLAPIENTRY _mesa_GetVertexAttribfv(GLuint index, GLenum pname, GLfloat *params); +extern void GLAPIENTRY +_mesa_GetVertexAttribLdv(GLuint index, GLenum pname, GLdouble *params); extern void GLAPIENTRY _mesa_GetVertexAttribiv(GLuint index, GLenum pname, GLint *params); @@ -199,6 +212,16 @@ extern void GLAPIENTRY _mesa_GetVertexAttribPointerv(GLuint index, GLenum pname, GLvoid **pointer); +void GLAPIENTRY +_mesa_GetVertexArrayIndexediv(GLuint vaobj, GLuint index, + GLenum pname, GLint *param); + + +void GLAPIENTRY +_mesa_GetVertexArrayIndexed64iv(GLuint vaobj, GLuint index, + GLenum pname, GLint64 *param); + + extern void GLAPIENTRY _mesa_InterleavedArrays(GLenum format, GLsizei stride, const GLvoid *pointer); @@ -278,27 +301,57 @@ _mesa_BindVertexBuffer(GLuint bindingIndex, GLuint buffer, GLintptr offset, GLsizei stride); extern void GLAPIENTRY +_mesa_VertexArrayVertexBuffer(GLuint vaobj, 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_VertexArrayVertexBuffers(GLuint vaobj, 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); extern void GLAPIENTRY +_mesa_VertexArrayAttribFormat(GLuint vaobj, GLuint attribIndex, GLint size, + GLenum type, GLboolean normalized, + GLuint relativeOffset); + +extern void GLAPIENTRY _mesa_VertexAttribIFormat(GLuint attribIndex, GLint size, GLenum type, GLuint relativeOffset); extern void GLAPIENTRY +_mesa_VertexArrayAttribIFormat(GLuint vaobj, GLuint attribIndex, + GLint size, GLenum type, + GLuint relativeOffset); + +extern void GLAPIENTRY _mesa_VertexAttribLFormat(GLuint attribIndex, GLint size, GLenum type, GLuint relativeOffset); extern void GLAPIENTRY +_mesa_VertexArrayAttribLFormat(GLuint vaobj, GLuint attribIndex, + GLint size, GLenum type, + GLuint relativeOffset); + +extern void GLAPIENTRY _mesa_VertexAttribBinding(GLuint attribIndex, GLuint bindingIndex); extern void GLAPIENTRY +_mesa_VertexArrayAttribBinding(GLuint vaobj, GLuint attribIndex, + GLuint bindingIndex); + +extern void GLAPIENTRY _mesa_VertexBindingDivisor(GLuint bindingIndex, GLuint divisor); +extern void GLAPIENTRY +_mesa_VertexArrayBindingDivisor(GLuint vaobj, GLuint bindingIndex, GLuint divisor); extern void _mesa_copy_client_array(struct gl_context *ctx, diff --git a/mesalib/src/mesa/main/version.c b/mesalib/src/mesa/main/version.c index 5b8ac0a5c..699a0de46 100644 --- a/mesalib/src/mesa/main/version.c +++ b/mesalib/src/mesa/main/version.c @@ -32,23 +32,16 @@ /** * Scans 'string' to see if it ends with 'ending'. */ -static GLboolean +static bool check_for_ending(const char *string, const char *ending) { - int len1, len2; + const size_t len1 = strlen(string); + const size_t len2 = strlen(ending); - len1 = strlen(string); - len2 = strlen(ending); + if (len2 > len1) + return false; - if (len2 > len1) { - return GL_FALSE; - } - - if (strcmp(string + (len1 - len2), ending) == 0) { - return GL_TRUE; - } else { - return GL_FALSE; - } + return strcmp(string + (len1 - len2), ending) == 0; } /** @@ -58,15 +51,14 @@ check_for_ending(const char *string, const char *ending) * fwd_context is only valid if version > 0 */ static void -get_gl_override(int *version, GLboolean *fwd_context, - GLboolean *compat_context) +get_gl_override(int *version, bool *fwd_context, bool *compat_context) { const char *env_var = "MESA_GL_VERSION_OVERRIDE"; const char *version_str; int major, minor, n; static int override_version = -1; - static GLboolean fc_suffix = GL_FALSE; - static GLboolean compat_suffix = GL_FALSE; + static bool fc_suffix = false; + static bool compat_suffix = false; if (override_version < 0) { override_version = 0; @@ -78,12 +70,14 @@ get_gl_override(int *version, GLboolean *fwd_context, n = sscanf(version_str, "%u.%u", &major, &minor); if (n != 2) { - fprintf(stderr, "error: invalid value for %s: %s\n", env_var, version_str); + fprintf(stderr, "error: invalid value for %s: %s\n", + env_var, version_str); override_version = 0; } else { override_version = major * 10 + minor; if (override_version < 30 && fc_suffix) { - fprintf(stderr, "error: invalid value for %s: %s\n", env_var, version_str); + fprintf(stderr, "error: invalid value for %s: %s\n", + env_var, version_str); } } } @@ -134,7 +128,7 @@ _mesa_override_gl_version_contextless(struct gl_constants *consts, gl_api *apiOut, GLuint *versionOut) { int version; - GLboolean fwd_context, compat_context; + bool fwd_context, compat_context; get_gl_override(&version, &fwd_context, &compat_context); @@ -148,9 +142,9 @@ _mesa_override_gl_version_contextless(struct gl_constants *consts, } else { *apiOut = API_OPENGL_COMPAT; } - return GL_TRUE; + return true; } - return GL_FALSE; + return false; } void @@ -171,7 +165,7 @@ int _mesa_get_gl_version_override(void) { int version; - GLboolean fwd_context, compat_context; + bool fwd_context, compat_context; get_gl_override(&version, &fwd_context, &compat_context); @@ -211,121 +205,121 @@ compute_version(const struct gl_extensions *extensions, { GLuint major, minor, version; - const GLboolean ver_1_3 = (extensions->ARB_texture_border_clamp && - extensions->ARB_texture_cube_map && - extensions->ARB_texture_env_combine && - extensions->ARB_texture_env_dot3); - const GLboolean ver_1_4 = (ver_1_3 && - extensions->ARB_depth_texture && - extensions->ARB_shadow && - extensions->ARB_texture_env_crossbar && - extensions->EXT_blend_color && - extensions->EXT_blend_func_separate && - extensions->EXT_blend_minmax && - extensions->EXT_point_parameters); - const GLboolean ver_1_5 = (ver_1_4 && - extensions->ARB_occlusion_query); - const GLboolean ver_2_0 = (ver_1_5 && - extensions->ARB_point_sprite && - extensions->ARB_vertex_shader && - extensions->ARB_fragment_shader && - extensions->ARB_texture_non_power_of_two && - extensions->EXT_blend_equation_separate && - - /* Technically, 2.0 requires the functionality - * of the EXT version. Enable 2.0 if either - * extension is available, and assume that a - * driver that only exposes the ATI extension - * will fallback to software when necessary. - */ - (extensions->EXT_stencil_two_side - || extensions->ATI_separate_stencil)); - const GLboolean ver_2_1 = (ver_2_0 && - extensions->EXT_pixel_buffer_object && - extensions->EXT_texture_sRGB); - const GLboolean ver_3_0 = (ver_2_1 && - consts->GLSLVersion >= 130 && - (consts->MaxSamples >= 4 || consts->FakeSWMSAA) && - (api == API_OPENGL_CORE || - extensions->ARB_color_buffer_float) && - extensions->ARB_depth_buffer_float && - extensions->ARB_half_float_vertex && - extensions->ARB_map_buffer_range && - extensions->ARB_shader_texture_lod && - extensions->ARB_texture_float && - extensions->ARB_texture_rg && - extensions->ARB_texture_compression_rgtc && - extensions->EXT_draw_buffers2 && - extensions->ARB_framebuffer_object && - extensions->EXT_framebuffer_sRGB && - extensions->EXT_packed_float && - extensions->EXT_texture_array && - extensions->EXT_texture_shared_exponent && - extensions->EXT_transform_feedback && - extensions->NV_conditional_render); - const GLboolean ver_3_1 = (ver_3_0 && - consts->GLSLVersion >= 140 && - extensions->ARB_draw_instanced && - extensions->ARB_texture_buffer_object && - extensions->ARB_uniform_buffer_object && - extensions->EXT_texture_snorm && - extensions->NV_primitive_restart && - extensions->NV_texture_rectangle && - consts->Program[MESA_SHADER_VERTEX].MaxTextureImageUnits >= 16); - const GLboolean ver_3_2 = (ver_3_1 && - consts->GLSLVersion >= 150 && - extensions->ARB_depth_clamp && - extensions->ARB_draw_elements_base_vertex && - extensions->ARB_fragment_coord_conventions && - extensions->EXT_provoking_vertex && - extensions->ARB_seamless_cube_map && - extensions->ARB_sync && - extensions->ARB_texture_multisample && - extensions->EXT_vertex_array_bgra); - const GLboolean ver_3_3 = (ver_3_2 && - consts->GLSLVersion >= 330 && - extensions->ARB_blend_func_extended && - extensions->ARB_explicit_attrib_location && - extensions->ARB_instanced_arrays && - extensions->ARB_occlusion_query2 && - extensions->ARB_shader_bit_encoding && - extensions->ARB_texture_rgb10_a2ui && - extensions->ARB_timer_query && - extensions->ARB_vertex_type_2_10_10_10_rev && - extensions->EXT_texture_swizzle); - /* ARB_sampler_objects is always enabled in mesa */ - - const GLboolean ver_4_0 = (ver_3_3 && - consts->GLSLVersion >= 400 && - extensions->ARB_draw_buffers_blend && - extensions->ARB_draw_indirect && - extensions->ARB_gpu_shader5 && - extensions->ARB_gpu_shader_fp64 && - extensions->ARB_sample_shading && - 0/*extensions->ARB_shader_subroutine*/ && - extensions->ARB_tessellation_shader && - extensions->ARB_texture_buffer_object_rgb32 && - extensions->ARB_texture_cube_map_array && - extensions->ARB_texture_query_lod && - extensions->ARB_transform_feedback2 && - extensions->ARB_transform_feedback3); - const GLboolean ver_4_1 = (ver_4_0 && - consts->GLSLVersion >= 410 && - extensions->ARB_ES2_compatibility && - extensions->ARB_shader_precision && - 0/*extensions->ARB_vertex_attrib_64bit*/ && - extensions->ARB_viewport_array); - const GLboolean ver_4_2 = (ver_4_1 && - consts->GLSLVersion >= 420 && - extensions->ARB_base_instance && - extensions->ARB_conservative_depth && - extensions->ARB_internalformat_query && - extensions->ARB_shader_atomic_counters && - extensions->ARB_shader_image_load_store && - extensions->ARB_shading_language_420pack && - extensions->ARB_shading_language_packing && - extensions->ARB_texture_compression_bptc && - extensions->ARB_transform_feedback_instanced); + const bool ver_1_3 = (extensions->ARB_texture_border_clamp && + extensions->ARB_texture_cube_map && + extensions->ARB_texture_env_combine && + extensions->ARB_texture_env_dot3); + const bool ver_1_4 = (ver_1_3 && + extensions->ARB_depth_texture && + extensions->ARB_shadow && + extensions->ARB_texture_env_crossbar && + extensions->EXT_blend_color && + extensions->EXT_blend_func_separate && + extensions->EXT_blend_minmax && + extensions->EXT_point_parameters); + const bool ver_1_5 = (ver_1_4 && + extensions->ARB_occlusion_query); + const bool ver_2_0 = (ver_1_5 && + extensions->ARB_point_sprite && + extensions->ARB_vertex_shader && + extensions->ARB_fragment_shader && + extensions->ARB_texture_non_power_of_two && + extensions->EXT_blend_equation_separate && + + /* Technically, 2.0 requires the functionality of the + * EXT version. Enable 2.0 if either extension is + * available, and assume that a driver that only + * exposes the ATI extension will fallback to + * software when necessary. + */ + (extensions->EXT_stencil_two_side + || extensions->ATI_separate_stencil)); + const bool ver_2_1 = (ver_2_0 && + extensions->EXT_pixel_buffer_object && + extensions->EXT_texture_sRGB); + const bool ver_3_0 = (ver_2_1 && + consts->GLSLVersion >= 130 && + (consts->MaxSamples >= 4 || consts->FakeSWMSAA) && + (api == API_OPENGL_CORE || + extensions->ARB_color_buffer_float) && + extensions->ARB_depth_buffer_float && + extensions->ARB_half_float_vertex && + extensions->ARB_map_buffer_range && + extensions->ARB_shader_texture_lod && + extensions->ARB_texture_float && + extensions->ARB_texture_rg && + extensions->ARB_texture_compression_rgtc && + extensions->EXT_draw_buffers2 && + extensions->ARB_framebuffer_object && + extensions->EXT_framebuffer_sRGB && + extensions->EXT_packed_float && + extensions->EXT_texture_array && + extensions->EXT_texture_shared_exponent && + extensions->EXT_transform_feedback && + extensions->NV_conditional_render); + const bool ver_3_1 = (ver_3_0 && + consts->GLSLVersion >= 140 && + extensions->ARB_draw_instanced && + extensions->ARB_texture_buffer_object && + extensions->ARB_uniform_buffer_object && + extensions->EXT_texture_snorm && + extensions->NV_primitive_restart && + extensions->NV_texture_rectangle && + consts->Program[MESA_SHADER_VERTEX].MaxTextureImageUnits >= 16); + const bool ver_3_2 = (ver_3_1 && + consts->GLSLVersion >= 150 && + extensions->ARB_depth_clamp && + extensions->ARB_draw_elements_base_vertex && + extensions->ARB_fragment_coord_conventions && + extensions->EXT_provoking_vertex && + extensions->ARB_seamless_cube_map && + extensions->ARB_sync && + extensions->ARB_texture_multisample && + extensions->EXT_vertex_array_bgra); + const bool ver_3_3 = (ver_3_2 && + consts->GLSLVersion >= 330 && + extensions->ARB_blend_func_extended && + extensions->ARB_explicit_attrib_location && + extensions->ARB_instanced_arrays && + extensions->ARB_occlusion_query2 && + extensions->ARB_shader_bit_encoding && + extensions->ARB_texture_rgb10_a2ui && + extensions->ARB_timer_query && + extensions->ARB_vertex_type_2_10_10_10_rev && + extensions->EXT_texture_swizzle); + /* ARB_sampler_objects is always enabled in mesa */ + + const bool ver_4_0 = (ver_3_3 && + consts->GLSLVersion >= 400 && + extensions->ARB_draw_buffers_blend && + extensions->ARB_draw_indirect && + extensions->ARB_gpu_shader5 && + extensions->ARB_gpu_shader_fp64 && + extensions->ARB_sample_shading && + false /*extensions->ARB_shader_subroutine*/ && + extensions->ARB_tessellation_shader && + extensions->ARB_texture_buffer_object_rgb32 && + extensions->ARB_texture_cube_map_array && + extensions->ARB_texture_query_lod && + extensions->ARB_transform_feedback2 && + extensions->ARB_transform_feedback3); + const bool ver_4_1 = (ver_4_0 && + consts->GLSLVersion >= 410 && + extensions->ARB_ES2_compatibility && + extensions->ARB_shader_precision && + extensions->ARB_vertex_attrib_64bit && + extensions->ARB_viewport_array); + const bool ver_4_2 = (ver_4_1 && + consts->GLSLVersion >= 420 && + extensions->ARB_base_instance && + extensions->ARB_conservative_depth && + extensions->ARB_internalformat_query && + extensions->ARB_shader_atomic_counters && + extensions->ARB_shader_image_load_store && + extensions->ARB_shading_language_420pack && + extensions->ARB_shading_language_packing && + extensions->ARB_texture_compression_bptc && + extensions->ARB_transform_feedback_instanced); if (ver_4_2) { major = 4; @@ -392,11 +386,11 @@ static GLuint compute_version_es1(const struct gl_extensions *extensions) { /* OpenGL ES 1.0 is derived from OpenGL 1.3 */ - const GLboolean ver_1_0 = (extensions->ARB_texture_env_combine && - extensions->ARB_texture_env_dot3); + const bool ver_1_0 = (extensions->ARB_texture_env_combine && + extensions->ARB_texture_env_dot3); /* OpenGL ES 1.1 is derived from OpenGL 1.5 */ - const GLboolean ver_1_1 = (ver_1_0 && - extensions->EXT_point_parameters); + const bool ver_1_1 = (ver_1_0 && + extensions->EXT_point_parameters); if (ver_1_1) { return 11; @@ -411,34 +405,34 @@ static GLuint compute_version_es2(const struct gl_extensions *extensions) { /* OpenGL ES 2.0 is derived from OpenGL 2.0 */ - const GLboolean ver_2_0 = (extensions->ARB_texture_cube_map && - extensions->EXT_blend_color && - extensions->EXT_blend_func_separate && - extensions->EXT_blend_minmax && - extensions->ARB_vertex_shader && - extensions->ARB_fragment_shader && - extensions->ARB_texture_non_power_of_two && - extensions->EXT_blend_equation_separate); + const bool ver_2_0 = (extensions->ARB_texture_cube_map && + extensions->EXT_blend_color && + extensions->EXT_blend_func_separate && + extensions->EXT_blend_minmax && + extensions->ARB_vertex_shader && + extensions->ARB_fragment_shader && + extensions->ARB_texture_non_power_of_two && + extensions->EXT_blend_equation_separate); /* FINISHME: This list isn't quite right. */ - const GLboolean ver_3_0 = (extensions->ARB_half_float_vertex && - extensions->ARB_internalformat_query && - extensions->ARB_map_buffer_range && - extensions->ARB_shader_texture_lod && - extensions->ARB_texture_float && - extensions->ARB_texture_rg && - extensions->ARB_depth_buffer_float && - extensions->EXT_draw_buffers2 && - /* extensions->ARB_framebuffer_object && */ - extensions->EXT_framebuffer_sRGB && - extensions->EXT_packed_float && - extensions->EXT_texture_array && - extensions->EXT_texture_shared_exponent && - extensions->EXT_transform_feedback && - extensions->ARB_draw_instanced && - extensions->ARB_uniform_buffer_object && - extensions->EXT_texture_snorm && - extensions->NV_primitive_restart && - extensions->OES_depth_texture_cube_map); + const bool ver_3_0 = (extensions->ARB_half_float_vertex && + extensions->ARB_internalformat_query && + extensions->ARB_map_buffer_range && + extensions->ARB_shader_texture_lod && + extensions->ARB_texture_float && + extensions->ARB_texture_rg && + extensions->ARB_depth_buffer_float && + extensions->EXT_draw_buffers2 && + /* extensions->ARB_framebuffer_object && */ + extensions->EXT_framebuffer_sRGB && + extensions->EXT_packed_float && + extensions->EXT_texture_array && + extensions->EXT_texture_shared_exponent && + extensions->EXT_transform_feedback && + extensions->ARB_draw_instanced && + extensions->ARB_uniform_buffer_object && + extensions->EXT_texture_snorm && + extensions->NV_primitive_restart && + extensions->OES_depth_texture_cube_map); if (ver_3_0) { return 30; } else if (ver_2_0) { diff --git a/mesalib/src/mesa/main/vtxfmt.c b/mesalib/src/mesa/main/vtxfmt.c index fc0a01edf..d7ef7e278 100644 --- a/mesalib/src/mesa/main/vtxfmt.c +++ b/mesalib/src/mesa/main/vtxfmt.c @@ -206,6 +206,18 @@ install_vtxfmt(struct gl_context *ctx, struct _glapi_table *tab, SET_VertexAttribP3uiv(tab, vfmt->VertexAttribP3uiv); SET_VertexAttribP4uiv(tab, vfmt->VertexAttribP4uiv); } + + if (_mesa_is_desktop_gl(ctx)) { + SET_VertexAttribL1d(tab, vfmt->VertexAttribL1d); + SET_VertexAttribL2d(tab, vfmt->VertexAttribL2d); + SET_VertexAttribL3d(tab, vfmt->VertexAttribL3d); + SET_VertexAttribL4d(tab, vfmt->VertexAttribL4d); + + SET_VertexAttribL1dv(tab, vfmt->VertexAttribL1dv); + SET_VertexAttribL2dv(tab, vfmt->VertexAttribL2dv); + SET_VertexAttribL3dv(tab, vfmt->VertexAttribL3dv); + SET_VertexAttribL4dv(tab, vfmt->VertexAttribL4dv); + } } diff --git a/mesalib/src/mesa/program/prog_statevars.c b/mesalib/src/mesa/program/prog_statevars.c index 0c0c87faa..bdb335e4b 100644 --- a/mesalib/src/mesa/program/prog_statevars.c +++ b/mesalib/src/mesa/program/prog_statevars.c @@ -244,14 +244,14 @@ _mesa_fetch_state(struct gl_context *ctx, const gl_state_index state[], { /* state[1] is the texture unit */ const GLuint unit = (GLuint) state[1]; - if (_mesa_get_clamp_fragment_color(ctx)) + if (_mesa_get_clamp_fragment_color(ctx, ctx->DrawBuffer)) COPY_4V(value, ctx->Texture.Unit[unit].EnvColor); else COPY_4V(value, ctx->Texture.Unit[unit].EnvColorUnclamped); } return; case STATE_FOG_COLOR: - if (_mesa_get_clamp_fragment_color(ctx)) + if (_mesa_get_clamp_fragment_color(ctx, ctx->DrawBuffer)) COPY_4V(value, ctx->Fog.Color); else COPY_4V(value, ctx->Fog.ColorUnclamped); diff --git a/mesalib/src/mesa/program/prog_to_nir.c b/mesalib/src/mesa/program/prog_to_nir.c index ff3d9f3be..6c5fa51ec 100644 --- a/mesalib/src/mesa/program/prog_to_nir.c +++ b/mesalib/src/mesa/program/prog_to_nir.c @@ -710,7 +710,7 @@ static const nir_op op_trans[MAX_OPCODE] = { [OPCODE_DST] = 0, [OPCODE_END] = 0, [OPCODE_EX2] = nir_op_fexp2, - [OPCODE_EXP] = nir_op_fexp, + [OPCODE_EXP] = 0, [OPCODE_FLR] = nir_op_ffloor, [OPCODE_FRC] = nir_op_ffract, [OPCODE_LG2] = nir_op_flog2, diff --git a/mesalib/src/mesa/program/program.c b/mesalib/src/mesa/program/program.c index 4f28e2a3b..fb61f4d36 100644 --- a/mesalib/src/mesa/program/program.c +++ b/mesalib/src/mesa/program/program.c @@ -102,6 +102,8 @@ _mesa_init_program(struct gl_context *ctx) _mesa_reference_geomprog(ctx, &ctx->GeometryProgram.Current, NULL); + _mesa_reference_compprog(ctx, &ctx->ComputeProgram.Current, NULL); + /* XXX probably move this stuff */ ctx->ATIFragmentShader.Enabled = GL_FALSE; ctx->ATIFragmentShader.Current = ctx->Shared->DefaultFragmentShader; @@ -121,6 +123,7 @@ _mesa_free_program_data(struct gl_context *ctx) _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current, NULL); _mesa_delete_shader_cache(ctx, ctx->FragmentProgram.Cache); _mesa_reference_geomprog(ctx, &ctx->GeometryProgram.Current, NULL); + _mesa_reference_compprog(ctx, &ctx->ComputeProgram.Current, NULL); /* XXX probably move this stuff */ if (ctx->ATIFragmentShader.Current) { diff --git a/mesalib/src/mesa/program/program.h b/mesalib/src/mesa/program/program.h index 0b0d1ac6f..2d92ab2f1 100644 --- a/mesalib/src/mesa/program/program.h +++ b/mesalib/src/mesa/program/program.h @@ -138,6 +138,15 @@ _mesa_reference_geomprog(struct gl_context *ctx, (struct gl_program *) prog); } +static inline void +_mesa_reference_compprog(struct gl_context *ctx, + struct gl_compute_program **ptr, + struct gl_compute_program *prog) +{ + _mesa_reference_program(ctx, (struct gl_program **) ptr, + (struct gl_program *) prog); +} + extern struct gl_program * _mesa_clone_program(struct gl_context *ctx, const struct gl_program *prog); @@ -276,6 +285,19 @@ gl_geometry_program_const(const struct gl_program *prog) } +static inline struct gl_compute_program * +gl_compute_program(struct gl_program *prog) +{ + return (struct gl_compute_program *) prog; +} + +static inline const struct gl_compute_program * +gl_compute_program_const(const struct gl_program *prog) +{ + return (const struct gl_compute_program *) prog; +} + + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/mesalib/src/mesa/state_tracker/st_atom_array.c b/mesalib/src/mesa/state_tracker/st_atom_array.c index d4fb8b862..56b8019a3 100644 --- a/mesalib/src/mesa/state_tracker/st_atom_array.c +++ b/mesalib/src/mesa/state_tracker/st_atom_array.c @@ -44,7 +44,6 @@ #include "cso_cache/cso_context.h" #include "util/u_math.h" - #include "main/bufferobj.h" #include "main/glformats.h" @@ -311,6 +310,18 @@ st_pipe_vertex_format(GLenum type, GLuint size, GLenum format, return PIPE_FORMAT_NONE; /* silence compiler warning */ } +static const struct gl_client_array * +get_client_array(const struct st_vertex_program *vp, + const struct gl_client_array **arrays, + int attr) +{ + const GLuint mesaAttr = vp->index_to_input[attr]; + /* st_program uses 0xffffffff to denote a double placeholder attribute */ + if (mesaAttr == ST_DOUBLE_ATTRIB_PLACEHOLDER) + return NULL; + return arrays[mesaAttr]; +} + /** * Examine the active arrays to determine if we have interleaved * vertex arrays all living in one VBO, or all living in user space. @@ -327,11 +338,16 @@ is_interleaved_arrays(const struct st_vertex_program *vp, GLboolean userSpaceBuffer = GL_FALSE; for (attr = 0; attr < vpv->num_inputs; attr++) { - const GLuint mesaAttr = vp->index_to_input[attr]; - const struct gl_client_array *array = arrays[mesaAttr]; - const struct gl_buffer_object *bufObj = array->BufferObj; - const GLsizei stride = array->StrideB; /* in bytes */ + const struct gl_client_array *array; + const struct gl_buffer_object *bufObj; + GLsizei stride; + + array = get_client_array(vp, arrays, attr); + if (!array) + continue; + stride = array->StrideB; /* in bytes */ + bufObj = array->BufferObj; if (attr == 0) { /* save info about the first array */ firstStride = stride; @@ -358,6 +374,55 @@ is_interleaved_arrays(const struct st_vertex_program *vp, return GL_TRUE; } +static void init_velement(struct pipe_vertex_element *velement, + int src_offset, int format, + int instance_divisor, int vbo_index) +{ + velement->src_offset = src_offset; + velement->src_format = format; + velement->instance_divisor = instance_divisor; + velement->vertex_buffer_index = vbo_index; + assert(velement->src_format); +} + +static void init_velement_lowered(struct st_context *st, + struct pipe_vertex_element *velements, + int src_offset, int format, + int instance_divisor, int vbo_index, + int nr_components, GLboolean doubles, + GLuint *attr_idx) +{ + int idx = *attr_idx; + if (doubles) { + int lower_format; + + if (nr_components == 1) + lower_format = PIPE_FORMAT_R32G32_UINT; + else if (nr_components >= 2) + lower_format = PIPE_FORMAT_R32G32B32A32_UINT; + + init_velement(&velements[idx], src_offset, + lower_format, instance_divisor, vbo_index); + idx++; + + if (nr_components > 2) { + if (nr_components == 3) + lower_format = PIPE_FORMAT_R32G32_UINT; + else if (nr_components >= 4) + lower_format = PIPE_FORMAT_R32G32B32A32_UINT; + + init_velement(&velements[idx], src_offset + 4 * sizeof(float), + lower_format, instance_divisor, vbo_index); + idx++; + } + } else { + init_velement(&velements[idx], src_offset, + format, instance_divisor, vbo_index); + idx++; + } + *attr_idx = idx; +} + /** * Set up for drawing interleaved arrays that all live in one VBO * or all live in user space. @@ -365,13 +430,15 @@ is_interleaved_arrays(const struct st_vertex_program *vp, * \param velements returns vertex element info */ static boolean -setup_interleaved_attribs(const struct st_vertex_program *vp, +setup_interleaved_attribs(struct st_context *st, + const struct st_vertex_program *vp, const struct st_vp_variant *vpv, const struct gl_client_array **arrays, struct pipe_vertex_buffer *vbuffer, - struct pipe_vertex_element velements[]) + struct pipe_vertex_element velements[], + unsigned *num_velements) { - GLuint attr; + GLuint attr, attr_idx; const GLubyte *low_addr = NULL; GLboolean usingVBO; /* all arrays in a VBO? */ struct gl_buffer_object *bufobj; @@ -381,8 +448,10 @@ setup_interleaved_attribs(const struct st_vertex_program *vp, * Init bufobj and stride. */ if (vpv->num_inputs) { - const GLuint mesaAttr0 = vp->index_to_input[0]; - const struct gl_client_array *array = arrays[mesaAttr0]; + const struct gl_client_array *array; + + array = get_client_array(vp, arrays, 0); + assert(array); /* Since we're doing interleaved arrays, we know there'll be at most * one buffer object and the stride will be the same for all arrays. @@ -394,7 +463,11 @@ setup_interleaved_attribs(const struct st_vertex_program *vp, low_addr = arrays[vp->index_to_input[0]]->Ptr; for (attr = 1; attr < vpv->num_inputs; attr++) { - const GLubyte *start = arrays[vp->index_to_input[attr]]->Ptr; + const GLubyte *start; + array = get_client_array(vp, arrays, attr); + if (!array) + continue; + start = array->Ptr; low_addr = MIN2(low_addr, start); } } @@ -408,25 +481,33 @@ setup_interleaved_attribs(const struct st_vertex_program *vp, /* are the arrays in user space? */ usingVBO = _mesa_is_bufferobj(bufobj); + attr_idx = 0; for (attr = 0; attr < vpv->num_inputs; attr++) { - const GLuint mesaAttr = vp->index_to_input[attr]; - const struct gl_client_array *array = arrays[mesaAttr]; - unsigned src_offset = (unsigned) (array->Ptr - low_addr); + const struct gl_client_array *array; + unsigned src_offset; + unsigned src_format; + + array = get_client_array(vp, arrays, attr); + if (!array) + continue; + src_offset = (unsigned) (array->Ptr - low_addr); assert(array->_ElementSize == _mesa_bytes_per_vertex_attrib(array->Size, array->Type)); - velements[attr].src_offset = src_offset; - velements[attr].instance_divisor = array->InstanceDivisor; - velements[attr].vertex_buffer_index = 0; - velements[attr].src_format = st_pipe_vertex_format(array->Type, - array->Size, - array->Format, - array->Normalized, - array->Integer); - assert(velements[attr].src_format); + src_format = st_pipe_vertex_format(array->Type, + array->Size, + array->Format, + array->Normalized, + array->Integer); + + init_velement_lowered(st, velements, src_offset, src_format, + array->InstanceDivisor, 0, + array->Size, array->Doubles, &attr_idx); } + *num_velements = attr_idx; + /* * Return the vbuffer info and setup user-space attrib info, if needed. */ @@ -472,17 +553,25 @@ setup_non_interleaved_attribs(struct st_context *st, const struct st_vp_variant *vpv, const struct gl_client_array **arrays, struct pipe_vertex_buffer vbuffer[], - struct pipe_vertex_element velements[]) + struct pipe_vertex_element velements[], + unsigned *num_velements) { struct gl_context *ctx = st->ctx; - GLuint attr; + GLuint attr, attr_idx = 0; for (attr = 0; attr < vpv->num_inputs; attr++) { const GLuint mesaAttr = vp->index_to_input[attr]; - const struct gl_client_array *array = arrays[mesaAttr]; - struct gl_buffer_object *bufobj = array->BufferObj; - GLsizei stride = array->StrideB; + const struct gl_client_array *array; + struct gl_buffer_object *bufobj; + GLsizei stride; + unsigned src_format; + array = get_client_array(vp, arrays, attr); + if (!array) + continue; + + stride = array->StrideB; + bufobj = array->BufferObj; assert(array->_ElementSize == _mesa_bytes_per_vertex_attrib(array->Size, array->Type)); @@ -524,16 +613,19 @@ setup_non_interleaved_attribs(struct st_context *st, /* common-case setup */ vbuffer[attr].stride = stride; /* in bytes */ - velements[attr].src_offset = 0; - velements[attr].instance_divisor = array->InstanceDivisor; - velements[attr].vertex_buffer_index = attr; - velements[attr].src_format = st_pipe_vertex_format(array->Type, - array->Size, - array->Format, - array->Normalized, - array->Integer); - assert(velements[attr].src_format); + src_format = st_pipe_vertex_format(array->Type, + array->Size, + array->Format, + array->Normalized, + array->Integer); + + init_velement_lowered(st, velements, 0, src_format, + array->InstanceDivisor, attr, + array->Size, array->Doubles, &attr_idx); + } + + *num_velements = attr_idx; return TRUE; } @@ -563,25 +655,23 @@ static void update_array(struct st_context *st) * Setup the vbuffer[] and velements[] arrays. */ if (is_interleaved_arrays(vp, vpv, arrays)) { - if (!setup_interleaved_attribs(vp, vpv, arrays, vbuffer, velements)) { + if (!setup_interleaved_attribs(st, vp, vpv, arrays, vbuffer, velements, &num_velements)) { st->vertex_array_out_of_memory = TRUE; return; } num_vbuffers = 1; - num_velements = vpv->num_inputs; if (num_velements == 0) num_vbuffers = 0; } else { if (!setup_non_interleaved_attribs(st, vp, vpv, arrays, vbuffer, - velements)) { + velements, &num_velements)) { st->vertex_array_out_of_memory = TRUE; return; } num_vbuffers = vpv->num_inputs; - num_velements = vpv->num_inputs; } cso_set_vertex_buffers(st->cso_context, 0, num_vbuffers, vbuffer); diff --git a/mesalib/src/mesa/state_tracker/st_atom_framebuffer.c b/mesalib/src/mesa/state_tracker/st_atom_framebuffer.c index b195c55b3..ae883a253 100644 --- a/mesalib/src/mesa/state_tracker/st_atom_framebuffer.c +++ b/mesalib/src/mesa/state_tracker/st_atom_framebuffer.c @@ -134,7 +134,10 @@ update_framebuffer_state( struct st_context *st ) else { strb = st_renderbuffer(fb->Attachment[BUFFER_STENCIL].Renderbuffer); if (strb) { - assert(strb->surface); + if (strb->is_rtt) { + /* rendering to a GL texture, may have to update surface */ + st_update_renderbuffer_surface(st, strb); + } pipe_surface_reference(&framebuffer->zsbuf, strb->surface); update_framebuffer_size(framebuffer, strb->surface); } diff --git a/mesalib/src/mesa/state_tracker/st_cb_fbo.c b/mesalib/src/mesa/state_tracker/st_cb_fbo.c index 296ea1e0d..0399eef72 100644 --- a/mesalib/src/mesa/state_tracker/st_cb_fbo.c +++ b/mesalib/src/mesa/state_tracker/st_cb_fbo.c @@ -842,7 +842,7 @@ void st_init_fbo_functions(struct dd_function_table *functions) functions->NewFramebuffer = st_new_framebuffer; functions->NewRenderbuffer = st_new_renderbuffer; functions->BindFramebuffer = st_bind_framebuffer; - functions->FramebufferRenderbuffer = _mesa_framebuffer_renderbuffer; + functions->FramebufferRenderbuffer = _mesa_FramebufferRenderbuffer_sw; functions->RenderTexture = st_render_texture; functions->FinishRenderTexture = st_finish_render_texture; functions->ValidateFramebuffer = st_validate_framebuffer; diff --git a/mesalib/src/mesa/state_tracker/st_cb_flush.c b/mesalib/src/mesa/state_tracker/st_cb_flush.c index ca51eeee3..82affd2de 100644 --- a/mesalib/src/mesa/state_tracker/st_cb_flush.c +++ b/mesalib/src/mesa/state_tracker/st_cb_flush.c @@ -141,11 +141,44 @@ static void st_glFinish(struct gl_context *ctx) } -void st_init_flush_functions(struct dd_function_table *functions) +/** + * Query information about GPU resets observed by this context + * + * Called via \c dd_function_table::GetGraphicsResetStatus. + */ +static GLenum +st_get_graphics_reset_status(struct gl_context *ctx) +{ + struct st_context *st = st_context(ctx); + enum pipe_reset_status status; + + status = st->pipe->get_device_reset_status(st->pipe); + + switch (status) { + case PIPE_NO_RESET: + return GL_NO_ERROR; + case PIPE_GUILTY_CONTEXT_RESET: + return GL_GUILTY_CONTEXT_RESET_ARB; + case PIPE_INNOCENT_CONTEXT_RESET: + return GL_INNOCENT_CONTEXT_RESET_ARB; + case PIPE_UNKNOWN_CONTEXT_RESET: + return GL_UNKNOWN_CONTEXT_RESET_ARB; + default: + assert(0); + return GL_NO_ERROR; + } +} + + +void st_init_flush_functions(struct pipe_screen *screen, + struct dd_function_table *functions) { functions->Flush = st_glFlush; functions->Finish = st_glFinish; + if (screen->get_param(screen, PIPE_CAP_DEVICE_RESET_STATUS_QUERY)) + functions->GetGraphicsResetStatus = st_get_graphics_reset_status; + /* Windows opengl32.dll calls glFinish prior to every swapbuffers. * This is unnecessary and degrades performance. Luckily we have some * scope to work around this, as the externally-visible behaviour of diff --git a/mesalib/src/mesa/state_tracker/st_cb_flush.h b/mesalib/src/mesa/state_tracker/st_cb_flush.h index 84ffc63ae..f92dcd56b 100644 --- a/mesalib/src/mesa/state_tracker/st_cb_flush.h +++ b/mesalib/src/mesa/state_tracker/st_cb_flush.h @@ -37,7 +37,8 @@ struct pipe_fence_handle; struct st_context; extern void -st_init_flush_functions(struct dd_function_table *functions); +st_init_flush_functions(struct pipe_screen *screen, + struct dd_function_table *functions); extern void st_flush(struct st_context *st, diff --git a/mesalib/src/mesa/state_tracker/st_cb_perfmon.c b/mesalib/src/mesa/state_tracker/st_cb_perfmon.c new file mode 100644 index 000000000..1bb5be397 --- /dev/null +++ b/mesalib/src/mesa/state_tracker/st_cb_perfmon.c @@ -0,0 +1,425 @@ +/* + * Copyright (C) 2013 Christoph Bumiller + * Copyright (C) 2015 Samuel Pitoiset + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * Performance monitoring counters interface to gallium. + */ + +#include "st_debug.h" +#include "st_context.h" +#include "st_cb_bitmap.h" +#include "st_cb_perfmon.h" + +#include "util/bitset.h" + +#include "pipe/p_context.h" +#include "pipe/p_screen.h" +#include "util/u_memory.h" + +/** + * Return a PIPE_QUERY_x type >= PIPE_QUERY_DRIVER_SPECIFIC, or -1 if + * the driver-specific query doesn't exist. + */ +static int +find_query_type(struct pipe_screen *screen, const char *name) +{ + int num_queries; + int type = -1; + int i; + + num_queries = screen->get_driver_query_info(screen, 0, NULL); + if (!num_queries) + return type; + + for (i = 0; i < num_queries; i++) { + struct pipe_driver_query_info info; + + if (!screen->get_driver_query_info(screen, i, &info)) + continue; + + if (!strncmp(info.name, name, strlen(name))) { + type = info.query_type; + break; + } + } + return type; +} + +/** + * Return TRUE if the underlying driver expose GPU counters. + */ +static bool +has_gpu_counters(struct pipe_screen *screen) +{ + int num_groups, gid; + + num_groups = screen->get_driver_query_group_info(screen, 0, NULL); + for (gid = 0; gid < num_groups; gid++) { + struct pipe_driver_query_group_info group_info; + + if (!screen->get_driver_query_group_info(screen, gid, &group_info)) + continue; + + if (group_info.type == PIPE_DRIVER_QUERY_GROUP_TYPE_GPU) + return true; + } + return false; +} + +static bool +init_perf_monitor(struct gl_context *ctx, struct gl_perf_monitor_object *m) +{ + struct st_perf_monitor_object *stm = st_perf_monitor_object(m); + struct pipe_screen *screen = st_context(ctx)->pipe->screen; + struct pipe_context *pipe = st_context(ctx)->pipe; + int gid, cid; + + st_flush_bitmap_cache(st_context(ctx)); + + /* Create a query for each active counter. */ + for (gid = 0; gid < ctx->PerfMonitor.NumGroups; gid++) { + const struct gl_perf_monitor_group *g = &ctx->PerfMonitor.Groups[gid]; + + if (m->ActiveGroups[gid] > g->MaxActiveCounters) { + /* Maximum number of counters reached. Cannot start the session. */ + if (ST_DEBUG & DEBUG_MESA) { + debug_printf("Maximum number of counters reached. " + "Cannot start the session!\n"); + } + return false; + } + + for (cid = 0; cid < g->NumCounters; cid++) { + const struct gl_perf_monitor_counter *c = &g->Counters[cid]; + struct st_perf_counter_object *cntr; + int query_type; + + if (!BITSET_TEST(m->ActiveCounters[gid], cid)) + continue; + + query_type = find_query_type(screen, c->Name); + assert(query_type != -1); + + cntr = CALLOC_STRUCT(st_perf_counter_object); + if (!cntr) + return false; + + cntr->query = pipe->create_query(pipe, query_type, 0); + cntr->id = cid; + cntr->group_id = gid; + + list_addtail(&cntr->list, &stm->active_counters); + } + } + return true; +} + +static void +reset_perf_monitor(struct st_perf_monitor_object *stm, + struct pipe_context *pipe) +{ + struct st_perf_counter_object *cntr, *tmp; + + LIST_FOR_EACH_ENTRY_SAFE(cntr, tmp, &stm->active_counters, list) { + if (cntr->query) + pipe->destroy_query(pipe, cntr->query); + list_del(&cntr->list); + free(cntr); + } +} + +static struct gl_perf_monitor_object * +st_NewPerfMonitor(struct gl_context *ctx) +{ + struct st_perf_monitor_object *stq = ST_CALLOC_STRUCT(st_perf_monitor_object); + if (stq) { + list_inithead(&stq->active_counters); + return &stq->base; + } + return NULL; +} + +static void +st_DeletePerfMonitor(struct gl_context *ctx, struct gl_perf_monitor_object *m) +{ + struct st_perf_monitor_object *stm = st_perf_monitor_object(m); + struct pipe_context *pipe = st_context(ctx)->pipe; + + reset_perf_monitor(stm, pipe); + FREE(stm); +} + +static GLboolean +st_BeginPerfMonitor(struct gl_context *ctx, struct gl_perf_monitor_object *m) +{ + struct st_perf_monitor_object *stm = st_perf_monitor_object(m); + struct pipe_context *pipe = st_context(ctx)->pipe; + struct st_perf_counter_object *cntr; + + if (LIST_IS_EMPTY(&stm->active_counters)) { + /* Create a query for each active counter before starting + * a new monitoring session. */ + if (!init_perf_monitor(ctx, m)) + goto fail; + } + + /* Start the query for each active counter. */ + LIST_FOR_EACH_ENTRY(cntr, &stm->active_counters, list) { + if (!pipe->begin_query(pipe, cntr->query)) + goto fail; + } + return true; + +fail: + /* Failed to start the monitoring session. */ + reset_perf_monitor(stm, pipe); + return false; +} + +static void +st_EndPerfMonitor(struct gl_context *ctx, struct gl_perf_monitor_object *m) +{ + struct st_perf_monitor_object *stm = st_perf_monitor_object(m); + struct pipe_context *pipe = st_context(ctx)->pipe; + struct st_perf_counter_object *cntr; + + /* Stop the query for each active counter. */ + LIST_FOR_EACH_ENTRY(cntr, &stm->active_counters, list) + pipe->end_query(pipe, cntr->query); +} + +static void +st_ResetPerfMonitor(struct gl_context *ctx, struct gl_perf_monitor_object *m) +{ + struct st_perf_monitor_object *stm = st_perf_monitor_object(m); + struct pipe_context *pipe = st_context(ctx)->pipe; + + if (!m->Ended) + st_EndPerfMonitor(ctx, m); + + reset_perf_monitor(stm, pipe); + + if (m->Active) + st_BeginPerfMonitor(ctx, m); +} + +static GLboolean +st_IsPerfMonitorResultAvailable(struct gl_context *ctx, + struct gl_perf_monitor_object *m) +{ + struct st_perf_monitor_object *stm = st_perf_monitor_object(m); + struct pipe_context *pipe = st_context(ctx)->pipe; + struct st_perf_counter_object *cntr; + + if (LIST_IS_EMPTY(&stm->active_counters)) + return false; + + /* The result of a monitoring session is only available if the query of + * each active counter is idle. */ + LIST_FOR_EACH_ENTRY(cntr, &stm->active_counters, list) { + union pipe_query_result result; + if (!pipe->get_query_result(pipe, cntr->query, FALSE, &result)) { + /* The query is busy. */ + return false; + } + } + return true; +} + +static void +st_GetPerfMonitorResult(struct gl_context *ctx, + struct gl_perf_monitor_object *m, + GLsizei dataSize, + GLuint *data, + GLint *bytesWritten) +{ + struct st_perf_monitor_object *stm = st_perf_monitor_object(m); + struct pipe_context *pipe = st_context(ctx)->pipe; + struct st_perf_counter_object *cntr; + + /* Copy data to the supplied array (data). + * + * The output data format is: <group ID, counter ID, value> for each + * active counter. The API allows counters to appear in any order. + */ + GLsizei offset = 0; + + /* Read query results for each active counter. */ + LIST_FOR_EACH_ENTRY(cntr, &stm->active_counters, list) { + union pipe_query_result result = { 0 }; + int gid, cid; + GLenum type; + + cid = cntr->id; + gid = cntr->group_id; + type = ctx->PerfMonitor.Groups[gid].Counters[cid].Type; + + if (!pipe->get_query_result(pipe, cntr->query, TRUE, &result)) + continue; + + data[offset++] = gid; + data[offset++] = cid; + switch (type) { + case GL_UNSIGNED_INT64_AMD: + *(uint64_t *)&data[offset] = result.u64; + offset += sizeof(uint64_t) / sizeof(GLuint); + break; + case GL_UNSIGNED_INT: + *(uint32_t *)&data[offset] = result.u32; + offset += sizeof(uint32_t) / sizeof(GLuint); + break; + case GL_FLOAT: + case GL_PERCENTAGE_AMD: + *(GLfloat *)&data[offset] = result.f; + offset += sizeof(GLfloat) / sizeof(GLuint); + break; + } + } + + if (bytesWritten) + *bytesWritten = offset * sizeof(GLuint); +} + + +bool +st_init_perfmon(struct st_context *st) +{ + struct gl_perf_monitor_state *perfmon = &st->ctx->PerfMonitor; + struct pipe_screen *screen = st->pipe->screen; + struct gl_perf_monitor_group *groups = NULL; + int num_counters, num_groups; + int gid, cid; + + if (!screen->get_driver_query_info || !screen->get_driver_query_group_info) + return false; + + if (!has_gpu_counters(screen)) { + /* According to the spec, GL_AMD_performance_monitor must only + * expose GPU counters. */ + return false; + } + + /* Get the number of available queries. */ + num_counters = screen->get_driver_query_info(screen, 0, NULL); + if (!num_counters) + return false; + + /* Get the number of available groups. */ + num_groups = screen->get_driver_query_group_info(screen, 0, NULL); + if (num_groups) + groups = CALLOC(num_groups, sizeof(*groups)); + if (!groups) + return false; + + for (gid = 0; gid < num_groups; gid++) { + struct gl_perf_monitor_group *g = &groups[perfmon->NumGroups]; + struct pipe_driver_query_group_info group_info; + struct gl_perf_monitor_counter *counters = NULL; + + if (!screen->get_driver_query_group_info(screen, gid, &group_info)) + continue; + + if (group_info.type != PIPE_DRIVER_QUERY_GROUP_TYPE_GPU) + continue; + + g->Name = group_info.name; + g->MaxActiveCounters = group_info.max_active_queries; + g->NumCounters = 0; + g->Counters = NULL; + + if (group_info.num_queries) + counters = CALLOC(group_info.num_queries, sizeof(*counters)); + if (!counters) + goto fail; + + for (cid = 0; cid < num_counters; cid++) { + struct gl_perf_monitor_counter *c = &counters[g->NumCounters]; + struct pipe_driver_query_info info; + + if (!screen->get_driver_query_info(screen, cid, &info)) + continue; + if (info.group_id != gid) + continue; + + c->Name = info.name; + switch (info.type) { + case PIPE_DRIVER_QUERY_TYPE_UINT64: + c->Minimum.u64 = 0; + c->Maximum.u64 = info.max_value.u64 ? info.max_value.u64 : -1; + c->Type = GL_UNSIGNED_INT64_AMD; + break; + case PIPE_DRIVER_QUERY_TYPE_UINT: + c->Minimum.u32 = 0; + c->Maximum.u32 = info.max_value.u32 ? info.max_value.u32 : -1; + c->Type = GL_UNSIGNED_INT; + break; + case PIPE_DRIVER_QUERY_TYPE_FLOAT: + c->Minimum.f = 0.0; + c->Maximum.f = info.max_value.f ? info.max_value.f : -1; + c->Type = GL_FLOAT; + break; + case PIPE_DRIVER_QUERY_TYPE_PERCENTAGE: + c->Minimum.f = 0.0f; + c->Maximum.f = 100.0f; + c->Type = GL_PERCENTAGE_AMD; + break; + default: + unreachable("Invalid driver query type!"); + } + g->NumCounters++; + } + g->Counters = counters; + perfmon->NumGroups++; + } + perfmon->Groups = groups; + + return true; + +fail: + for (gid = 0; gid < num_groups; gid++) + FREE((void *)groups[gid].Counters); + FREE(groups); + return false; +} + +void +st_destroy_perfmon(struct st_context *st) +{ + struct gl_perf_monitor_state *perfmon = &st->ctx->PerfMonitor; + int gid; + + for (gid = 0; gid < perfmon->NumGroups; gid++) + FREE((void *)perfmon->Groups[gid].Counters); + FREE((void *)perfmon->Groups); +} + +void st_init_perfmon_functions(struct dd_function_table *functions) +{ + functions->NewPerfMonitor = st_NewPerfMonitor; + functions->DeletePerfMonitor = st_DeletePerfMonitor; + functions->BeginPerfMonitor = st_BeginPerfMonitor; + functions->EndPerfMonitor = st_EndPerfMonitor; + functions->ResetPerfMonitor = st_ResetPerfMonitor; + functions->IsPerfMonitorResultAvailable = st_IsPerfMonitorResultAvailable; + functions->GetPerfMonitorResult = st_GetPerfMonitorResult; +} diff --git a/mesalib/src/mesa/state_tracker/st_cb_perfmon.h b/mesalib/src/mesa/state_tracker/st_cb_perfmon.h new file mode 100644 index 000000000..13d3627de --- /dev/null +++ b/mesalib/src/mesa/state_tracker/st_cb_perfmon.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2013 Christoph Bumiller + * Copyright (C) 2015 Samuel Pitoiset + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef ST_CB_PERFMON_H +#define ST_CB_PERFMON_H + +#include "util/list.h" + +/** + * Subclass of gl_perf_monitor_object + */ +struct st_perf_monitor_object +{ + struct gl_perf_monitor_object base; + struct list_head active_counters; +}; + +struct st_perf_counter_object +{ + struct list_head list; + struct pipe_query *query; + int id; + int group_id; +}; + +/** + * Cast wrapper + */ +static INLINE struct st_perf_monitor_object * +st_perf_monitor_object(struct gl_perf_monitor_object *q) +{ + return (struct st_perf_monitor_object *)q; +} + +bool +st_init_perfmon(struct st_context *st); + +void +st_destroy_perfmon(struct st_context *st); + +extern void +st_init_perfmon_functions(struct dd_function_table *functions); + +#endif diff --git a/mesalib/src/mesa/state_tracker/st_context.c b/mesalib/src/mesa/state_tracker/st_context.c index 5fe132ac2..69e0f929d 100644 --- a/mesalib/src/mesa/state_tracker/st_context.c +++ b/mesalib/src/mesa/state_tracker/st_context.c @@ -51,6 +51,7 @@ #include "st_cb_fbo.h" #include "st_cb_feedback.h" #include "st_cb_msaa.h" +#include "st_cb_perfmon.h" #include "st_cb_program.h" #include "st_cb_queryobj.h" #include "st_cb_readpixels.h" @@ -116,6 +117,7 @@ st_destroy_context_priv(struct st_context *st) st_destroy_bitmap(st); st_destroy_drawpix(st); st_destroy_drawtex(st); + st_destroy_perfmon(st); for (shader = 0; shader < ARRAY_SIZE(st->state.sampler_views); shader++) { for (i = 0; i < ARRAY_SIZE(st->state.sampler_views[0]); i++) { @@ -250,6 +252,12 @@ st_create_context_priv( struct gl_context *ctx, struct pipe_context *pipe, st_init_extensions(st->pipe->screen, &ctx->Const, &ctx->Extensions, &st->options, ctx->Mesa_DXTn); + if (st_init_perfmon(st)) { + /* GL_AMD_performance_monitor is only enabled when the underlying + * driver expose GPU hardware performance counters. */ + ctx->Extensions.AMD_performance_monitor = GL_TRUE; + } + /* Enable shader-based fallbacks for ARB_color_buffer_float if needed. */ if (screen->get_param(screen, PIPE_CAP_VERTEX_COLOR_UNCLAMPED)) { if (!screen->get_param(screen, PIPE_CAP_VERTEX_COLOR_CLAMPED)) { @@ -313,7 +321,7 @@ struct st_context *st_create_context(gl_api api, struct pipe_context *pipe, struct st_context *st; memset(&funcs, 0, sizeof(funcs)); - st_init_driver_functions(&funcs); + st_init_driver_functions(pipe->screen, &funcs); ctx = _mesa_create_context(api, visual, shareCtx, &funcs); if (!ctx) { @@ -393,7 +401,8 @@ void st_destroy_context( struct st_context *st ) } -void st_init_driver_functions(struct dd_function_table *functions) +void st_init_driver_functions(struct pipe_screen *screen, + struct dd_function_table *functions) { _mesa_init_shader_object_functions(functions); _mesa_init_sampler_object_functions(functions); @@ -414,13 +423,14 @@ void st_init_driver_functions(struct dd_function_table *functions) st_init_fbo_functions(functions); st_init_feedback_functions(functions); st_init_msaa_functions(functions); + st_init_perfmon_functions(functions); st_init_program_functions(functions); st_init_query_functions(functions); st_init_cond_render_functions(functions); st_init_readpixels_functions(functions); st_init_texture_functions(functions); st_init_texture_barrier_functions(functions); - st_init_flush_functions(functions); + st_init_flush_functions(screen, functions); st_init_string_functions(functions); st_init_viewport_functions(functions); diff --git a/mesalib/src/mesa/state_tracker/st_context.h b/mesalib/src/mesa/state_tracker/st_context.h index 8a9504bb7..dac5a4b90 100644 --- a/mesalib/src/mesa/state_tracker/st_context.h +++ b/mesalib/src/mesa/state_tracker/st_context.h @@ -237,7 +237,8 @@ struct st_framebuffer }; -extern void st_init_driver_functions(struct dd_function_table *functions); +extern void st_init_driver_functions(struct pipe_screen *screen, + struct dd_function_table *functions); void st_invalidate_state(struct gl_context * ctx, GLuint new_state); diff --git a/mesalib/src/mesa/state_tracker/st_extensions.c b/mesalib/src/mesa/state_tracker/st_extensions.c index 82e4a3009..23a45883d 100644 --- a/mesalib/src/mesa/state_tracker/st_extensions.c +++ b/mesalib/src/mesa/state_tracker/st_extensions.c @@ -650,6 +650,12 @@ void st_init_extensions(struct pipe_screen *screen, ARRAY_SIZE(vertex_mapping), PIPE_BUFFER, PIPE_BIND_VERTEX_BUFFER); + /* ARB_direct_state_access requires OpenGL 2.0. Assume that all drivers + * that support NPOT textures are able to support GL 2.0. + */ + if (extensions->ARB_texture_non_power_of_two) + extensions->ARB_direct_state_access = GL_TRUE; + if (extensions->ARB_stencil_texturing) extensions->ARB_texture_stencil8 = GL_TRUE; @@ -909,6 +915,8 @@ void st_init_extensions(struct pipe_screen *screen, if (screen->get_shader_param(screen, PIPE_SHADER_VERTEX, PIPE_SHADER_CAP_DOUBLES) && screen->get_shader_param(screen, PIPE_SHADER_FRAGMENT, - PIPE_SHADER_CAP_DOUBLES)) + PIPE_SHADER_CAP_DOUBLES)) { extensions->ARB_gpu_shader_fp64 = GL_TRUE; + extensions->ARB_vertex_attrib_64bit = GL_TRUE; + } } diff --git a/mesalib/src/mesa/state_tracker/st_format.c b/mesalib/src/mesa/state_tracker/st_format.c index 181465dd8..db7b5b71d 100644 --- a/mesalib/src/mesa/state_tracker/st_format.c +++ b/mesalib/src/mesa/state_tracker/st_format.c @@ -991,7 +991,7 @@ static const struct format_mapping format_map[] = { { { GL_RGB10, 0 }, { PIPE_FORMAT_B10G10R10X2_UNORM, PIPE_FORMAT_B10G10R10A2_UNORM, - DEFAULT_RGB_FORMATS } + PIPE_FORMAT_R10G10B10A2_UNORM, DEFAULT_RGB_FORMATS } }, { { GL_RGB10_A2, 0 }, 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 93671ba9c..f0f2a77d0 100644 --- a/mesalib/src/mesa/state_tracker/st_glsl_to_tgsi.cpp +++ b/mesalib/src/mesa/state_tracker/st_glsl_to_tgsi.cpp @@ -88,6 +88,7 @@ public: this->reladdr = NULL; this->reladdr2 = NULL; this->has_index2 = false; + this->double_reg2 = false; } st_src_reg(gl_register_file file, int index, int type) @@ -101,6 +102,7 @@ public: this->reladdr = NULL; this->reladdr2 = NULL; this->has_index2 = false; + this->double_reg2 = false; } st_src_reg(gl_register_file file, int index, int type, int index2D) @@ -114,6 +116,7 @@ public: this->reladdr = NULL; this->reladdr2 = NULL; this->has_index2 = false; + this->double_reg2 = false; } st_src_reg() @@ -127,6 +130,7 @@ public: this->reladdr = NULL; this->reladdr2 = NULL; this->has_index2 = false; + this->double_reg2 = false; } explicit st_src_reg(st_dst_reg reg); @@ -141,6 +145,11 @@ public: st_src_reg *reladdr; st_src_reg *reladdr2; bool has_index2; + /* + * Is this the second half of a double register pair? + * currently used for input mapping only. + */ + bool double_reg2; }; class st_dst_reg { @@ -197,6 +206,7 @@ st_src_reg::st_src_reg(st_dst_reg reg) this->index2D = 0; this->reladdr2 = NULL; this->has_index2 = false; + this->double_reg2 = false; } st_dst_reg::st_dst_reg(st_src_reg reg) @@ -677,8 +687,10 @@ glsl_to_tgsi_visitor::emit(ir_instruction *ir, unsigned op, if (dinst->src[j].type == GLSL_TYPE_DOUBLE) { dinst->src[j].index = initial_src_idx[j]; - if (swz > 1) + if (swz > 1) { + dinst->src[j].double_reg2 = true; dinst->src[j].index++; + } if (swz & 1) dinst->src[j].swizzle = MAKE_SWIZZLE4(SWIZZLE_Z, SWIZZLE_W, SWIZZLE_Z, SWIZZLE_W); @@ -1941,7 +1953,7 @@ glsl_to_tgsi_visitor::visit(ir_expression *ir) break; case ir_unop_i2b: if (native_integers) - emit(ir, TGSI_OPCODE_INEG, result_dst, op[0]); + emit(ir, TGSI_OPCODE_USNE, result_dst, op[0], st_src_reg_for_int(0)); else emit(ir, TGSI_OPCODE_SNE, result_dst, op[0], st_src_reg_for_float(0.0)); break; @@ -2611,6 +2623,7 @@ glsl_to_tgsi_visitor::visit(ir_assignment *ir) assert(!ir->lhs->type->is_scalar() && !ir->lhs->type->is_vector()); l.writemask = WRITEMASK_XYZW; } else if (ir->lhs->type->is_scalar() && + !ir->lhs->type->is_double() && ir->lhs->variable_referenced()->data.mode == ir_var_shader_out) { /* FINISHME: This hack makes writing to gl_FragDepth, which lives in the * FINISHME: W component of fragment shader output zero, work correctly. @@ -3704,6 +3717,7 @@ glsl_to_tgsi_visitor::copy_propagate(void) } else { if (first->src[0].file != copy_chan->src[0].file || first->src[0].index != copy_chan->src[0].index || + first->src[0].double_reg2 != copy_chan->src[0].double_reg2 || first->src[0].index2D != copy_chan->src[0].index2D) { good = false; break; @@ -3719,6 +3733,7 @@ glsl_to_tgsi_visitor::copy_propagate(void) inst->src[r].index = first->src[0].index; inst->src[r].index2D = first->src[0].index2D; inst->src[r].has_index2 = first->src[0].has_index2; + inst->src[r].double_reg2 = first->src[0].double_reg2; int swizzle = 0; for (int i = 0; i < 4; i++) { @@ -4551,6 +4566,9 @@ dst_register(struct st_translate *t, static struct ureg_src src_register(struct st_translate *t, const st_src_reg *reg) { + int index = reg->index; + int double_reg2 = reg->double_reg2 ? 1 : 0; + switch(reg->file) { case PROGRAM_UNDEFINED: return ureg_imm4f(t->ureg, 0, 0, 0, 0); @@ -4576,8 +4594,12 @@ src_register(struct st_translate *t, const st_src_reg *reg) return t->immediates[reg->index]; case PROGRAM_INPUT: - assert(t->inputMapping[reg->index] < ARRAY_SIZE(t->inputs)); - return t->inputs[t->inputMapping[reg->index]]; + /* GLSL inputs are 64-bit containers, so we have to + * map back to the original index and add the offset after + * mapping. */ + index -= double_reg2; + assert(t->inputMapping[index] < ARRAY_SIZE(t->inputs)); + return t->inputs[t->inputMapping[index] + double_reg2]; case PROGRAM_OUTPUT: assert(t->outputMapping[reg->index] < ARRAY_SIZE(t->outputs)); diff --git a/mesalib/src/mesa/state_tracker/st_manager.c b/mesalib/src/mesa/state_tracker/st_manager.c index 840f76a13..0376954f7 100644 --- a/mesalib/src/mesa/state_tracker/st_manager.c +++ b/mesalib/src/mesa/state_tracker/st_manager.c @@ -680,6 +680,10 @@ st_api_create_context(struct st_api *stapi, struct st_manager *smapi, if (attribs->flags & ST_CONTEXT_FLAG_FORWARD_COMPATIBLE) st->ctx->Const.ContextFlags |= GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT; + if (attribs->flags & ST_CONTEXT_FLAG_ROBUST_ACCESS) + st->ctx->Const.ContextFlags |= GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT_ARB; + if (attribs->flags & ST_CONTEXT_FLAG_RESET_NOTIFICATION_ENABLED) + st->ctx->Const.ResetStrategy = GL_LOSE_CONTEXT_ON_RESET_ARB; /* need to perform version check */ if (attribs->major > 1 || attribs->minor > 0) { diff --git a/mesalib/src/mesa/state_tracker/st_program.c b/mesalib/src/mesa/state_tracker/st_program.c index d93b3c7bc..a9110d3c6 100644 --- a/mesalib/src/mesa/state_tracker/st_program.c +++ b/mesalib/src/mesa/state_tracker/st_program.c @@ -194,6 +194,11 @@ st_prepare_vertex_program(struct gl_context *ctx, stvp->input_to_index[attr] = stvp->num_inputs; stvp->index_to_input[stvp->num_inputs] = attr; stvp->num_inputs++; + if ((stvp->Base.Base.DoubleInputsRead & BITFIELD64_BIT(attr)) != 0) { + /* add placeholder for second part of a double attribute */ + stvp->index_to_input[stvp->num_inputs] = ST_DOUBLE_ATTRIB_PLACEHOLDER; + stvp->num_inputs++; + } } } /* bit of a hack, presetup potentially unused edgeflag input */ diff --git a/mesalib/src/mesa/state_tracker/st_program.h b/mesalib/src/mesa/state_tracker/st_program.h index b2c86faec..a2c56062d 100644 --- a/mesalib/src/mesa/state_tracker/st_program.h +++ b/mesalib/src/mesa/state_tracker/st_program.h @@ -45,6 +45,7 @@ extern "C" { #endif +#define ST_DOUBLE_ATTRIB_PLACEHOLDER 0xffffffff /** Fragment program variant key */ struct st_fp_variant_key diff --git a/mesalib/src/mesa/swrast/s_drawpix.c b/mesalib/src/mesa/swrast/s_drawpix.c index bf427266c..fb677ee1b 100644 --- a/mesalib/src/mesa/swrast/s_drawpix.c +++ b/mesalib/src/mesa/swrast/s_drawpix.c @@ -448,14 +448,34 @@ draw_rgba_pixels( struct gl_context *ctx, GLint x, GLint y, { const GLbitfield interpMask = span.interpMask; const GLbitfield arrayMask = span.arrayMask; - const GLint srcStride - = _mesa_image_row_stride(unpack, width, format, type); GLint skipPixels = 0; /* use span array for temp color storage */ GLfloat *rgba = (GLfloat *) span.array->attribs[VARYING_SLOT_COL0]; void *tempImage = NULL; - if (unpack->SwapBytes) { + /* We have to deal with GL_COLOR_INDEX manually because + * _mesa_format_convert does not handle this format. So what we do here is + * convert it to RGBA ubyte first and then convert from that to dst as + * usual. + */ + if (format == GL_COLOR_INDEX) { + /* This will handle byte swapping and transferops if needed */ + tempImage = + _mesa_unpack_color_index_to_rgba_ubyte(ctx, 2, + pixels, format, type, + width, height, 1, + unpack, + transferOps); + if (!tempImage) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDrawPixels"); + return; + } + + transferOps = 0; + pixels = tempImage; + format = GL_RGBA; + type = GL_UNSIGNED_BYTE; + } else if (unpack->SwapBytes) { /* We have to handle byte-swapping scenarios before calling * _mesa_format_convert */ @@ -476,6 +496,9 @@ draw_rgba_pixels( struct gl_context *ctx, GLint x, GLint y, } } + const GLint srcStride + = _mesa_image_row_stride(unpack, width, format, type); + /* if the span is wider than SWRAST_MAX_WIDTH we have to do it in chunks */ while (skipPixels < width) { const GLint spanWidth = MIN2(width - skipPixels, SWRAST_MAX_WIDTH); diff --git a/mesalib/src/mesa/swrast/s_texrender.c b/mesalib/src/mesa/swrast/s_texrender.c index fa853c919..4e41b3b72 100644 --- a/mesalib/src/mesa/swrast/s_texrender.c +++ b/mesalib/src/mesa/swrast/s_texrender.c @@ -72,7 +72,7 @@ update_wrapper(struct gl_context *ctx, struct gl_renderbuffer_attachment *att) * \param fb the framebuffer object the texture is being bound to * \param att the fb attachment point of the texture * - * \sa _mesa_framebuffer_renderbuffer + * \sa _mesa_FramebufferRenderbuffer_sw */ void _swrast_render_texture(struct gl_context *ctx, diff --git a/mesalib/src/mesa/vbo/vbo_attrib_tmp.h b/mesalib/src/mesa/vbo/vbo_attrib_tmp.h index 17e057836..e73b8fb5f 100644 --- a/mesalib/src/mesa/vbo/vbo_attrib_tmp.h +++ b/mesalib/src/mesa/vbo/vbo_attrib_tmp.h @@ -31,14 +31,16 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. /* ATTR */ #define ATTRI( A, N, V0, V1, V2, V3 ) \ - ATTR_UNION(A, N, GL_INT, INT_AS_UNION(V0), INT_AS_UNION(V1), \ + ATTR_UNION(A, N, GL_INT, fi_type, INT_AS_UNION(V0), INT_AS_UNION(V1), \ INT_AS_UNION(V2), INT_AS_UNION(V3)) #define ATTRUI( A, N, V0, V1, V2, V3 ) \ - ATTR_UNION(A, N, GL_UNSIGNED_INT, UINT_AS_UNION(V0), UINT_AS_UNION(V1), \ + ATTR_UNION(A, N, GL_UNSIGNED_INT, fi_type, UINT_AS_UNION(V0), UINT_AS_UNION(V1), \ UINT_AS_UNION(V2), UINT_AS_UNION(V3)) #define ATTRF( A, N, V0, V1, V2, V3 ) \ - ATTR_UNION(A, N, GL_FLOAT, FLOAT_AS_UNION(V0), FLOAT_AS_UNION(V1),\ + ATTR_UNION(A, N, GL_FLOAT, fi_type, FLOAT_AS_UNION(V0), FLOAT_AS_UNION(V1),\ FLOAT_AS_UNION(V2), FLOAT_AS_UNION(V3)) +#define ATTRD( A, N, V0, V1, V2, V3 ) \ + ATTR_UNION(A, N, GL_DOUBLE, double, V0, V1, V2, V3) /* float */ @@ -232,6 +234,19 @@ static inline float conv_i2_to_norm_float(const struct gl_context *ctx, int i2) ERROR(GL_INVALID_VALUE); \ } while(0) + +/* Doubles */ +#define ATTR1DV( A, V ) ATTRD( A, 1, (V)[0], 0, 0, 1 ) +#define ATTR2DV( A, V ) ATTRD( A, 2, (V)[0], (V)[1], 0, 1 ) +#define ATTR3DV( A, V ) ATTRD( A, 3, (V)[0], (V)[1], (V)[2], 1 ) +#define ATTR4DV( A, V ) ATTRD( A, 4, (V)[0], (V)[1], (V)[2], (V)[3] ) + +#define ATTR1D( A, X ) ATTRD( A, 1, X, 0, 0, 1 ) +#define ATTR2D( A, X, Y ) ATTRD( A, 2, X, Y, 0, 1 ) +#define ATTR3D( A, X, Y, Z ) ATTRD( A, 3, X, Y, Z, 1 ) +#define ATTR4D( A, X, Y, Z, W ) ATTRD( A, 4, X, Y, Z, W ) + + static void GLAPIENTRY TAG(Vertex2f)(GLfloat x, GLfloat y) { @@ -1190,6 +1205,104 @@ TAG(VertexAttribP4uiv)(GLuint index, GLenum type, GLboolean normalized, } + +static void GLAPIENTRY +TAG(VertexAttribL1d)(GLuint index, GLdouble x) +{ + GET_CURRENT_CONTEXT(ctx); + if (index == 0 && _mesa_attr_zero_aliases_vertex(ctx)) + ATTR1D(0, x); + else if (index < MAX_VERTEX_GENERIC_ATTRIBS) + ATTR1D(VBO_ATTRIB_GENERIC0 + index, x); + else + ERROR(GL_INVALID_VALUE); +} + +static void GLAPIENTRY +TAG(VertexAttribL1dv)(GLuint index, const GLdouble * v) +{ + GET_CURRENT_CONTEXT(ctx); + if (index == 0 && _mesa_attr_zero_aliases_vertex(ctx)) + ATTR1DV(0, v); + else if (index < MAX_VERTEX_GENERIC_ATTRIBS) + ATTR1DV(VBO_ATTRIB_GENERIC0 + index, v); + else + ERROR(GL_INVALID_VALUE); +} + +static void GLAPIENTRY +TAG(VertexAttribL2d)(GLuint index, GLdouble x, GLdouble y) +{ + GET_CURRENT_CONTEXT(ctx); + if (index == 0 && _mesa_attr_zero_aliases_vertex(ctx)) + ATTR2D(0, x, y); + else if (index < MAX_VERTEX_GENERIC_ATTRIBS) + ATTR2D(VBO_ATTRIB_GENERIC0 + index, x, y); + else + ERROR(GL_INVALID_VALUE); +} + +static void GLAPIENTRY +TAG(VertexAttribL2dv)(GLuint index, const GLdouble * v) +{ + GET_CURRENT_CONTEXT(ctx); + if (index == 0 && _mesa_attr_zero_aliases_vertex(ctx)) + ATTR2DV(0, v); + else if (index < MAX_VERTEX_GENERIC_ATTRIBS) + ATTR2DV(VBO_ATTRIB_GENERIC0 + index, v); + else + ERROR(GL_INVALID_VALUE); +} + +static void GLAPIENTRY +TAG(VertexAttribL3d)(GLuint index, GLdouble x, GLdouble y, GLdouble z) +{ + GET_CURRENT_CONTEXT(ctx); + if (index == 0 && _mesa_attr_zero_aliases_vertex(ctx)) + ATTR3D(0, x, y, z); + else if (index < MAX_VERTEX_GENERIC_ATTRIBS) + ATTR3D(VBO_ATTRIB_GENERIC0 + index, x, y, z); + else + ERROR(GL_INVALID_VALUE); +} + +static void GLAPIENTRY +TAG(VertexAttribL3dv)(GLuint index, const GLdouble * v) +{ + GET_CURRENT_CONTEXT(ctx); + if (index == 0 && _mesa_attr_zero_aliases_vertex(ctx)) + ATTR3DV(0, v); + else if (index < MAX_VERTEX_GENERIC_ATTRIBS) + ATTR3DV(VBO_ATTRIB_GENERIC0 + index, v); + else + ERROR(GL_INVALID_VALUE); +} + +static void GLAPIENTRY +TAG(VertexAttribL4d)(GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w) +{ + GET_CURRENT_CONTEXT(ctx); + if (index == 0 && _mesa_attr_zero_aliases_vertex(ctx)) + ATTR4D(0, x, y, z, w); + else if (index < MAX_VERTEX_GENERIC_ATTRIBS) + ATTR4D(VBO_ATTRIB_GENERIC0 + index, x, y, z, w); + else + ERROR(GL_INVALID_VALUE); +} + +static void GLAPIENTRY +TAG(VertexAttribL4dv)(GLuint index, const GLdouble * v) +{ + GET_CURRENT_CONTEXT(ctx); + if (index == 0 && _mesa_attr_zero_aliases_vertex(ctx)) + ATTR4DV(0, v); + else if (index < MAX_VERTEX_GENERIC_ATTRIBS) + ATTR4DV(VBO_ATTRIB_GENERIC0 + index, v); + else + ERROR(GL_INVALID_VALUE); +} + + #undef ATTR1FV #undef ATTR2FV #undef ATTR3FV diff --git a/mesalib/src/mesa/vbo/vbo_context.h b/mesalib/src/mesa/vbo/vbo_context.h index 6099b56e6..a376efe34 100644 --- a/mesalib/src/mesa/vbo/vbo_context.h +++ b/mesalib/src/mesa/vbo/vbo_context.h @@ -146,6 +146,7 @@ vbo_attrtype_to_integer_flag(GLenum format) { switch (format) { case GL_FLOAT: + case GL_DOUBLE: return GL_FALSE; case GL_INT: case GL_UNSIGNED_INT: @@ -156,6 +157,22 @@ vbo_attrtype_to_integer_flag(GLenum format) } } +static inline GLboolean +vbo_attrtype_to_double_flag(GLenum format) +{ + switch (format) { + case GL_FLOAT: + case GL_INT: + case GL_UNSIGNED_INT: + return GL_FALSE; + case GL_DOUBLE: + return GL_TRUE; + default: + assert(0); + return GL_FALSE; + } +} + /** * Return default component values for the given format. * The return type is an array of fi_types, because that's how we declare diff --git a/mesalib/src/mesa/vbo/vbo_exec_api.c b/mesalib/src/mesa/vbo/vbo_exec_api.c index 48680ec88..138cd6051 100644 --- a/mesalib/src/mesa/vbo/vbo_exec_api.c +++ b/mesalib/src/mesa/vbo/vbo_exec_api.c @@ -159,27 +159,36 @@ static void vbo_exec_copy_to_current( struct vbo_exec_context *exec ) * ctx->Current.Attrib and ctx->Light.Material.Attrib arrays. */ GLfloat *current = (GLfloat *)vbo->currval[i].Ptr; - fi_type tmp[4]; + fi_type tmp[8]; /* space for doubles */ + int dmul = exec->vtx.attrtype[i] == GL_DOUBLE ? 2 : 1; + + if (exec->vtx.attrtype[i] == GL_DOUBLE) { + memset(tmp, 0, sizeof(tmp)); + memcpy(tmp, exec->vtx.attrptr[i], exec->vtx.attrsz[i] * sizeof(GLfloat)); + } else { + COPY_CLEAN_4V_TYPE_AS_UNION(tmp, + exec->vtx.attrsz[i], + exec->vtx.attrptr[i], + exec->vtx.attrtype[i]); + } - COPY_CLEAN_4V_TYPE_AS_UNION(tmp, - exec->vtx.attrsz[i], - exec->vtx.attrptr[i], - exec->vtx.attrtype[i]); - if (exec->vtx.attrtype[i] != vbo->currval[i].Type || - memcmp(current, tmp, sizeof(tmp)) != 0) { - memcpy(current, tmp, sizeof(tmp)); + memcmp(current, tmp, 4 * sizeof(GLfloat) * dmul) != 0) { + memcpy(current, tmp, 4 * sizeof(GLfloat) * dmul); /* Given that we explicitly state size here, there is no need * for the COPY_CLEAN above, could just copy 16 bytes and be * done. The only problem is when Mesa accesses ctx->Current * directly. */ - vbo->currval[i].Size = exec->vtx.attrsz[i]; - vbo->currval[i]._ElementSize = vbo->currval[i].Size * sizeof(GLfloat); + /* Size here is in components - not bytes */ + vbo->currval[i].Size = exec->vtx.attrsz[i] / dmul; + vbo->currval[i]._ElementSize = vbo->currval[i].Size * sizeof(GLfloat) * dmul; vbo->currval[i].Type = exec->vtx.attrtype[i]; vbo->currval[i].Integer = vbo_attrtype_to_integer_flag(exec->vtx.attrtype[i]); + vbo->currval[i].Doubles = + vbo_attrtype_to_double_flag(exec->vtx.attrtype[i]); /* This triggers rather too much recalculation of Mesa state * that doesn't get used (eg light positions). @@ -214,13 +223,17 @@ vbo_exec_copy_from_current(struct vbo_exec_context *exec) GLint i; for (i = VBO_ATTRIB_POS + 1; i < VBO_ATTRIB_MAX; i++) { - const fi_type *current = (fi_type *) vbo->currval[i].Ptr; - switch (exec->vtx.attrsz[i]) { - case 4: exec->vtx.attrptr[i][3] = current[3]; - case 3: exec->vtx.attrptr[i][2] = current[2]; - case 2: exec->vtx.attrptr[i][1] = current[1]; - case 1: exec->vtx.attrptr[i][0] = current[0]; - break; + if (exec->vtx.attrtype[i] == GL_DOUBLE) { + memcpy(exec->vtx.attrptr[i], vbo->currval[i].Ptr, exec->vtx.attrsz[i] * sizeof(GLfloat)); + } else { + const fi_type *current = (fi_type *) vbo->currval[i].Ptr; + switch (exec->vtx.attrsz[i]) { + case 4: exec->vtx.attrptr[i][3] = current[3]; + case 3: exec->vtx.attrptr[i][2] = current[2]; + case 2: exec->vtx.attrptr[i][1] = current[1]; + case 1: exec->vtx.attrptr[i][0] = current[0]; + break; + } } } } @@ -364,11 +377,11 @@ vbo_exec_wrap_upgrade_vertex(struct vbo_exec_context *exec, * glTexCoord4f() call. We promote the array from size=2 to size=4. */ static void -vbo_exec_fixup_vertex(struct gl_context *ctx, GLuint attr, GLuint newSize) +vbo_exec_fixup_vertex(struct gl_context *ctx, GLuint attr, GLuint newSize, GLenum newType) { struct vbo_exec_context *exec = &vbo_context(ctx)->exec; - if (newSize > exec->vtx.attrsz[attr]) { + if (newSize > exec->vtx.attrsz[attr] || newType != exec->vtx.attrtype[attr]) { /* New size is larger. Need to flush existing vertices and get * an enlarged vertex format. */ @@ -401,18 +414,19 @@ vbo_exec_fixup_vertex(struct gl_context *ctx, GLuint attr, GLuint newSize) * This macro is used to implement all the glVertex, glColor, glTexCoord, * glVertexAttrib, etc functions. */ -#define ATTR_UNION( A, N, T, V0, V1, V2, V3 ) \ +#define ATTR_UNION( A, N, T, C, V0, V1, V2, V3 ) \ do { \ struct vbo_exec_context *exec = &vbo_context(ctx)->exec; \ - \ + int sz = (sizeof(C) / sizeof(GLfloat)); \ if (unlikely(!(ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT))) \ ctx->Driver.BeginVertices( ctx ); \ - \ - if (unlikely(exec->vtx.active_sz[A] != N)) \ - vbo_exec_fixup_vertex(ctx, A, N); \ - \ + \ + if (unlikely(exec->vtx.active_sz[A] != N * sz) || \ + unlikely(exec->vtx.attrtype[A] != T)) \ + vbo_exec_fixup_vertex(ctx, A, N * sz, T); \ + \ { \ - fi_type *dest = exec->vtx.attrptr[A]; \ + C *dest = (C *)exec->vtx.attrptr[A]; \ if (N>0) dest[0] = V0; \ if (N>1) dest[1] = V1; \ if (N>2) dest[2] = V2; \ @@ -438,7 +452,6 @@ do { \ } \ } while (0) - #define ERROR(err) _mesa_error( ctx, err, __func__ ) #define TAG(x) vbo_##x @@ -575,7 +588,7 @@ static void GLAPIENTRY vbo_exec_EvalCoord1f( GLfloat u ) for (i = 0; i <= VBO_ATTRIB_TEX7; i++) { if (exec->eval.map1[i].map) if (exec->vtx.active_sz[i] != exec->eval.map1[i].sz) - vbo_exec_fixup_vertex( ctx, i, exec->eval.map1[i].sz ); + vbo_exec_fixup_vertex( ctx, i, exec->eval.map1[i].sz, GL_FLOAT ); } } @@ -602,12 +615,12 @@ static void GLAPIENTRY vbo_exec_EvalCoord2f( GLfloat u, GLfloat v ) for (i = 0; i <= VBO_ATTRIB_TEX7; i++) { if (exec->eval.map2[i].map) if (exec->vtx.active_sz[i] != exec->eval.map2[i].sz) - vbo_exec_fixup_vertex( ctx, i, exec->eval.map2[i].sz ); + vbo_exec_fixup_vertex( ctx, i, exec->eval.map2[i].sz, GL_FLOAT ); } if (ctx->Eval.AutoNormal) if (exec->vtx.active_sz[VBO_ATTRIB_NORMAL] != 3) - vbo_exec_fixup_vertex( ctx, VBO_ATTRIB_NORMAL, 3 ); + vbo_exec_fixup_vertex( ctx, VBO_ATTRIB_NORMAL, 3, GL_FLOAT ); } memcpy( exec->vtx.copied.buffer, exec->vtx.vertex, @@ -968,6 +981,16 @@ static void vbo_exec_vtxfmt_init( struct vbo_exec_context *exec ) vfmt->VertexAttribP3uiv = vbo_VertexAttribP3uiv; vfmt->VertexAttribP4ui = vbo_VertexAttribP4ui; vfmt->VertexAttribP4uiv = vbo_VertexAttribP4uiv; + + vfmt->VertexAttribL1d = vbo_VertexAttribL1d; + vfmt->VertexAttribL2d = vbo_VertexAttribL2d; + vfmt->VertexAttribL3d = vbo_VertexAttribL3d; + vfmt->VertexAttribL4d = vbo_VertexAttribL4d; + + vfmt->VertexAttribL1dv = vbo_VertexAttribL1dv; + vfmt->VertexAttribL2dv = vbo_VertexAttribL2dv; + vfmt->VertexAttribL3dv = vbo_VertexAttribL3dv; + vfmt->VertexAttribL4dv = vbo_VertexAttribL4dv; } diff --git a/mesalib/src/mesa/vbo/vbo_save_api.c b/mesalib/src/mesa/vbo/vbo_save_api.c index 5927beeb3..29de3d38a 100644 --- a/mesalib/src/mesa/vbo/vbo_save_api.c +++ b/mesalib/src/mesa/vbo/vbo_save_api.c @@ -772,7 +772,7 @@ _save_reset_vertex(struct gl_context *ctx) * 3f version won't otherwise set color[3] to 1.0 -- this is the job * of the chooser function when switching between Color4f and Color3f. */ -#define ATTR_UNION(A, N, T, V0, V1, V2, V3) \ +#define ATTR_UNION(A, N, T, C, V0, V1, V2, V3) \ do { \ struct vbo_save_context *save = &vbo_context(ctx)->save; \ \ @@ -780,7 +780,7 @@ do { \ save_fixup_vertex(ctx, A, N); \ \ { \ - fi_type *dest = save->attrptr[A]; \ + C *dest = (C *)save->attrptr[A]; \ if (N>0) dest[0] = V0; \ if (N>1) dest[1] = V1; \ if (N>2) dest[2] = V2; \ @@ -1372,6 +1372,16 @@ _save_vtxfmt_init(struct gl_context *ctx) vfmt->VertexAttribP3uiv = _save_VertexAttribP3uiv; vfmt->VertexAttribP4uiv = _save_VertexAttribP4uiv; + vfmt->VertexAttribL1d = _save_VertexAttribL1d; + vfmt->VertexAttribL2d = _save_VertexAttribL2d; + vfmt->VertexAttribL3d = _save_VertexAttribL3d; + vfmt->VertexAttribL4d = _save_VertexAttribL4d; + + vfmt->VertexAttribL1dv = _save_VertexAttribL1dv; + vfmt->VertexAttribL2dv = _save_VertexAttribL2dv; + vfmt->VertexAttribL3dv = _save_VertexAttribL3dv; + vfmt->VertexAttribL4dv = _save_VertexAttribL4dv; + /* This will all require us to fallback to saving the list as opcodes: */ vfmt->CallList = _save_CallList; diff --git a/mesalib/src/mesa/vbo/vbo_split_copy.c b/mesalib/src/mesa/vbo/vbo_split_copy.c index d1107dd84..7b1e20b18 100644 --- a/mesalib/src/mesa/vbo/vbo_split_copy.c +++ b/mesalib/src/mesa/vbo/vbo_split_copy.c @@ -533,6 +533,7 @@ replay_init( struct copy_context *copy ) dst->Enabled = GL_TRUE; dst->Normalized = src->Normalized; dst->Integer = src->Integer; + dst->Doubles = src->Doubles; dst->BufferObj = ctx->Shared->NullBufferObj; dst->_ElementSize = src->_ElementSize; diff --git a/mesalib/src/util/Makefile.sources b/mesalib/src/util/Makefile.sources index 3e0d02bad..dc5593918 100644 --- a/mesalib/src/util/Makefile.sources +++ b/mesalib/src/util/Makefile.sources @@ -7,6 +7,7 @@ MESA_UTIL_FILES := \ format_srgb.h \ hash_table.c \ hash_table.h \ + list.h \ macros.h \ ralloc.c \ ralloc.h \ diff --git a/mesalib/src/gallium/auxiliary/util/u_double_list.h b/mesalib/src/util/list.h index 247f0f282..946034710 100644 --- a/mesalib/src/gallium/auxiliary/util/u_double_list.h +++ b/mesalib/src/util/list.h @@ -1,8 +1,8 @@ /************************************************************************** - * + * * Copyright 2006 VMware, Inc., Bismarck, ND. USA. * All Rights Reserved. - * + * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including @@ -10,36 +10,37 @@ * distribute, sub license, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * USE OR OTHER DEALINGS IN THE SOFTWARE. * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial portions * of the Software. - * + * **************************************************************************/ /** * \file * List macros heavily inspired by the Linux kernel * list handling. No list looping yet. - * + * * Is not threadsafe, so common operations need to * be protected using an external mutex. */ -#ifndef _U_DOUBLE_LIST_H_ -#define _U_DOUBLE_LIST_H_ +#ifndef _UTIL_LIST_H_ +#define _UTIL_LIST_H_ +#include <stdbool.h> #include <stddef.h> -#include "pipe/p_compiler.h" +#include <assert.h> struct list_head @@ -48,13 +49,13 @@ struct list_head struct list_head *next; }; -static INLINE void list_inithead(struct list_head *item) +static inline void list_inithead(struct list_head *item) { item->prev = item; item->next = item; } -static INLINE void list_add(struct list_head *item, struct list_head *list) +static inline void list_add(struct list_head *item, struct list_head *list) { item->prev = list; item->next = list->next; @@ -62,7 +63,7 @@ static INLINE void list_add(struct list_head *item, struct list_head *list) list->next = item; } -static INLINE void list_addtail(struct list_head *item, struct list_head *list) +static inline void list_addtail(struct list_head *item, struct list_head *list) { item->next = list; item->prev = list->prev; @@ -70,7 +71,7 @@ static INLINE void list_addtail(struct list_head *item, struct list_head *list) list->prev = item; } -static INLINE void list_replace(struct list_head *from, struct list_head *to) +static inline void list_replace(struct list_head *from, struct list_head *to) { to->prev = from->prev; to->next = from->next; @@ -78,14 +79,14 @@ static INLINE void list_replace(struct list_head *from, struct list_head *to) from->prev->next = to; } -static INLINE void list_del(struct list_head *item) +static inline void list_del(struct list_head *item) { item->prev->next = item->next; item->next->prev = item->prev; item->prev = item->next = NULL; } -static INLINE void list_delinit(struct list_head *item) +static inline void list_delinit(struct list_head *item) { item->prev->next = item->next; item->next->prev = item->prev; @@ -93,6 +94,28 @@ static INLINE void list_delinit(struct list_head *item) item->prev = item; } +static inline bool list_empty(struct list_head *list) +{ + return list->next == list; +} + +static inline unsigned list_length(struct list_head *list) +{ + struct list_head *node; + unsigned length = 0; + for (node = list->next; node != list; node = node->next) + length++; + return length; +} + +static inline void list_validate(struct list_head *list) +{ + struct list_head *node; + assert(list->next->prev == list && list->prev->next == list); + for (node = list->next; node != list; node = node->next) + assert(node->next->prev == node && node->prev->next == node); +} + #define LIST_INITHEAD(__item) list_inithead(__item) #define LIST_ADD(__item, __list) list_add(__item, __list) #define LIST_ADDTAIL(__item, __list) list_addtail(__item, __list) @@ -144,4 +167,38 @@ static INLINE void list_delinit(struct list_head *item) &pos->member != (head); \ pos = container_of(pos->member.prev, pos, member)) -#endif /*_U_DOUBLE_LIST_H_*/ +#define list_for_each_entry(type, pos, head, member) \ + for (type *pos = LIST_ENTRY(type, (head)->next, member); \ + &pos->member != (head); \ + pos = LIST_ENTRY(type, pos->member.next, member)) + +#define list_for_each_entry_safe(type, pos, head, member) \ + for (type *pos = LIST_ENTRY(type, (head)->next, member), \ + *__next = LIST_ENTRY(type, pos->member.next, member); \ + &pos->member != (head); \ + pos = __next, \ + __next = LIST_ENTRY(type, __next->member.next, member)) + +#define list_for_each_entry_rev(type, pos, head, member) \ + for (type *pos = LIST_ENTRY(type, (head)->prev, member); \ + &pos->member != (head); \ + pos = LIST_ENTRY(type, pos->member.prev, member)) + +#define list_for_each_entry_safe_rev(type, pos, head, member) \ + for (type *pos = LIST_ENTRY(type, (head)->prev, member), \ + *__prev = LIST_ENTRY(type, pos->member.prev, member); \ + &pos->member != (head); \ + pos = __prev, \ + __prev = LIST_ENTRY(type, __prev->member.prev, member)) + +#define list_for_each_entry_from(type, pos, start, head, member) \ + for (type *pos = LIST_ENTRY(type, (start), member); \ + &pos->member != (head); \ + pos = LIST_ENTRY(type, pos->member.next, member)) + +#define list_for_each_entry_from_rev(type, pos, start, head, member) \ + for (type *pos = LIST_ENTRY(type, (start), member); \ + &pos->member != (head); \ + pos = LIST_ENTRY(type, pos->member.prev, member)) + +#endif /*_UTIL_LIST_H_*/ |