[Mesa-dev] [PATCH 2/2] mesa/st: add support for hw atomics (v2)
Nicolai Hähnle
nhaehnle at gmail.com
Wed Aug 9 11:44:14 UTC 2017
Hi Dave,
Thanks for the update, I prefer this.
Have you considered Marek's query about pipeline-wide atomic buffers?
The issue I'm thinking about is what happens when multiple shaders
access the same atomic counter. In a GDS/GWS-based implementation, those
accesses must map to the same hardware counter slot, as far as I
understand it. But if you follow a straight-forward mapping based on
today's TGSI, they won't be.
There are two types of situations that can happen:
1. A GL program object has one counter that is accessed by multiple stages.
2. A GL program object (or even a single shader stage) has multiple
counters with different bindings, and the same buffer range happens to
be bound to both bindings.
I'm pretty sure the second case is intended to be undefined behavior
(see Issue 19 of ARB_shader_atomic_counters), but I believe the first
case is intended to be supported.
So *something* has to make sure that different stages end up accessing
the same hardware counter. One way of doing this is to have a global (as
opposed to per-shader-stage) list of atomic buffers at the Gallium
pipe_context level.
Cheers,
Nicolai
On 08.08.2017 05:13, Dave Airlie wrote:
> From: Dave Airlie <airlied at redhat.com>
>
> This adds support for hw atomics to the state tracker,
> it just sets the limits using the new CAPs, and sets
> the maximums etc for it.
>
> v2: rework for dropping CAP.
>
> Signed-off-by: Dave Airlie <airlied at redhat.com>
> ---
> src/mesa/state_tracker/st_extensions.c | 52 +++++++++++++++++++++++++++-------
> 1 file changed, 42 insertions(+), 10 deletions(-)
>
> diff --git a/src/mesa/state_tracker/st_extensions.c b/src/mesa/state_tracker/st_extensions.c
> index 74193cc..2d93802 100644
> --- a/src/mesa/state_tracker/st_extensions.c
> +++ b/src/mesa/state_tracker/st_extensions.c
> @@ -78,6 +78,8 @@ void st_init_limits(struct pipe_screen *screen,
> int supported_irs;
> unsigned sh;
> boolean can_ubo = TRUE;
> + uint32_t temp;
> + bool ssbo_atomic = true;
>
> c->MaxTextureLevels
> = _min(screen->get_param(screen, PIPE_CAP_MAX_TEXTURE_2D_LEVELS),
> @@ -242,11 +244,21 @@ void st_init_limits(struct pipe_screen *screen,
> c->MaxUniformBlockSize / 4 *
> pc->MaxUniformBlocks);
>
> - pc->MaxAtomicCounters = MAX_ATOMIC_COUNTERS;
> - pc->MaxAtomicBuffers = screen->get_shader_param(
> - screen, sh, PIPE_SHADER_CAP_MAX_SHADER_BUFFERS) / 2;
> - pc->MaxShaderStorageBlocks = pc->MaxAtomicBuffers;
> -
> + temp = screen->get_shader_param(screen, sh, PIPE_SHADER_CAP_MAX_HW_ATOMIC_COUNTERS);
> + if (temp) {
> + /*
> + * for separate atomic counters get the actual hw limits
> + * per stage on atomic counters and buffers
> + */
> + ssbo_atomic = false;
> + pc->MaxAtomicCounters = temp;
> + pc->MaxAtomicBuffers = screen->get_shader_param(screen, sh, PIPE_SHADER_CAP_MAX_HW_ATOMIC_COUNTER_BUFFERS);
> + pc->MaxShaderStorageBlocks = screen->get_shader_param(screen, sh, PIPE_SHADER_CAP_MAX_SHADER_BUFFERS);
> + } else {
> + pc->MaxAtomicCounters = MAX_ATOMIC_COUNTERS;
> + pc->MaxAtomicBuffers = screen->get_shader_param(screen, sh, PIPE_SHADER_CAP_MAX_SHADER_BUFFERS) / 2;
> + pc->MaxShaderStorageBlocks = pc->MaxAtomicBuffers;
> + }
> pc->MaxImageUniforms = screen->get_shader_param(
> screen, sh, PIPE_SHADER_CAP_MAX_SHADER_IMAGES);
>
> @@ -406,14 +418,26 @@ void st_init_limits(struct pipe_screen *screen,
> screen->get_param(screen, PIPE_CAP_TGSI_FS_FACE_IS_INTEGER_SYSVAL);
>
> c->MaxAtomicBufferBindings =
> - c->Program[MESA_SHADER_FRAGMENT].MaxAtomicBuffers;
> - c->MaxCombinedAtomicBuffers =
> + c->Program[MESA_SHADER_FRAGMENT].MaxAtomicBuffers;
> +
> + if (!ssbo_atomic) {
> + /* for separate atomic buffers - there atomic buffer size will be
> + limitied */
> + c->MaxAtomicBufferSize = c->Program[MESA_SHADER_FRAGMENT].MaxAtomicCounters * ATOMIC_COUNTER_SIZE;
> + /* on all HW with separate atomic (evergreen) the following
> + lines are true. not sure it's worth adding CAPs for this at this
> + stage. */
> + c->MaxCombinedAtomicCounters = c->Program[MESA_SHADER_FRAGMENT].MaxAtomicCounters;
> + c->MaxCombinedAtomicBuffers = c->Program[MESA_SHADER_FRAGMENT].MaxAtomicBuffers;
> + } else {
> + c->MaxCombinedAtomicBuffers =
> c->Program[MESA_SHADER_VERTEX].MaxAtomicBuffers +
> c->Program[MESA_SHADER_TESS_CTRL].MaxAtomicBuffers +
> c->Program[MESA_SHADER_TESS_EVAL].MaxAtomicBuffers +
> c->Program[MESA_SHADER_GEOMETRY].MaxAtomicBuffers +
> c->Program[MESA_SHADER_FRAGMENT].MaxAtomicBuffers;
> - assert(c->MaxCombinedAtomicBuffers <= MAX_COMBINED_ATOMIC_BUFFERS);
> + assert(c->MaxCombinedAtomicBuffers <= MAX_COMBINED_ATOMIC_BUFFERS);
> + }
>
> if (c->MaxCombinedAtomicBuffers > 0) {
> extensions->ARB_shader_atomic_counters = GL_TRUE;
> @@ -424,8 +448,11 @@ void st_init_limits(struct pipe_screen *screen,
> c->ShaderStorageBufferOffsetAlignment =
> screen->get_param(screen, PIPE_CAP_SHADER_BUFFER_OFFSET_ALIGNMENT);
> if (c->ShaderStorageBufferOffsetAlignment) {
> - c->MaxCombinedShaderStorageBlocks = c->MaxShaderStorageBufferBindings =
> - c->MaxCombinedAtomicBuffers;
> +
> + /* for hw atomic counters leaves these at default for now */
> + if (ssbo_atomic)
> + c->MaxCombinedShaderStorageBlocks = c->MaxShaderStorageBufferBindings =
> + c->MaxCombinedAtomicBuffers;
> c->MaxCombinedShaderOutputResources +=
> c->MaxCombinedShaderStorageBlocks;
> c->MaxShaderStorageBlockSize = 1 << 27;
> @@ -466,6 +493,11 @@ void st_init_limits(struct pipe_screen *screen,
>
> c->AllowMappedBuffersDuringExecution =
> screen->get_param(screen, PIPE_CAP_ALLOW_MAPPED_BUFFERS_DURING_EXECUTION);
> +
> + /* limit the max combined shader output resources to a driver limit */
> + temp = screen->get_param(screen, PIPE_CAP_MAX_COMBINED_SHADER_OUTPUT_RESOURCES);
> + if (temp > 0 && c->MaxCombinedShaderOutputResources > temp)
> + c->MaxCombinedShaderOutputResources = temp;
> }
>
>
>
--
Lerne, wie die Welt wirklich ist,
Aber vergiss niemals, wie sie sein sollte.
More information about the mesa-dev
mailing list