Add support for integer vertex attributes
authorMikko Rasa <tdb@tdb.fi>
Wed, 15 Sep 2021 18:51:59 +0000 (21:51 +0300)
committerMikko Rasa <tdb@tdb.fi>
Wed, 15 Sep 2021 18:51:59 +0000 (21:51 +0300)
gl.fixes.xml
source/builders/vertexarraybuilder.cpp
source/builders/vertexarraybuilder.h
source/core/vertexformat.cpp
source/core/vertexformat.h
source/core/vertexsetup.cpp
source/core/vertexsetup.h

index e5f9ee55c3bed91d2bf459338fdadd5d6dd03c4b..4a00e3790ce9f5bd001beef5e657aa415dddf008 100644 (file)
                 <enum name="GL_RED"/>
             </require>
         </extension>
+
+        <extension name="GL_EXT_gpu_shader4" supported="gl">
+            <require>
+                <!-- Integer attribute functions are supposed to be in this
+                extension but are misattributed to NV_vertex_program4. -->
+                <command name="glVertexAttribI1iEXT"/>
+                <command name="glVertexAttribI2iEXT"/>
+                <command name="glVertexAttribI3iEXT"/>
+                <command name="glVertexAttribI4iEXT"/>
+                <command name="glVertexAttribI1uiEXT"/>
+                <command name="glVertexAttribI2uiEXT"/>
+                <command name="glVertexAttribI3uiEXT"/>
+                <command name="glVertexAttribI4uiEXT"/>
+                <command name="glVertexAttribI1ivEXT"/>
+                <command name="glVertexAttribI2ivEXT"/>
+                <command name="glVertexAttribI3ivEXT"/>
+                <command name="glVertexAttribI4ivEXT"/>
+                <command name="glVertexAttribI1uivEXT"/>
+                <command name="glVertexAttribI2uivEXT"/>
+                <command name="glVertexAttribI3uivEXT"/>
+                <command name="glVertexAttribI4uivEXT"/>
+                <command name="glVertexAttribI4bvEXT"/>
+                <command name="glVertexAttribI4svEXT"/>
+                <command name="glVertexAttribI4ubvEXT"/>
+                <command name="glVertexAttribI4usvEXT"/>
+                <command name="glVertexAttribIPointerEXT"/>
+                <command name="glGetVertexAttribIivEXT"/>
+                <command name="glGetVertexAttribIuivEXT"/>
+            </require>
+        </extension>
     </extensions>
 </registry>
index 3afe9a40e2bf22c48869207ef9b73235c9dd784b..6ede4d2ab60f8a417087f0d784ac0b00642c2114 100644 (file)
@@ -17,6 +17,7 @@ void VertexArrayBuilder::vertex_(const Vector4 &vtx)
        for(const UInt16 *a=format.begin(); a!=format.end(); ++a)
        {
                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);
 
@@ -24,19 +25,19 @@ void VertexArrayBuilder::vertex_(const Vector4 &vtx)
                {
                        const Vector4 &value = (sem==0 ? vtx : attr[sem]);
                        if(type==UNSIGNED_BYTE)
-                               store_attribute<UInt8>(ptr, value, cc);
+                               store_attribute<UInt8>(ptr, value, !integer, cc);
                        else if(type==BYTE)
-                               store_attribute<Int8>(ptr, value, cc);
+                               store_attribute<Int8>(ptr, value, !integer, cc);
                        else if(type==UNSIGNED_SHORT)
-                               store_attribute<UInt16>(ptr, value, cc);
+                               store_attribute<UInt16>(ptr, value, !integer, cc);
                        else if(type==SHORT)
-                               store_attribute<Int16>(ptr, value, cc);
+                               store_attribute<Int16>(ptr, value, !integer, cc);
                        else if(type==UNSIGNED_INT)
-                               store_attribute<UInt32>(ptr, value, cc);
+                               store_attribute<UInt32>(ptr, value, !integer, cc);
                        else if(type==INT)
-                               store_attribute<Int32>(ptr, value, cc);
+                               store_attribute<Int32>(ptr, value, !integer, cc);
                        else if(type==FLOAT)
-                               store_attribute<float>(ptr, value, cc);
+                               store_attribute<float>(ptr, value, false, cc);
                }
 
                ptr += get_attribute_size(*a);
@@ -44,12 +45,12 @@ void VertexArrayBuilder::vertex_(const Vector4 &vtx)
 }
 
 template<typename T>
-void VertexArrayBuilder::store_attribute(char *ptr, const Vector4 &value, unsigned count)
+void VertexArrayBuilder::store_attribute(char *ptr, const Vector4 &value, bool normalize, unsigned count)
 {
        T *tptr = reinterpret_cast<T *>(ptr);
        for(unsigned i=0; i<count; ++i)
        {
-               if(!numeric_limits<T>::is_integer)
+               if(!numeric_limits<T>::is_integer || !normalize)
                        *tptr++ = value[i];
                else if(numeric_limits<T>::is_signed)
                        *tptr++ = round(min(max(value[i], -1.0f), 1.0f)*numeric_limits<T>::max());
index aa723540c5271b2ca3b0b5fbc2913ddca7b45ca2..523359609a2153614c07e68497f8fca47e29cacb 100644 (file)
@@ -23,7 +23,7 @@ private:
        virtual void vertex_(const Vector4 &);
 
        template<typename T>
-       void store_attribute(char *, const Vector4 &, unsigned);
+       void store_attribute(char *, const Vector4 &, bool, unsigned);
 };
 
 } // namespace GL
index 5d0b078fe06f154b2821ab176a2bf9310132c253..7dcb7aba5472e9438671ef31da1036ef15276c8b 100644 (file)
@@ -97,6 +97,8 @@ VertexAttribute make_typed_attribute(VertexAttribute attr, DataType type)
 {
        if(is_matrix(type) || is_vector(type) || is_image(type))
                throw invalid_argument("make_typed_attribute");
+       if(is_integer_attribute(attr) && is_float(type))
+               throw invalid_argument("make_typed_attribute");
 
        return static_cast<VertexAttribute>((attr&0xFC0F) | (type&0x0F)<<4 | (type&0x300)>>1);
 }
@@ -140,9 +142,19 @@ bool convert_attribute(const string &str, const char *name, int min_size, int ma
        for(; *name; ++name, ++i)
                if(*i!=*name)
                        return false;
+
+       VertexAttribute result = base_attr;
+
+       if(i!=str.end() && *i=='_')
+       {
+               if(*(++i)++!='I')
+                       return false;
+               result = static_cast<VertexAttribute>(result|8);
+       }
+
        if(i==str.end() || *i<'0'+min_size || *i>'0'+max_size)
                return false;
-       VertexAttribute result = static_cast<VertexAttribute>(base_attr+(*i++-'0'-min_size));
+       result = static_cast<VertexAttribute>(result+(*i++-'0'-min_size));
 
        while(i!=str.end())
        {
index a503aff83f84f19bcbbb1d9e3009c77fd526d4bb..132d0b95a88a0b36411b70a55ade9a48c5c19c15 100644 (file)
@@ -20,8 +20,9 @@ are doing.
 
 The values are bitfields laid as follows:
 
-nnnn nn_f gsss _ccc
-      │ │ │  │    └╴Number of components
+nnnn nn_f gsss iccc
+      │ │ │  │ │  └╴Number of components
+      │ │ │  │ └───╴Integer attribute flag
       │ │ │  └─────╴Size of one component
       │ │ └────────╴Signed flag
       │ └──────────╴Floating-point flag
@@ -55,10 +56,18 @@ enum VertexAttribute
        GENERIC2 = 0x29C2,
        GENERIC3 = 0x29C3,
        GENERIC4 = 0x29C4,
+       GENERIC_I1 = 0x28C9,
+       GENERIC_I2 = 0x28CA,
+       GENERIC_I3 = 0x28CB,
+       GENERIC_I4 = 0x28CC,
        RAW_ATTRIB1 = 0xFDC1,
        RAW_ATTRIB2 = 0xFDC2,
        RAW_ATTRIB3 = 0xFDC3,
-       RAW_ATTRIB4 = 0xFDC4
+       RAW_ATTRIB4 = 0xFDC4,
+       RAW_ATTRIB_I1 = 0xFCC9,
+       RAW_ATTRIB_I2 = 0xFCCA,
+       RAW_ATTRIB_I3 = 0xFCCB,
+       RAW_ATTRIB_I4 = 0xFCCC
 };
 
 class VertexFormat
@@ -111,6 +120,9 @@ inline unsigned get_attribute_component_count(UInt16 a)
 inline unsigned get_attribute_size(UInt16 a)
 { return get_attribute_component_count(a)*get_type_size(get_attribute_source_type(a)); }
 
+inline bool is_integer_attribute(UInt16 a)
+{ return a&8; }
+
 void operator>>(const LexicalConverter &, VertexAttribute &);
 
 } // namespace GL
index 8498e043dde57d48c758e4a83957caf2f77e384b..81d2261e6aa78b55b3240e231ea72b25232bea60 100644 (file)
@@ -5,6 +5,7 @@
 #include <msp/gl/extensions/arb_vertex_attrib_binding.h>
 #include <msp/gl/extensions/arb_vertex_buffer_object.h>
 #include <msp/gl/extensions/arb_vertex_shader.h>
+#include <msp/gl/extensions/ext_gpu_shader4.h>
 #include <msp/gl/extensions/khr_debug.h>
 #include "buffer.h"
 #include "deviceinfo.h"
@@ -45,6 +46,8 @@ void VertexSetup::set_format(const VertexFormat &vfmt)
        if(!vertex_format.empty())
                throw invalid_operation("VertexSetup::set_format");
 
+       require_format(vfmt);
+
        vertex_format = vfmt;
 }
 
@@ -55,6 +58,9 @@ void VertexSetup::set_format_instanced(const VertexFormat &vfmt, const VertexFor
        if(!vertex_format.empty())
                throw invalid_operation("VertexSetup::set_format");
 
+       require_format(vfmt);
+       require_format(ifmt);
+
        vertex_format = vfmt;
        inst_format = ifmt;
 }
@@ -108,6 +114,16 @@ bool VertexSetup::verify_format(const VertexFormat &fmt)
        return true;
 }
 
+void VertexSetup::require_format(const VertexFormat &fmt)
+{
+       bool has_int = false;
+       for(const UInt16 *a=fmt.begin(); a!=fmt.end(); ++a)
+               has_int = has_int | is_integer_attribute(*a);
+
+       if(has_int)
+               static Require _req(EXT_gpu_shader4);
+}
+
 void VertexSetup::update() const
 {
        static bool direct = ARB_direct_state_access && ARB_vertex_attrib_binding;
@@ -146,17 +162,24 @@ void VertexSetup::update_vertex_array(const VertexArray &array, unsigned binding
        for(const UInt16 *a=fmt.begin(); a!=fmt.end(); ++a)
        {
                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)
                {
-                       glVertexArrayAttribFormat(id, sem, cc, type, true, offset);
+                       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(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);
index 756f5bc03644990990aafb1f360c1cebb9b6bfe0..d0ed870378034334b6935b092dcfbcae80909c80 100644 (file)
@@ -50,6 +50,7 @@ public:
 
 private:
        static bool verify_format(const VertexFormat &);
+       static void require_format(const VertexFormat &);
        void update() const;
        void update_vertex_array(const VertexArray &, unsigned, unsigned, bool) const;