From 1c7dcfed7ceb9e47943d6adaacc1ca483c97fcf6 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Mon, 7 Oct 2013 18:53:40 -0700 Subject: [PATCH] mesa: Add support for ARB_shader_atomic_counters. This patch implements the common support code required for the ARB_shader_atomic_counters extension. It defines the necessary data structures for tracking atomic counter buffer objects (from now on "ABOs") associated with some specific context or shader program, it implements support for binding buffers to an ABO binding point and querying the existing atomic counters and buffers declared by GLSL shaders. v2: Fix extension checks. Drop unused MAX_ATOMIC_BUFFERS constant. Acked-by: Paul Berry Reviewed-by: Ian Romanick --- src/glsl/ir_uniform.h | 7 ++++ src/glsl/link_uniforms.cpp | 1 + src/mesa/main/bufferobj.c | 58 ++++++++++++++++++++++++++++++ src/mesa/main/config.h | 5 +++ src/mesa/main/context.c | 9 +++++ src/mesa/main/extensions.c | 1 + src/mesa/main/get.c | 40 +++++++++++++++++++++ src/mesa/main/get_hash_params.py | 12 +++++++ src/mesa/main/mtypes.h | 59 ++++++++++++++++++++++++++++++ src/mesa/main/shaderapi.c | 6 ++++ src/mesa/main/uniform_query.cpp | 14 ++++++-- src/mesa/main/uniforms.c | 62 +++++++++++++++++++++++++++++++- 12 files changed, 271 insertions(+), 3 deletions(-) diff --git a/src/glsl/ir_uniform.h b/src/glsl/ir_uniform.h index 8198c481983..13faab7c0a1 100644 --- a/src/glsl/ir_uniform.h +++ b/src/glsl/ir_uniform.h @@ -166,6 +166,13 @@ struct gl_uniform_storage { bool row_major; /** @} */ + + /** + * Index within gl_shader_program::AtomicBuffers[] of the atomic + * counter buffer this uniform is stored in, or -1 if this is not + * an atomic counter. + */ + int atomic_buffer_index; }; #ifdef __cplusplus diff --git a/src/glsl/link_uniforms.cpp b/src/glsl/link_uniforms.cpp index ea71b3063ca..0a15739c265 100644 --- a/src/glsl/link_uniforms.cpp +++ b/src/glsl/link_uniforms.cpp @@ -513,6 +513,7 @@ private: this->uniforms[id].num_driver_storage = 0; this->uniforms[id].driver_storage = NULL; this->uniforms[id].storage = this->values; + this->uniforms[id].atomic_buffer_index = -1; if (this->ubo_block_index != -1) { this->uniforms[id].block_index = this->ubo_block_index; diff --git a/src/mesa/main/bufferobj.c b/src/mesa/main/bufferobj.c index 312ffb78888..1f5506157ca 100644 --- a/src/mesa/main/bufferobj.c +++ b/src/mesa/main/bufferobj.c @@ -102,6 +102,11 @@ get_buffer_target(struct gl_context *ctx, GLenum target) return &ctx->UniformBuffer; } break; + case GL_ATOMIC_COUNTER_BUFFER: + if (ctx->Extensions.ARB_shader_atomic_counters) { + return &ctx->AtomicBuffer; + } + break; default: return NULL; } @@ -2119,6 +2124,51 @@ bind_buffer_base_uniform_buffer(struct gl_context *ctx, set_ubo_binding(ctx, index, bufObj, 0, 0, GL_TRUE); } +static void +set_atomic_buffer_binding(struct gl_context *ctx, + unsigned index, + struct gl_buffer_object *bufObj, + GLintptr offset, + GLsizeiptr size, + const char *name) +{ + struct gl_atomic_buffer_binding *binding; + + if (index >= ctx->Const.MaxAtomicBufferBindings) { + _mesa_error(ctx, GL_INVALID_VALUE, "%s(index=%d)", name, index); + return; + } + + if (offset & (ATOMIC_COUNTER_SIZE - 1)) { + _mesa_error(ctx, GL_INVALID_VALUE, + "%s(offset misalgned %d/%d)", name, (int) offset, + ATOMIC_COUNTER_SIZE); + return; + } + + _mesa_reference_buffer_object(ctx, &ctx->AtomicBuffer, bufObj); + + binding = &ctx->AtomicBufferBindings[index]; + if (binding->BufferObject == bufObj && + binding->Offset == offset && + binding->Size == size) { + return; + } + + FLUSH_VERTICES(ctx, 0); + ctx->NewDriverState |= ctx->DriverFlags.NewAtomicBuffer; + + _mesa_reference_buffer_object(ctx, &binding->BufferObject, bufObj); + + if (bufObj == ctx->Shared->NullBufferObj) { + binding->Offset = -1; + binding->Size = -1; + } else { + binding->Offset = offset; + binding->Size = size; + } +} + void GLAPIENTRY _mesa_BindBufferRange(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size) @@ -2156,6 +2206,10 @@ _mesa_BindBufferRange(GLenum target, GLuint index, case GL_UNIFORM_BUFFER: bind_buffer_range_uniform_buffer(ctx, index, bufObj, offset, size); return; + case GL_ATOMIC_COUNTER_BUFFER: + set_atomic_buffer_binding(ctx, index, bufObj, offset, size, + "glBindBufferRange"); + return; default: _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferRange(target)"); return; @@ -2215,6 +2269,10 @@ _mesa_BindBufferBase(GLenum target, GLuint index, GLuint buffer) case GL_UNIFORM_BUFFER: bind_buffer_base_uniform_buffer(ctx, index, bufObj); return; + case GL_ATOMIC_COUNTER_BUFFER: + set_atomic_buffer_binding(ctx, index, bufObj, 0, 0, + "glBindBufferBase"); + return; default: _mesa_error(ctx, GL_INVALID_ENUM, "glBindBufferBase(target)"); return; diff --git a/src/mesa/main/config.h b/src/mesa/main/config.h index 0bcf27c345b..22bbfa0cf31 100644 --- a/src/mesa/main/config.h +++ b/src/mesa/main/config.h @@ -170,6 +170,11 @@ #define MAX_UNIFORM_BUFFERS 15 /* + 1 default uniform buffer */ /* 6 is for vertex, hull, domain, geometry, fragment, and compute shader. */ #define MAX_COMBINED_UNIFORM_BUFFERS (MAX_UNIFORM_BUFFERS * 6) +#define MAX_ATOMIC_COUNTERS 4096 +/* 6 is for vertex, hull, domain, geometry, fragment, and compute shader. */ +#define MAX_COMBINED_ATOMIC_BUFFERS (MAX_UNIFORM_BUFFERS * 6) +/* Size of an atomic counter in bytes according to ARB_shader_atomic_counters */ +#define ATOMIC_COUNTER_SIZE 4 /*@}*/ /** diff --git a/src/mesa/main/context.c b/src/mesa/main/context.c index 0d1f71c7142..6cdeed19b0a 100644 --- a/src/mesa/main/context.c +++ b/src/mesa/main/context.c @@ -537,6 +537,9 @@ init_program_limits(struct gl_context *ctx, GLenum type, prog->MaxCombinedUniformComponents = (prog->MaxUniformComponents + ctx->Const.MaxUniformBlockSize / 4 * prog->MaxUniformBlocks); + + prog->MaxAtomicBuffers = 0; + prog->MaxAtomicCounters = 0; } @@ -669,6 +672,12 @@ _mesa_init_constants(struct gl_context *ctx) ctx->Const.MaxColorTextureSamples = 1; ctx->Const.MaxDepthTextureSamples = 1; ctx->Const.MaxIntegerSamples = 1; + + /* GL_ARB_shader_atomic_counters */ + ctx->Const.MaxAtomicBufferBindings = MAX_COMBINED_ATOMIC_BUFFERS; + ctx->Const.MaxAtomicBufferSize = MAX_ATOMIC_COUNTERS * ATOMIC_COUNTER_SIZE; + ctx->Const.MaxCombinedAtomicBuffers = MAX_COMBINED_ATOMIC_BUFFERS; + ctx->Const.MaxCombinedAtomicCounters = MAX_ATOMIC_COUNTERS; } diff --git a/src/mesa/main/extensions.c b/src/mesa/main/extensions.c index 00d65ccb04d..285ec377cfd 100644 --- a/src/mesa/main/extensions.c +++ b/src/mesa/main/extensions.c @@ -120,6 +120,7 @@ static const struct extension extension_table[] = { { "GL_ARB_robustness", o(dummy_true), GL, 2010 }, { "GL_ARB_sampler_objects", o(dummy_true), GL, 2009 }, { "GL_ARB_seamless_cube_map", o(ARB_seamless_cube_map), GL, 2009 }, + { "GL_ARB_shader_atomic_counters", o(ARB_shader_atomic_counters), GL, 2011 }, { "GL_ARB_shader_bit_encoding", o(ARB_shader_bit_encoding), GL, 2010 }, { "GL_ARB_shader_objects", o(dummy_true), GL, 2002 }, { "GL_ARB_shader_stencil_export", o(ARB_shader_stencil_export), GL, 2009 }, diff --git a/src/mesa/main/get.c b/src/mesa/main/get.c index 89b3bf09ddb..6e72ff5c298 100644 --- a/src/mesa/main/get.c +++ b/src/mesa/main/get.c @@ -143,6 +143,7 @@ enum value_extra { EXTRA_FLUSH_CURRENT, EXTRA_GLSL_130, EXTRA_EXT_UBO_GS4, + EXTRA_EXT_ATOMICS_GS4, }; #define NO_EXTRA NULL @@ -331,6 +332,11 @@ static const int extra_MESA_texture_array_es3[] = { EXTRA_END }; +static const int extra_ARB_shader_atomic_counters_and_geometry_shader[] = { + EXTRA_EXT_ATOMICS_GS4, + EXTRA_END +}; + EXTRA_EXT(ARB_texture_cube_map); EXTRA_EXT(MESA_texture_array); EXTRA_EXT(NV_fog_distance); @@ -367,6 +373,7 @@ EXTRA_EXT(ARB_texture_cube_map_array); EXTRA_EXT(ARB_texture_buffer_range); EXTRA_EXT(ARB_texture_multisample); EXTRA_EXT(ARB_texture_gather); +EXTRA_EXT(ARB_shader_atomic_counters); static const int extra_ARB_color_buffer_float_or_glcore[] = { @@ -894,6 +901,10 @@ find_custom_value(struct gl_context *ctx, const struct value_desc *d, union valu _mesa_problem(ctx, "driver doesn't implement GetTimestamp"); } break; + /* GL_ARB_shader_atomic_counters */ + case GL_ATOMIC_COUNTER_BUFFER_BINDING: + v->value_int = ctx->AtomicBuffer->Name; + break; } } @@ -999,6 +1010,11 @@ check_extra(struct gl_context *ctx, const char *func, const struct value_desc *d api_found = (ctx->Extensions.ARB_uniform_buffer_object && _mesa_has_geometry_shaders(ctx)); break; + case EXTRA_EXT_ATOMICS_GS4: + api_check = GL_TRUE; + api_found = (ctx->Extensions.ARB_shader_atomic_counters && + _mesa_has_geometry_shaders(ctx)); + break; case EXTRA_END: break; default: /* *e is a offset into the extension struct */ @@ -1692,6 +1708,30 @@ find_value_indexed(const char *func, GLenum pname, GLuint index, union value *v) goto invalid_enum; v->value_int = ctx->Multisample.SampleMaskValue; return TYPE_INT; + + case GL_ATOMIC_COUNTER_BUFFER_BINDING: + if (!ctx->Extensions.ARB_shader_atomic_counters) + goto invalid_enum; + if (index >= ctx->Const.MaxAtomicBufferBindings) + goto invalid_value; + v->value_int = ctx->AtomicBufferBindings[index].BufferObject->Name; + return TYPE_INT; + + case GL_ATOMIC_COUNTER_BUFFER_START: + if (!ctx->Extensions.ARB_shader_atomic_counters) + goto invalid_enum; + if (index >= ctx->Const.MaxAtomicBufferBindings) + goto invalid_value; + v->value_int64 = ctx->AtomicBufferBindings[index].Offset; + return TYPE_INT64; + + case GL_ATOMIC_COUNTER_BUFFER_SIZE: + if (!ctx->Extensions.ARB_shader_atomic_counters) + goto invalid_enum; + if (index >= ctx->Const.MaxAtomicBufferBindings) + goto invalid_value; + v->value_int64 = ctx->AtomicBufferBindings[index].Size; + return TYPE_INT64; } invalid_enum: diff --git a/src/mesa/main/get_hash_params.py b/src/mesa/main/get_hash_params.py index 9c54af094d7..9f79f340683 100644 --- a/src/mesa/main/get_hash_params.py +++ b/src/mesa/main/get_hash_params.py @@ -722,6 +722,18 @@ descriptor=[ [ "MAX_PROGRAM_TEXTURE_GATHER_OFFSET", "CONTEXT_INT(Const.MaxProgramTextureGatherOffset), extra_ARB_texture_gather"], [ "MAX_PROGRAM_TEXTURE_GATHER_COMPONENTS_ARB", "CONTEXT_INT(Const.MaxProgramTextureGatherComponents), extra_ARB_texture_gather"], +# GL_ARB_shader_atomic_counters + [ "ATOMIC_COUNTER_BUFFER_BINDING", "LOC_CUSTOM, TYPE_INT, 0, extra_ARB_shader_atomic_counters" ], + [ "MAX_ATOMIC_COUNTER_BUFFER_BINDINGS", "CONTEXT_INT(Const.MaxAtomicBufferBindings), extra_ARB_shader_atomic_counters" ], + [ "MAX_ATOMIC_COUNTER_BUFFER_SIZE", "CONTEXT_INT(Const.MaxAtomicBufferSize), extra_ARB_shader_atomic_counters" ], + [ "MAX_VERTEX_ATOMIC_COUNTER_BUFFERS", "CONTEXT_INT(Const.VertexProgram.MaxAtomicBuffers), extra_ARB_shader_atomic_counters" ], + [ "MAX_VERTEX_ATOMIC_COUNTERS", "CONTEXT_INT(Const.VertexProgram.MaxAtomicCounters), extra_ARB_shader_atomic_counters" ], + [ "MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS", "CONTEXT_INT(Const.FragmentProgram.MaxAtomicBuffers), extra_ARB_shader_atomic_counters" ], + [ "MAX_FRAGMENT_ATOMIC_COUNTERS", "CONTEXT_INT(Const.FragmentProgram.MaxAtomicCounters), extra_ARB_shader_atomic_counters" ], + [ "MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS", "CONTEXT_INT(Const.GeometryProgram.MaxAtomicBuffers), extra_ARB_shader_atomic_counters_and_geometry_shader" ], + [ "MAX_GEOMETRY_ATOMIC_COUNTERS", "CONTEXT_INT(Const.GeometryProgram.MaxAtomicCounters), extra_ARB_shader_atomic_counters_and_geometry_shader" ], + [ "MAX_COMBINED_ATOMIC_COUNTER_BUFFERS", "CONTEXT_INT(Const.MaxCombinedAtomicBuffers), extra_ARB_shader_atomic_counters" ], + [ "MAX_COMBINED_ATOMIC_COUNTERS", "CONTEXT_INT(Const.MaxCombinedAtomicCounters), extra_ARB_shader_atomic_counters" ], ]}, # Enums restricted to OpenGL Core profile diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h index 824e33906fd..a1a5eb4bf13 100644 --- a/src/mesa/main/mtypes.h +++ b/src/mesa/main/mtypes.h @@ -2375,6 +2375,25 @@ struct gl_uniform_block enum gl_uniform_block_packing _Packing; }; +/** + * Structure that represents a reference to an atomic buffer from some + * shader program. + */ +struct gl_active_atomic_buffer +{ + /** Uniform indices of the atomic counters declared within it. */ + GLuint *Uniforms; + GLuint NumUniforms; + + /** Binding point index associated with it. */ + GLuint Binding; + + /** Minimum reasonable size it is expected to have. */ + GLuint MinimumSize; + + /** Shader stages making use of it. */ + GLboolean StageReferences[MESA_SHADER_TYPES]; +}; /** * A GLSL program object. @@ -2523,6 +2542,9 @@ struct gl_shader_program */ struct string_to_uint_map *UniformHash; + struct gl_active_atomic_buffer *AtomicBuffers; + unsigned NumAtomicBuffers; + GLboolean LinkStatus; /**< GL_LINK_STATUS */ GLboolean Validated; GLboolean _Used; /**< Ever used for drawing? */ @@ -2960,6 +2982,9 @@ struct gl_program_constants GLuint MaxUniformBlocks; GLuint MaxCombinedUniformComponents; GLuint MaxTextureImageUnits; + /* GL_ARB_shader_atomic_counters */ + GLuint MaxAtomicBuffers; + GLuint MaxAtomicCounters; }; @@ -3166,6 +3191,12 @@ struct gl_constants GLint MaxColorTextureSamples; GLint MaxDepthTextureSamples; GLint MaxIntegerSamples; + + /** GL_ARB_shader_atomic_counters */ + GLuint MaxAtomicBufferBindings; + GLuint MaxAtomicBufferSize; + GLuint MaxCombinedAtomicBuffers; + GLuint MaxCombinedAtomicCounters; }; @@ -3209,6 +3240,7 @@ struct gl_extensions GLboolean ARB_occlusion_query2; GLboolean ARB_point_sprite; GLboolean ARB_seamless_cube_map; + GLboolean ARB_shader_atomic_counters; GLboolean ARB_shader_bit_encoding; GLboolean ARB_shader_stencil_export; GLboolean ARB_shader_texture_lod; @@ -3582,6 +3614,11 @@ struct gl_driver_flags * gl_shader_program::UniformBlocks */ GLbitfield NewUniformBuffer; + + /** + * gl_context::AtomicBufferBindings + */ + GLbitfield NewAtomicBuffer; }; struct gl_uniform_buffer_binding @@ -3598,6 +3635,16 @@ struct gl_uniform_buffer_binding GLboolean AutomaticSize; }; +/** + * Binding point for an atomic counter buffer object. + */ +struct gl_atomic_buffer_binding +{ + struct gl_buffer_object *BufferObject; + GLintptr Offset; + GLsizeiptr Size; +}; + /** * Mesa rendering context. * @@ -3766,6 +3813,18 @@ struct gl_context struct gl_uniform_buffer_binding UniformBufferBindings[MAX_COMBINED_UNIFORM_BUFFERS]; + /** + * Object currently associated with the GL_ATOMIC_COUNTER_BUFFER + * target. + */ + struct gl_buffer_object *AtomicBuffer; + + /** + * Array of atomic counter buffer binding points. + */ + struct gl_atomic_buffer_binding + AtomicBufferBindings[MAX_COMBINED_ATOMIC_BUFFERS]; + /*@}*/ struct gl_meta_state *Meta; /**< for "meta" operations */ diff --git a/src/mesa/main/shaderapi.c b/src/mesa/main/shaderapi.c index f5c04b9f38f..4a6bd73d446 100644 --- a/src/mesa/main/shaderapi.c +++ b/src/mesa/main/shaderapi.c @@ -648,6 +648,12 @@ get_programiv(struct gl_context *ctx, GLuint program, GLenum pname, GLint *param case GL_PROGRAM_BINARY_LENGTH: *params = 0; return; + case GL_ACTIVE_ATOMIC_COUNTER_BUFFERS: + if (!ctx->Extensions.ARB_shader_atomic_counters) + break; + + *params = shProg->NumAtomicBuffers; + return; default: break; } diff --git a/src/mesa/main/uniform_query.cpp b/src/mesa/main/uniform_query.cpp index 3c460042eee..88ad476acb9 100644 --- a/src/mesa/main/uniform_query.cpp +++ b/src/mesa/main/uniform_query.cpp @@ -154,11 +154,21 @@ _mesa_GetActiveUniformsiv(GLuint program, params[i] = uni->row_major; break; + case GL_UNIFORM_ATOMIC_COUNTER_BUFFER_INDEX: + if (!ctx->Extensions.ARB_shader_atomic_counters) + goto invalid_enum; + params[i] = uni->atomic_buffer_index; + break; + default: - _mesa_error(ctx, GL_INVALID_ENUM, "glGetActiveUniformsiv(pname)"); - return; + goto invalid_enum; } } + + return; + + invalid_enum: + _mesa_error(ctx, GL_INVALID_ENUM, "glGetActiveUniformsiv(pname)"); } static bool diff --git a/src/mesa/main/uniforms.c b/src/mesa/main/uniforms.c index 07e7ea37998..2e847fe3147 100644 --- a/src/mesa/main/uniforms.c +++ b/src/mesa/main/uniforms.c @@ -535,7 +535,8 @@ _mesa_GetUniformLocation(GLhandleARB programObj, const GLcharARB *name) * with a named uniform block, or if starts with the reserved * prefix "gl_"." */ - if (shProg->UniformStorage[index].block_index != -1) + if (shProg->UniformStorage[index].block_index != -1 || + shProg->UniformStorage[index].atomic_buffer_index != -1) return -1; return _mesa_uniform_merge_location_offset(shProg, index, offset); @@ -849,4 +850,63 @@ void GLAPIENTRY _mesa_GetActiveAtomicCounterBufferiv(GLuint program, GLuint bufferIndex, GLenum pname, GLint *params) { + GET_CURRENT_CONTEXT(ctx); + struct gl_shader_program *shProg; + struct gl_active_atomic_buffer *ab; + int i; + + if (!ctx->Extensions.ARB_shader_atomic_counters) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glGetActiveAtomicCounterBufferiv"); + return; + } + + shProg = _mesa_lookup_shader_program_err(ctx, program, + "glGetActiveAtomicCounterBufferiv"); + if (!shProg) + return; + + if (bufferIndex >= shProg->NumAtomicBuffers) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glGetActiveAtomicCounterBufferiv(bufferIndex)"); + return; + } + + ab = &shProg->AtomicBuffers[bufferIndex]; + + switch (pname) { + case GL_ATOMIC_COUNTER_BUFFER_BINDING: + params[0] = ab->Binding; + return; + case GL_ATOMIC_COUNTER_BUFFER_DATA_SIZE: + params[0] = ab->MinimumSize; + return; + case GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTERS: + params[0] = ab->NumUniforms; + return; + case GL_ATOMIC_COUNTER_BUFFER_ACTIVE_ATOMIC_COUNTER_INDICES: + for (i = 0; i < ab->NumUniforms; ++i) + params[i] = ab->Uniforms[i]; + return; + case GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_VERTEX_SHADER: + params[0] = ab->StageReferences[MESA_SHADER_VERTEX]; + return; + case GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_GEOMETRY_SHADER: + params[0] = ab->StageReferences[MESA_SHADER_GEOMETRY]; + return; + case GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_FRAGMENT_SHADER: + params[0] = ab->StageReferences[MESA_SHADER_FRAGMENT]; + return; + case GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_CONTROL_SHADER: + params[0] = GL_FALSE; + return; + case GL_ATOMIC_COUNTER_BUFFER_REFERENCED_BY_TESS_EVALUATION_SHADER: + params[0] = GL_FALSE; + return; + default: + _mesa_error(ctx, GL_INVALID_ENUM, + "glGetActiveAtomicCounterBufferiv(pname 0x%x (%s))", + pname, _mesa_lookup_enum_by_nr(pname)); + return; + } } -- 2.30.2