Commit 1c7dcfed authored by Francisco Jerez's avatar Francisco Jerez

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's avatarPaul Berry <stereotype441@gmail.com>
Reviewed-by: 's avatarIan Romanick <ian.d.romanick@intel.com>
parent e3fd31dc
......@@ -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
......
......@@ -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;
......
......@@ -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;
......
......@@ -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
/*@}*/
/**
......
......@@ -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;
}
......
......@@ -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 },
......
......@@ -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:
......
......@@ -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
......
......@@ -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 */
......
......@@ -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;
}
......
......@@ -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
......
......@@ -535,7 +535,8 @@ _mesa_GetUniformLocation(GLhandleARB programObj, const GLcharARB *name)
* with a named uniform block, or if <name> 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;
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment