From e92de029768eef5f0fd744329e589161b46d0762 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Wed, 15 Sep 2021 21:51:59 +0300 Subject: [PATCH] Add support for integer vertex attributes --- gl.fixes.xml | 30 ++++++++++++++++++++++++++ source/builders/vertexarraybuilder.cpp | 19 ++++++++-------- source/builders/vertexarraybuilder.h | 2 +- source/core/vertexformat.cpp | 14 +++++++++++- source/core/vertexformat.h | 18 +++++++++++++--- source/core/vertexsetup.cpp | 27 +++++++++++++++++++++-- source/core/vertexsetup.h | 1 + 7 files changed, 95 insertions(+), 16 deletions(-) diff --git a/gl.fixes.xml b/gl.fixes.xml index e5f9ee55..4a00e379 100644 --- a/gl.fixes.xml +++ b/gl.fixes.xml @@ -107,5 +107,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/source/builders/vertexarraybuilder.cpp b/source/builders/vertexarraybuilder.cpp index 3afe9a40..6ede4d2a 100644 --- a/source/builders/vertexarraybuilder.cpp +++ b/source/builders/vertexarraybuilder.cpp @@ -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(ptr, value, cc); + store_attribute(ptr, value, !integer, cc); else if(type==BYTE) - store_attribute(ptr, value, cc); + store_attribute(ptr, value, !integer, cc); else if(type==UNSIGNED_SHORT) - store_attribute(ptr, value, cc); + store_attribute(ptr, value, !integer, cc); else if(type==SHORT) - store_attribute(ptr, value, cc); + store_attribute(ptr, value, !integer, cc); else if(type==UNSIGNED_INT) - store_attribute(ptr, value, cc); + store_attribute(ptr, value, !integer, cc); else if(type==INT) - store_attribute(ptr, value, cc); + store_attribute(ptr, value, !integer, cc); else if(type==FLOAT) - store_attribute(ptr, value, cc); + store_attribute(ptr, value, false, cc); } ptr += get_attribute_size(*a); @@ -44,12 +45,12 @@ void VertexArrayBuilder::vertex_(const Vector4 &vtx) } template -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(ptr); for(unsigned i=0; i::is_integer) + if(!numeric_limits::is_integer || !normalize) *tptr++ = value[i]; else if(numeric_limits::is_signed) *tptr++ = round(min(max(value[i], -1.0f), 1.0f)*numeric_limits::max()); diff --git a/source/builders/vertexarraybuilder.h b/source/builders/vertexarraybuilder.h index aa723540..52335960 100644 --- a/source/builders/vertexarraybuilder.h +++ b/source/builders/vertexarraybuilder.h @@ -23,7 +23,7 @@ private: virtual void vertex_(const Vector4 &); template - void store_attribute(char *, const Vector4 &, unsigned); + void store_attribute(char *, const Vector4 &, bool, unsigned); }; } // namespace GL diff --git a/source/core/vertexformat.cpp b/source/core/vertexformat.cpp index 5d0b078f..7dcb7aba 100644 --- a/source/core/vertexformat.cpp +++ b/source/core/vertexformat.cpp @@ -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((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(result|8); + } + if(i==str.end() || *i<'0'+min_size || *i>'0'+max_size) return false; - VertexAttribute result = static_cast(base_attr+(*i++-'0'-min_size)); + result = static_cast(result+(*i++-'0'-min_size)); while(i!=str.end()) { diff --git a/source/core/vertexformat.h b/source/core/vertexformat.h index a503aff8..132d0b95 100644 --- a/source/core/vertexformat.h +++ b/source/core/vertexformat.h @@ -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 diff --git a/source/core/vertexsetup.cpp b/source/core/vertexsetup.cpp index 8498e043..81d2261e 100644 --- a/source/core/vertexsetup.cpp +++ b/source/core/vertexsetup.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #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(offset)); + if(integer) + glVertexAttribIPointer(sem, cc, type, stride, reinterpret_cast(offset)); + else + glVertexAttribPointer(sem, cc, type, true, stride, reinterpret_cast(offset)); if(ARB_instanced_arrays) glVertexAttribDivisor(sem, divisor); glEnableVertexAttribArray(sem); diff --git a/source/core/vertexsetup.h b/source/core/vertexsetup.h index 756f5bc0..d0ed8703 100644 --- a/source/core/vertexsetup.h +++ b/source/core/vertexsetup.h @@ -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; -- 2.43.0