Name

    AMD_shader_atomic_counter_ops

Name Strings

    GL_AMD_shader_atomic_counter_ops

Contact

    Daniel Rakos (daniel.rakos 'at' amd.com)

Contributors

    Daniel Rakos, AMD
    Graham Sellers, AMD

Status

    Shipping

Version

    Last Modified Date:         02/01/2013
    Author Revision:            2

Number

    OpenGL Extension #435

Dependencies

    OpenGL 4.2 or ARB_shader_atomic_counters is required.

    This extension is written against the OpenGL 4.3 (core) specification
    and the GLSL 4.30.7 specification.

Overview

    The ARB_shader_atomic_counters extension introduced atomic counters, but
    it limits list of potential operations that can be performed on them to
    increment, decrement, and query. This extension extends the list of GLSL
    built-in functions that can operate on atomic counters. The list of new
    operations include:

      * Increment and decrement with wrap
      * Addition and subtraction
      * Minimum and maximum
      * Bitwise operators (AND, OR, XOR, etc.)
      * Masked OR operator
      * Exchange, and compare and exchange operators

New Procedures and Functions

    None.

New Tokens

    None.

Additions to Chapter 8 of the GLSL 4.30.7 Specification (Built-in Functions)

    Modify Section 8.10, Atomic-Counter Functions

    Remove second paragraph ("The value returned by...")

    Modify third paragraph ("The underlying...")

      The underlying counter is a 32-bit unsigned integer. The result of
      operations will wrap to [0, 2^32-1].

    Additions to the table listing atomic counter built-in functions:

      Syntax                                Description
      ------------------------------------  ------------------------------------------------------------------
      uint atomicCounterIncWrap(            Atomically
          atomic_uint c,                      1. increments the counter for c, then forces it to zero if and
          uint wrap                              only if the incremented value is greater than or equal to
      )                                          <wrap>, and
                                              2. returns its value prior to the operation.
                                            These two steps are done atomically with respect to the atomic
                                            counter functions in this table.

      uint atomicCounterDecWrap(            Atomically
          atomic_uint c,                      1. decrements the counter for c, then forces it to <wrap>-1 if
          uint wrap                              and only if the original value of the counter was either
      )                                          zero or greater than <wrap>, and
                                              2. returns its value resulting from the operation.
                                            These two steps are done atomically with respect to the atomic
                                            counter functions in this table.

      uint atomicCounterAdd(                Atomically
          atomic_uint c,                      1. adds the value of <data> to the counter for c, and
          uint data                           2. returns its value prior to the operation.
      )                                     These two steps are done atomically with respect to the atomic
                                            counter functions in this table.

      uint atomicCounterSubtract(           Atomically
          atomic_uint c,                      1. subtracts the value of <data> from the counter for c, and
          uint data                           2. returns the value resulting from the operation.
      )                                     These two steps are done atomically with respect to the atomic
                                            counter functions in this table.

      uint atomicCounterReverseSubtract(    Atomically
          atomic_uint c,                      1. subtracts the value of the counter for c from the value of
          uint data                              <data> and sets the counter for c to the result of the
      )                                          operation, and
                                              2. returns the value prior to the operation.
                                            These two steps are done atomically with respect to the atomic
                                            counter functions in this table.

      uint atomicCounterMin(                Atomically
          atomic_uint c,                      1. sets the counter for c to the minimum of the value of the
          uint data                              counter and the value of <data>, and
      )                                       2. returns the value prior to the operation.
                                            These two steps are done atomically with respect to the atomic
                                            counter functions in this table.

      uint atomicCounterMax(                Atomically
          atomic_uint c,                      1. sets the counter for c to the maximum of the value of the
          uint data                              counter and the value of <data>, and
      )                                       2. returns the value prior to the operation.
                                            These two steps are done atomically with respect to the atomic
                                            counter functions in this table.

      uint atomicCounterAnd(                Atomically
          atomic_uint c,                      1. sets the counter for c to the result of the bitwise AND of
          uint data                              the value of the counter and the value of <data>, and
      )                                       2. returns the value prior to the operation.
                                            These two steps are done atomically with respect to the atomic
                                            counter functions in this table.

      uint atomicCounterOr(                 Atomically
          atomic_uint c,                      1. sets the counter for c to the result of the bitwise OR of
          uint data                              the value of the counter and the value of <data>, and
      )                                       2. returns the value prior to the operation.
                                            These two steps are done atomically with respect to the atomic
                                            counter functions in this table.

      uint atomicCounterXor(                Atomically
          atomic_uint c,                      1. sets the counter for c to the result of the bitwise XOR of
          uint data                              the value of the counter and the value of <data>, and
      )                                       2. returns the value prior to the operation.
                                            These two steps are done atomically with respect to the atomic
                                            counter functions in this table.

      uint atomicCounterMaskOr(             Atomically
          atomic_uint c,                      1. sets the counter for c to the result of the operation:
          uint mask,                               (counter ^ ~mask) | data
          uint data                           2. returns the value prior to the operation.
      )                                     These two steps are done atomically with respect to the atomic
                                            counter functions in this table.

      uint atomicCounterExchange(           Atomically
          atomic_uint c,                      1. sets the counter value for c to the value of <data>, and
          uint data                           2. returns its value prior to the operation.
      )                                     These two steps are done atomically with respect to the atomic
                                            counter functions in this table.

      uint atomicCounterCompSwap(           Atomically
          atomic_uint c,                      1. compares the value of <compare> and the counter value for c,
          uint compare,                       2. if the values are equal, sets the counter value for c to
          uint data                              the value of <data>, and
      )                                       3. returns its value prior to the operation.
                                            These three steps are done atomically with respect to the atomic
                                            counter functions in this table.

Additions to the AGL/GLX/WGL Specifications

    None.

GLX Protocol

    None.

Errors

    None.

New State

    None.

New Implementation Dependent State

    None.

Usage Examples

    Example 1: Appending/consuming data to/from a ring buffer using a compute shader

        // Here we use increment/decrement with wrap to account for the wrapping at the
        // end of the ring buffer.
        // Using regular increment/decrement and performing a modulo manually is not
        // satisfactory for non-power-of-two sized buffers as when the 32-bit counter
        // wraps around we get incorrect results.

        // Append shader
        layout(binding=0, offset=0) uniform atomic_uint ringCounter;
        layout(binding=0, r32ui) uniform imageBuffer ringBuffer;

        void main()
        {
            uint myBufferData = ...;

            imageStore(ringBuffer,
                       atomicCounterIncWrap(ringCounter, imageSize(ringBuffer)),
                       myBufferData);
        }

        // Consume shader
        layout(binding=0, offset=0) uniform atomic_uint ringCounter;
        layout(binding=0, r32ui) uniform imageBuffer ringBuffer;

        void main()
        {
            uint myBufferData =
                imageLoad(ringBuffer,
                          atomicCounterDecWrap(ringCounter, imageSize(ringBuffer))).x;
        }

    Example 2: Appending variable length records to a buffer using a compute shader

        // Here we use atomicCounterAdd to ensure that we "allocate" a contiguous list of
        // elements in the buffer.
        // Using atomicCounterIncrement cannot mimic this behavior as there is no guarantee
        // that subsequent calls to atomicCounterIncrement return subsequent counter values.

        layout(binding=0, offset=0) uniform atomic_uint vlrCounter;
        layout(binding=0, r32ui) uniform imageBuffer vlrBuffer;

        void main()
        {
            uint data[...] = ...;
            uint recordLength = ...;

            uint recordStart = atomicCounterAdd(vlrCounter, recordLength);

            for (uint i = 0; i < recordLength; ++i)
            {
                imageStore(vlrBuffer, recordStart + i, data[i]);
            }
        }

Issues

    1) Should the new decrement with wrap and subtract operators match the
    behavior of the existing decrement operator and return the post-operation
    value of the counter?

    RESOLVED: Yes, for consistency with the existing functionality.

    2) Most of the new operations introduced by this extension are already
    supported on load/store images and shader storage buffers. What benefit
    the application developer could get from using this extension?

    DISCUSSION: Atomic counter operations can have different performance
    characteristics than load/store images or shader storage buffers. It is
    expected that implementations can do atomic counter operations faster.
    Also, there is no increment/decrement with wrap, reverse subtract and
    mask-or operation for these storages (though the EXT version of load/store
    image extension does provide a increment/decrement with wrap operators).

    RESOLVED: It enables existing operations for atomic counters and also
    adds completely new operations that are not available for load/store
    images and shader storage buffers.

    3) What should be the result of the increment/decrement with wrap
    operations if the original counter value is greater than the <wrap>
    parameter?

    RESOLVED: Increment with wrap will force the value of the counter to zero,
    decrement with wrap will force the value of the counter to <wrap>-1.

Revision History

    Rev.    Date      Author    Changes
    ----  --------    --------  ---------------------------------------------

      2   02/01/2013  drakos    Added issue #2 and #3
                                Cleaned up naming convention
      1   11/13/2012  drakos    Initial revision
