GL_ARB_enhanced_layouts: consider std140 rules
authorAndres Gomez <agomez@igalia.com>
Wed, 1 Mar 2017 13:43:24 +0000 (15:43 +0200)
committerAlexander Galazin <Alexander.Galazin@arm.com>
Sat, 1 Jul 2017 10:29:50 +0000 (06:29 -0400)
In the case of UBOs and SSBOs, the offset for a block member depends
on the base alignment of its type. When the block uses the std140
packaging we have to take into account its specific rules for the
calculation of the base alignment for such data type.

From the GL_ARB_enhanced_layouts spec:

    "The specified offset must be a multiple of the base alignment of
     the type of the block member it qualifies, or a compile-time
     error results."

From page 61 (page 74 of the PDF) of the OpenGL 3.1 spec:

    "2.11. VERTEX SHADERS

     ...

     Standard Uniform Block Layout

     ...

     When using the std140 storage layout, structures will be laid out
     in buffer storage with its members stored in monotonically
     increasing order based on their location in the declaration. A
     structure and each structure member have a base offset and a base
     alignment, from which an aligned offset is computed by rounding
     the base offset up to a multiple of the base alignment.

     ...

     1. If the member is a scalar consuming N basic machine units, the
        base alignment is N.

     2. If the member is a two- or four-component vector with
        components consuming N basic machine units, the base alignment
        is 2N or 4N , respectively.

     3. If the member is a three-component vector with components
        consuming N basic machine units, the base alignment is 4N .

     4. If the member is an array of scalars or vectors, the base
        alignment and array stride are set to match the base alignment
        of a single array element, according to rules (1), (2),
        and (3), and rounded up to the base alignment of a vec4. The
        array may have padding at the end; the base offset of the
        member following the array is rounded up to the next multiple
        of the base alignment.

     5. If the member is a column-major matrix with C columns and R
        rows, the matrix is stored identically to an array of C column
        vectors with R compo- nents each, according to rule (4)."

From page 128 (page 149 of the PDF) of the OpenGL 4.3 spec:

    "7.8 Shader Buffer Variables and Shader Storage Blocks

     ...

     Buffer variables in shader storage blocks are represented in
     memory in the same way as uniforms stored in uniform blocks, as
     described in section 7.6.2.1.  When a program is linked
     successfully, each active buffer variable is assigned an offset
     relative to the base of the buffer object binding associated with
     its shader storage block. For buffer variables declared as arrays
     and matrices, strides between array elements or matrix columns or
     rows will also be assigned. Offsets and strides of buffer
     variables will be assigned in an implementation-dependent manner
     unless the shader storage block is declared using the std140 or
     std430 storage layout qualifiers. For std140 and std430 shader
     storage blocks, offsets will be assigned using the method
     described in section 7.6.2.2."

Affects:

GL44-CTS.enhanced_layouts.uniform_block_member_invalid_offset_alignment
GL44-CTS.enhanced_layouts.ssb_member_invalid_offset_alignment

Components: OpenGL

VK-GL-CTS issue: 519

Change-Id: I5176d555605a8c482377ebfa5fbf16bc0dbf741a

external/openglcts/modules/gl/gl4cEnhancedLayoutsTests.cpp
external/openglcts/modules/gl/gl4cEnhancedLayoutsTests.hpp

index e3658a6..4686f5b 100644 (file)
@@ -520,15 +520,24 @@ GLuint Type::GetLocations() const
        return n_loc_per_column * m_n_columns;
 }
 
-/** Get size of the type in bytes. Note that this routine assumes tightly packing
+/** Get size of the type in bytes.
+ * Note that this routine doesn't consider arrays and assumes
+ * column_major matrices.
  *
- * @return Formula Number of columns * number of rows * sizeof(base_type)
+ * @return Formula:
+ *          - If std140 packaging and matrix; number of columns * base alignment
+ *          - Otherwise; number of elements * sizeof(base_type)
  **/
-GLuint Type::GetSize() const
+GLuint Type::GetSize(const bool is_std140) const
 {
        const GLuint basic_type_size = GetTypeSize(m_basic_type);
        const GLuint n_elements          = m_n_columns * m_n_rows;
 
+       if (is_std140 && m_n_columns > 1)
+       {
+               return m_n_columns * GetBaseAlignment(false);
+       }
+
        return basic_type_size * n_elements;
 }
 
@@ -9345,7 +9354,7 @@ void UniformBlockMemberInvalidOffsetAlignmentTest::testInit()
        {
                const Utils::Type& type           = getType(i);
                const GLuint       alignment  = type.GetBaseAlignment(false);
-               const GLuint       type_size  = type.GetSize();
+               const GLuint       type_size  = type.GetSize(true);
                const GLuint       sec_to_end = max_size - 2 * type_size;
 
                for (GLuint stage = 0; stage < Utils::Shader::STAGE_MAX; ++stage)
index 3bf5c94..433e203 100644 (file)
@@ -66,9 +66,9 @@ public:
        std::string GetGLSLConstructor(const glw::GLvoid* data) const;
        const glw::GLchar* GetGLSLTypeName() const;
        glw::GLuint                GetLocations() const;
-       glw::GLuint                GetSize() const;
-       glw::GLenum                GetTypeGLenum() const;
-       glw::GLuint                GetNumComponents() const;
+       glw::GLuint GetSize(const bool is_std140 = false) const;
+       glw::GLenum GetTypeGLenum() const;
+       glw::GLuint GetNumComponents() const;
 
        /* Public static routines */
        /* Functionality */