[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