206 lines
5 KiB
C++
206 lines
5 KiB
C++
|
#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;
|
||
|
}
|