From ab4416ed585179284e744ca0605b689ae199009c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emmanuel=20Beno=C3=AEt?= Date: Mon, 9 Oct 2017 10:58:03 +0200 Subject: [PATCH] Data structures for uniforms --- Makefile | 1 + externals.hh | 6 ++ uniforms.cc | 205 +++++++++++++++++++++++++++++++++++++++++++++++++++ uniforms.hh | 96 ++++++++++++++++++++++++ 4 files changed, 308 insertions(+) create mode 100644 uniforms.cc create mode 100644 uniforms.hh diff --git a/Makefile b/Makefile index 75f2d9d..f672934 100644 --- a/Makefile +++ b/Makefile @@ -16,6 +16,7 @@ DEMO = \ utilities.cc \ texture.cc \ rendertarget.cc \ + uniforms.cc \ camera.cc \ \ filewatcher.cc \ diff --git a/externals.hh b/externals.hh index 9358efe..b85f018 100644 --- a/externals.hh +++ b/externals.hh @@ -43,6 +43,12 @@ #define NO_MOVE( CLS ) \ CLS( CLS&& ) = delete; \ CLS& operator =( CLS&& ) = delete +#define DEF_COPY( CLS ) \ + CLS( CLS const& ) = default; \ + CLS& operator =( CLS const& ) = default +#define DEF_MOVE( CLS ) \ + CLS( CLS&& ) noexcept = default; \ + CLS& operator =( CLS&& ) noexcept = default #define COPY( CLS ) \ CLS( CLS const& ); \ CLS& operator =( CLS const& ) diff --git a/uniforms.cc b/uniforms.cc new file mode 100644 index 0000000..722305d --- /dev/null +++ b/uniforms.cc @@ -0,0 +1,205 @@ +#include "externals.hh" +#include "uniforms.hh" + + +/*= Uniform types ============================================================*/ + +E_UniformCategory GetUniformCategory( + __rd__ const E_UniformType type ) +{ + switch ( type ) { + case E_UniformType::F1: + case E_UniformType::F2: + case E_UniformType::F3: + case E_UniformType::F4: + return E_UniformCategory::FLOAT; + case E_UniformType::I1: + case E_UniformType::I2: + case E_UniformType::I3: + case E_UniformType::I4: + return E_UniformCategory::INT; + case E_UniformType::SAMPLER2D: + return E_UniformCategory::SAMPLER2D; + } + std::abort( ); +} + + +uint32_t GetElementCount( + __rd__ const E_UniformType type ) +{ + switch ( type ) { + case E_UniformType::F1: + case E_UniformType::I1: + return 1; + case E_UniformType::F2: + case E_UniformType::I2: + return 2; + case E_UniformType::F3: + case E_UniformType::I3: + return 3; + case E_UniformType::F4: + case E_UniformType::I4: + return 4; + + case E_UniformType::SAMPLER2D: + return 0; + } + std::abort( ); +} + +bool IsVectorCategory( + __rd__ const E_UniformCategory category ) +{ + assert( category != E_UniformCategory::__COUNT__ ); + return category == E_UniformCategory::FLOAT + || category == E_UniformCategory::INT; +} + + +/*= PackUniforms =============================================================*/ + +namespace { + +T_PackedUniforms PackVectorUniforms_( + __rd__ T_UniformDeclarations const& declarations , + __rd__ const E_UniformCategory category ) +{ + std::vector< std::string > packOrder; + packOrder.reserve( declarations.size( ) ); + for ( auto entry : declarations ) { + auto const& u( entry.second ); + if ( GetUniformCategory( u.type ) == category ) { + packOrder.push_back( entry.first ); + } + } + std::sort( packOrder.begin( ) , packOrder.end( ) , + [&declarations]( auto const& a , auto const& b ) + { + auto const& ua( declarations.find( a )->second ); + auto const& ub( declarations.find( b )->second ); + return GetElementCount( ub.type ) < GetElementCount( ua.type ); + } ); + + const auto n( packOrder.size( ) ); + auto index = 0u; + T_PackedUniforms pu; + + // Place vec4's + while ( index < n && GetElementCount( declarations.find( packOrder[ index ] )->second.type ) == 4 ) { + pu.positions[ packOrder[ index ] ] = pu.elements; + pu.elements += 4; + index ++; + } + + // Place vec3's + uint32_t s3left( 0 ); + while ( index < n && GetElementCount( declarations.find( packOrder[ index ] )->second.type ) == 3 ) { + pu.positions[ packOrder[ index ] ] = pu.elements; + pu.elements += 4; + s3left ++; + index ++; + } + + // Place vec2's + const uint32_t s2s( pu.elements ); + bool s2spare( false ); + while ( index < n && GetElementCount( declarations.find( packOrder[ index ] )->second.type ) == 2 ) { + if ( !s2spare ) { + pu.elements += 4; + } + const uint32_t pos( pu.elements - ( s2spare ? 2 : 4 ) ); + pu.positions[ packOrder[ index ] ] = pos; + s2spare = !s2spare; + index ++; + } + + // Place single elements + uint32_t s1pos( s2spare ? ( pu.elements - 2 ) : pu.elements ); + while ( index < n ) { + uint32_t pos; + if ( s3left ) { + pos = s2s - s3left * 4 + 3; + s3left --; + } else { + if ( s1pos == pu.elements ) { + pu.elements += 4; + } + pos = s1pos; + s1pos ++; + } + pu.positions[ packOrder[ index ] ] = pos; + index ++; + } + + return pu; +} + +T_PackedUniforms PackOpaqueUniforms_( + __rd__ T_UniformDeclarations const& declarations , + __rd__ const E_UniformCategory category ) +{ + T_PackedUniforms pu; + for ( auto entry : declarations ) { + auto const& u( entry.second ); + if ( GetUniformCategory( u.type ) == category ) { + pu.positions[ entry.first ] = pu.elements; + pu.elements ++; + } + } + return pu; +} + +} // namespace + +/*----------------------------------------------------------------------------*/ + +T_PackedUniforms PackUniforms( + __rd__ T_UniformDeclarations const& declarations , + __rd__ const E_UniformCategory category ) +{ + assert( category != E_UniformCategory::__COUNT__ ); + if ( IsVectorCategory( category ) ) { + return PackVectorUniforms_( declarations , category ); + } + return PackOpaqueUniforms_( declarations , category ); +} + + +/*= T_UniformSet =============================================================*/ + +constexpr uint32_t T_UniformSet::Invalid; + +T_UniformSet::T_UniformSet( ) + : vectorElements_( 0 ) , opaqueElements_( 0 ) +{ } + +T_UniformSet::T_UniformSet( + __rw__ T_UniformDeclarations declarations ) + : declarations_( std::move( declarations ) ) , + vectorElements_( 0 ) , opaqueElements_( 0 ) +{ + for ( auto i = 0 ; i < int( E_UniformCategory::__COUNT__ ) ; i ++ ) { + const auto cat{ E_UniformCategory( i ) }; + packed_[ i ] = PackUniforms( declarations_ , cat ); + if ( IsVectorCategory( cat ) ) { + vectorElements_ += packed_[ i ].elements; + } else { + opaqueElements_ += packed_[ i ].elements; + } + } +} + +uint32_t T_UniformSet::position( + __rd__ std::string const& uniform ) const +{ + const auto pos( declarations_.find( uniform ) ); + if ( pos == declarations_.end( ) ) { + return Invalid; + } + + const int ci( int( GetUniformCategory( pos->second.type ) ) ); + const auto ePos( packed_[ ci ].positions.find( uniform ) ); + assert( ePos != packed_[ ci ].positions.end( ) ); + return ePos->second; +} diff --git a/uniforms.hh b/uniforms.hh new file mode 100644 index 0000000..d73025f --- /dev/null +++ b/uniforms.hh @@ -0,0 +1,96 @@ +#pragma once +#ifndef REAL_BUILD +# include "externals.hh" +#endif + + +// Uniform types +enum class E_UniformType { + F1 , F2 , F3 , F4 , + I1 , I2 , I3 , I4 , + SAMPLER2D +}; + +// Categories +enum class E_UniformCategory { + FLOAT , INT , + SAMPLER2D , + __COUNT__ +}; + +// Category from type +E_UniformCategory GetUniformCategory( + __rd__ const E_UniformType type ); +// Element count from type +uint32_t GetElementCount( + __rd__ const E_UniformType type ); +// Is some category a vector type? +bool IsVectorCategory( + __rd__ const E_UniformCategory category ); + + +// Uniform declarations +struct T_UniformDeclaration +{ + std::string name; + bool global; + E_UniformType type; + + std::string source; + uint32_t line; +}; + +using T_UniformDeclarations = std::unordered_map< std::string , T_UniformDeclaration >; + + +// Packed uniforms +struct T_PackedUniforms +{ + uint32_t elements = 0; + std::map< std::string , uint32_t > positions; +}; + +T_PackedUniforms PackUniforms( + __rd__ T_UniformDeclarations const& declarations , + __rd__ const E_UniformCategory category ); + + +// A set of uniforms, meant for use with a buffer or directly +struct T_UniformSet +{ + static constexpr uint32_t Invalid = 0xffffffff; + + T_UniformSet( ); + explicit T_UniformSet( + __rw__ T_UniformDeclarations uniforms ); + + DEF_MOVE( T_UniformSet ); + NO_COPY( T_UniformSet ); + + // --------------------------------------------------------------------- + + T_UniformDeclarations const& declarations( ) const noexcept + { return declarations_; } + + uint32_t vectorElements( ) const noexcept + { return vectorElements_; } + uint32_t opaqueElements( ) const noexcept + { return opaqueElements_; } + + uint32_t inCategory( + __rd__ const E_UniformCategory category ) const noexcept + { + assert( category != E_UniformCategory::__COUNT__ ); + return packed_[ int( category ) ].elements; + } + + // Return the position of the specified uniform in its category. + // If the uniform doesn't exist, this will return Invalid. + uint32_t position( + __rd__ std::string const& uniform ) const; + + private: + T_UniformDeclarations declarations_; + uint32_t vectorElements_ , opaqueElements_; + T_PackedUniforms packed_[ int( E_UniformCategory::__COUNT__ ) ]; +};