Add support for padding in vertex formats
authorMikko Rasa <tdb@tdb.fi>
Wed, 17 Nov 2021 13:39:01 +0000 (15:39 +0200)
committerMikko Rasa <tdb@tdb.fi>
Wed, 17 Nov 2021 13:48:20 +0000 (15:48 +0200)
Vulkan requires attributes to be correctly aligned, so depending on the
combination of types padding may be necessary.  It's better to make it
explicit so support for raw mesh data files can be added in the future.

source/backends/opengl/vertexsetup_backend.cpp
source/builders/vertexarraybuilder.cpp
source/core/vertexformat.cpp
source/core/vertexformat.h
source/core/vertexsetup.cpp

index acd14f48b70c42fd539f85c277c09e06ac3a94e7..d45481f996b5eba732c1a1512c7e8d1a3619c077 100644 (file)
@@ -87,27 +87,30 @@ void OpenGLVertexSetup::update_vertex_array(const VertexArray &array, unsigned b
        for(VertexAttribute a: fmt)
        {
                unsigned sem = get_attribute_semantic(a);
-               bool integer = is_integer_attribute(a);
-               GLenum type = get_gl_type(get_attribute_source_type(a));
-               unsigned cc = get_attribute_component_count(a);
-               if(direct)
-               {
-                       if(integer)
-                               glVertexArrayAttribIFormat(id, sem, cc, type, offset);
-                       else
-                               glVertexArrayAttribFormat(id, sem, cc, type, true, offset);
-                       glVertexArrayAttribBinding(id, sem, binding);
-                       glEnableVertexArrayAttrib(id, sem);
-               }
-               else
+               if(!is_padding(a))
                {
-                       if(integer)
-                               glVertexAttribIPointer(sem, cc, type, stride, reinterpret_cast<void *>(offset));
+                       bool integer = is_integer_attribute(a);
+                       GLenum type = get_gl_type(get_attribute_source_type(a));
+                       unsigned cc = get_attribute_component_count(a);
+                       if(direct)
+                       {
+                               if(integer)
+                                       glVertexArrayAttribIFormat(id, sem, cc, type, offset);
+                               else
+                                       glVertexArrayAttribFormat(id, sem, cc, type, true, offset);
+                               glVertexArrayAttribBinding(id, sem, binding);
+                               glEnableVertexArrayAttrib(id, sem);
+                       }
                        else
-                               glVertexAttribPointer(sem, cc, type, true, stride, reinterpret_cast<void *>(offset));
-                       if(ARB_instanced_arrays)
-                               glVertexAttribDivisor(sem, divisor);
-                       glEnableVertexAttribArray(sem);
+                       {
+                               if(integer)
+                                       glVertexAttribIPointer(sem, cc, type, stride, reinterpret_cast<void *>(offset));
+                               else
+                                       glVertexAttribPointer(sem, cc, type, true, stride, reinterpret_cast<void *>(offset));
+                               if(ARB_instanced_arrays)
+                                       glVertexAttribDivisor(sem, divisor);
+                               glEnableVertexAttribArray(sem);
+                       }
                }
                offset += get_attribute_size(a);
        }
@@ -130,17 +133,19 @@ void OpenGLVertexSetup::unload()
                glBindBuffer(GL_ARRAY_BUFFER, 0);
 
                for(VertexAttribute a: static_cast<const VertexSetup *>(this)->vertex_format)
-               {
-                       unsigned sem = get_attribute_semantic(a);
-                       glDisableVertexAttribArray(sem);
-                       glVertexAttribPointer(sem, 1, GL_FLOAT, false, 0, 0);
-               }
+                       if(!is_padding(a))
+                       {
+                               unsigned sem = get_attribute_semantic(a);
+                               glDisableVertexAttribArray(sem);
+                               glVertexAttribPointer(sem, 1, GL_FLOAT, false, 0, 0);
+                       }
                for(VertexAttribute a: static_cast<const VertexSetup *>(this)->inst_format)
-               {
-                       unsigned sem = get_attribute_semantic(a);
-                       glDisableVertexAttribArray(sem);
-                       glVertexAttribPointer(sem, 1, GL_FLOAT, false, 0, 0);
-               }
+                       if(!is_padding(a))
+                       {
+                               unsigned sem = get_attribute_semantic(a);
+                               glDisableVertexAttribArray(sem);
+                               glVertexAttribPointer(sem, 1, GL_FLOAT, false, 0, 0);
+                       }
 
                glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
        }
index c9a1f3bc8c5c5d8a751705fdfb3603ad196a7e6f..00ff00128c14591ed6de778a586a3d3af411d4ca 100644 (file)
@@ -16,12 +16,12 @@ void VertexArrayBuilder::vertex_(const Vector4 &vtx)
        for(VertexAttribute a: array.get_format())
        {
                unsigned sem = get_attribute_semantic(a);
-               bool integer = is_integer_attribute(a);
-               DataType type = get_attribute_source_type(a);
-               unsigned cc = get_attribute_component_count(a);
-
-               if(sem<attr.size())
+               if(!is_padding(a) && sem<attr.size())
                {
+                       bool integer = is_integer_attribute(a);
+                       DataType type = get_attribute_source_type(a);
+                       unsigned cc = get_attribute_component_count(a);
+
                        const Vector4 &value = (sem==0 ? vtx : attr[sem]);
                        if(type==UNSIGNED_BYTE)
                                store_attribute<uint8_t>(ptr, value, !integer, cc);
index ff043f7d0466bef73b08e216836617ef8fe9200f..3db7542f4da68ab240ed17d7773299908dbcc7d9 100644 (file)
@@ -188,7 +188,8 @@ void operator>>(const LexicalConverter &conv, VertexAttribute &a)
                        convert_attribute(str, "GROUP", 1, 4, a, GROUP1) ||
                        convert_attribute(str, "WEIGHT", 1, 4, a, WEIGHT1) ||
                        convert_attribute(str, "TEXCOORD", 1, 4, a, TEXCOORD1) ||
-                       convert_attribute(str, "GENERIC", 1, 4, a, GENERIC1))
+                       convert_attribute(str, "GENERIC", 1, 4, a, GENERIC1) ||
+                       convert_attribute(str, "PADDING", 1, 4, a, PADDING1))
                        return;
        }
        catch(...)
index 64c89e13166abae491fa2a50d30785cddd7a86cc..fba206e4386e978674a2d5e6bbc7cc33c9d2119e 100644 (file)
@@ -61,6 +61,10 @@ enum VertexAttribute: std::uint16_t
        GENERIC_I2 = 0x28CA,
        GENERIC_I3 = 0x28CB,
        GENERIC_I4 = 0x28CC,
+       PADDING1 = 0xF811,
+       PADDING2 = 0xF812,
+       PADDING3 = 0xF813,
+       PADDING4 = 0xF814,
        RAW_ATTRIB1 = 0xFDC1,
        RAW_ATTRIB2 = 0xFDC2,
        RAW_ATTRIB3 = 0xFDC3,
@@ -134,6 +138,9 @@ inline unsigned get_attribute_size(VertexAttribute a)
 inline bool is_integer_attribute(VertexAttribute a)
 { return a&8; }
 
+inline bool is_padding(VertexAttribute a)
+{ return get_attribute_semantic(a)==get_attribute_semantic(PADDING1); }
+
 void operator>>(const LexicalConverter &, VertexAttribute &);
 
 } // namespace GL
index 61bf032c0fcaecae0ffac46fef15c95f86e95952..2994916e81e0503c29110d55882f60cccf258ea1 100644 (file)
@@ -73,7 +73,7 @@ bool VertexSetup::verify_format(const VertexFormat &fmt)
                return false;
 
        static unsigned max_attribs = Device::get_current().get_info().limits.max_vertex_attributes;
-       return all_of(fmt.begin(), fmt.end(), [](VertexAttribute a){ return get_attribute_semantic(a)<max_attribs; });
+       return all_of(fmt.begin(), fmt.end(), [](VertexAttribute a){ return is_padding(a) || get_attribute_semantic(a)<max_attribs; });
 }
 
 void VertexSetup::update() const