diff --git a/shaders.cc b/shaders.cc index 8d80501..612f139 100644 --- a/shaders.cc +++ b/shaders.cc @@ -257,6 +257,114 @@ bool T_ShaderInput::load( } +/*= T_ShaderPogram ===========================================================*/ + +T_ShaderProgram::T_ShaderProgram( ) + : T_ShaderProgram( 0 ) +{ } + +T_ShaderProgram::T_ShaderProgram( + T_ShaderProgram const& other ) + : T_ShaderProgram( other.id_ ) +{ } + +T_ShaderProgram::T_ShaderProgram( + T_ShaderProgram&& other ) noexcept + : T_ShaderProgram( ) +{ + swap( other.id_ , id_ ); +} + +T_ShaderProgram::T_ShaderProgram( + const uint32_t id ) noexcept + : id_( id ) +{ + if ( id_ ) { + Globals::Shaders( ).programs_[ id_ - 1 ].saReferences ++; + } +} + +T_ShaderProgram::~T_ShaderProgram( ) +{ + if ( id_ ) { + Globals::Shaders( ).dereferenceProgram( id_ ); + } +} + +T_ShaderProgram& T_ShaderProgram::operator=( + T_ShaderProgram const& other ) +{ + if ( this != &other ) { + if ( id_ ) { + Globals::Shaders( ).dereferenceProgram( id_ ); + } + id_ = other.id_; + if ( id_ ) { + Globals::Shaders( ).programs_[ id_ - 1 ].saReferences ++; + } + } + return *this; +} + +T_ShaderProgram& T_ShaderProgram::operator=( + T_ShaderProgram&& other ) noexcept +{ + if ( this != &other ) { + if ( id_ ) { + Globals::Shaders( ).dereferenceProgram( id_ ); + } + id_ = other.id_; + other.id_ = T_String{}; + } + return *this; +} + +bool T_ShaderProgram::valid( ) const noexcept +{ + return id_ && Globals::Shaders( ).programs_[ id_ - 1 ].id != 0; +} + +void T_ShaderProgram::enable( ) const +{ + if ( !id_ ) { + return; + } + + auto const& p( Globals::Shaders( ).programs_[ id_ - 1 ] ); + if ( p.id ) { + glBindProgramPipeline( 0 ); + glUseProgram( p.id ); + } +} + +GLuint T_ShaderProgram::id( ) const +{ + if ( id_ ) { + return Globals::Shaders( ).programs_[ id_ - 1 ].id; + } else { + return 0; + } +} + +T_Optional< E_ShaderType > T_ShaderProgram::type( ) const +{ + if ( id_ ) { + return Globals::Shaders( ).programs_[ id_ - 1 ].code.type; + } else { + return {}; + } +} + +T_String T_ShaderProgram::name( ) const +{ + if ( id_ ) { + return Globals::Shaders( ).programs_[ id_ - 1 ].name; + } else { + return {}; + } +} + + /*= T_ShaderPipeline =========================================================*/ T_ShaderPipeline::T_ShaderPipeline( ) @@ -332,6 +440,7 @@ void T_ShaderPipeline::enable( ) const auto const* pl( Globals::Shaders( ).pipelines_.get( id_ ) ); if ( pl && pl->id ) { + glUseProgram( 0 ); glBindProgramPipeline( pl->id ); } } @@ -552,6 +661,14 @@ T_ShaderManager::T_ShaderManager( ) noexcept /*----------------------------------------------------------------------------*/ +T_ShaderProgram T_ShaderManager::program( + T_String const& name ) +{ + loadProgram( name ); + assert( programIndex_.contains( name ) ); + return T_ShaderProgram( *programIndex_.get( name ) ); +} + T_ShaderPipeline T_ShaderManager::pipeline( std::initializer_list< T_String > shaders ) { @@ -576,7 +693,7 @@ T_ShaderPipeline T_ShaderManager::pipeline( pipelines_.add( T_Pipeline_{ id , shaders } ); auto& p( *pipelines_.get( id ) ); for ( auto const& pName : shaders ) { - loadProgram( p.idString , (char*)( pName.toOSString( ).data( ) ) ); + loadProgram( p.idString , pName ); } initPipeline( p ); @@ -623,7 +740,7 @@ void T_ShaderManager::update( ) auto const* p( programIndex_.get( *it ) ); if ( p ) { auto& pr( programs_[ *p ] ); - for ( auto const& ref : pr.references ) { + for ( auto const& ref : pr.plReferences ) { if ( !temp.contains( ref ) ) { temp.add( ref ); } @@ -669,43 +786,13 @@ void T_ShaderManager::update( ) } -uint32_t T_ShaderManager::newProgramRecord( ) -{ - uint32_t i = 0; - while ( i < programs_.size( ) ) { - if ( programs_[ i ].references.empty( ) ) { - return i; - } - i ++; - } - programs_.addNew( ); - return i; -} - - void T_ShaderManager::loadProgram( T_String const& pipeline , T_String const& name ) { - if ( useExistingProgram( pipeline , name ) ) { - return; + if ( !useExistingProgram( pipeline , name ) ) { + initProgramRecord( name ).plReferences.add( pipeline ); } - - const uint32_t index( newProgramRecord( ) ); - auto& program( programs_[ index ] ); - programIndex_.add( name , index ); - program.name = name; - program.references.add( pipeline ); - program.id = 0; - initProgram( program ); - - T_StringBuilder sb; - for ( auto const& e : program.code.errors ) { - sb << e.source << ':' << e.line << ": " - << e.error << '\n'; - } - sb << '\0'; - printf( "%s" , sb.data( ) ); } bool T_ShaderManager::useExistingProgram( @@ -716,12 +803,67 @@ bool T_ShaderManager::useExistingProgram( if ( !pos ) { return false; } - auto& refs( programs_[ *pos ].references ); + auto& refs( programs_[ *pos ].plReferences ); assert( !refs.contains( pipeline ) ); refs.add( pipeline ); return true; } +void T_ShaderManager::loadProgram( + T_String const& name ) +{ + if ( useExistingProgram( name ) ) { + initProgramRecord( name ); + } +} + +bool T_ShaderManager::useExistingProgram( + T_String const& name ) +{ + auto const* pos( programIndex_.get( name ) ); + if ( !pos ) { + return false; + } + programs_[ *pos ].saReferences ++; + return true; +} + + +uint32_t T_ShaderManager::newProgramRecord( ) +{ + uint32_t i = 0; + while ( i < programs_.size( ) ) { + if ( programs_[ i ].plReferences.empty( ) + && !programs_[ i ].saReferences ) { + return i; + } + i ++; + } + programs_.addNew( ); + return i; +} + +T_ShaderManager::T_Program_& T_ShaderManager::initProgramRecord( + T_String const& name ) +{ + const uint32_t index( newProgramRecord( ) ); + auto& program( programs_[ index ] ); + programIndex_.add( name , index ); + program.name = name; + program.id = 0; + initProgram( program ); + + T_StringBuilder sb; + for ( auto const& e : program.code.errors ) { + sb << e.source << ':' << e.line << ": " + << e.error << '\n'; + } + sb << '\0'; + printf( "%s" , sb.data( ) ); + + return program; +} + T_ShaderInput const* T_ShaderManager::getInput( T_String const& name ) @@ -772,11 +914,25 @@ void T_ShaderManager::dereferenceProgram( T_String const& pipeline ) { auto& program( programs_[ index ] ); - auto& refs( program.references ); + auto& refs( program.plReferences ); const auto plidx( refs.indexOf( pipeline ) ); assert( plidx >= 0 ); refs.remove( plidx ); - if ( refs.size( ) != 0 ) { + if ( !refs.empty( ) || program.saReferences ) { + return; + } + resetProgram( program ); + programIndex_.remove( program.name ); +} + + +void T_ShaderManager::dereferenceProgram( + const uint32_t index ) +{ + auto& program( programs_[ index ] ); + assert( program.saReferences > 0 ); + program.saReferences --; + if ( program.saReferences || !program.plReferences.empty( ) ) { return; } resetProgram( program ); @@ -997,12 +1153,15 @@ void T_ShaderManager::makeUI( ) ImGui::Begin( "Shaders" ); const auto n( std::count_if( programs_.begin( ) , programs_.end( ) , - []( auto const& p ) { return !p.references.empty( ); } ) ); + []( auto const& p ) { + return !p.plReferences.empty( ) || p.saReferences != 0; + } ) ); std::vector< size_t > indices; const auto rn = programs_.size( ); for ( auto i = 0u ; i < rn ; i ++ ) { - if ( !programs_[ i ].references.empty( ) ) { + auto const& p( programs_[ i ] ); + if ( !p.plReferences.empty( ) || p.saReferences ) { indices.push_back( i ); } } @@ -1013,8 +1172,8 @@ void T_ShaderManager::makeUI( ) if ( pa.code.errors.size( ) != pb.code.errors.size( ) ) { return pa.code.errors.size( ) > pb.code.errors.size( ); } - if ( pa.references.size( ) != pb.references.size( ) ) { - return pa.references.size( ) > pb.references.size( ); + if ( pa.plReferences.size( ) != pb.plReferences.size( ) ) { + return pa.plReferences.size( ) > pb.plReferences.size( ); } return programs_[ a ].name < programs_[ b ].name; } ); @@ -1034,7 +1193,7 @@ void T_ShaderManager::makeUI( ) } ImGui::SameLine( 400 ); - ImGui::Text( "Usage: %u" , program.references.size( ) ); + ImGui::Text( "Usage: %u" , program.plReferences.size( ) + program.saReferences ); ImGui::SameLine( 550 ); if ( program.code.errors.empty( ) ) { ImGui::PushStyleColor( ImGuiCol_Text , ImVec4( .6 , 1 , .6 , 1 ) ); diff --git a/shaders.hh b/shaders.hh index 7e5b38b..40bdf7f 100644 --- a/shaders.hh +++ b/shaders.hh @@ -119,6 +119,26 @@ struct T_ShaderError struct T_ShaderManager; +struct T_ShaderProgram +{ + friend struct T_ShaderManager; + + T_ShaderProgram( ); + COPY( T_ShaderProgram ); + MOVE( T_ShaderProgram ); + ~T_ShaderProgram( ); + + bool valid( ) const noexcept; + void enable( ) const; + GLuint id( ) const; + T_Optional< E_ShaderType > type( ) const; + T_String name( ) const; + + private: + explicit T_ShaderProgram( uint32_t id ) noexcept; + uint32_t id_; +}; + struct T_ShaderPipeline { friend struct T_ShaderManager; @@ -143,6 +163,7 @@ struct T_ShaderPipeline struct T_ShaderManager { friend struct T_ShaderPipeline; + friend struct T_ShaderProgram; struct T_ShaderCode { @@ -157,6 +178,7 @@ struct T_ShaderManager T_ShaderManager( ) noexcept; + T_ShaderProgram program( T_String const& name ); T_ShaderPipeline pipeline( std::initializer_list< T_String > shaders ); @@ -183,7 +205,8 @@ struct T_ShaderManager struct T_Program_ { T_String name; - T_Array< T_String > references; + T_Array< T_String > plReferences; + uint32_t saReferences{ 0 }; T_ShaderCode code; GLuint id; T_Optional< T_WatchedFiles > watch; @@ -201,8 +224,7 @@ struct T_ShaderManager T_KeyValueTable< T_String , T_Array< T_String > > missing_; T_Array< T_String > updates_; - uint32_t newProgramRecord( ); - + // Load/use existing program for use with pipelines void loadProgram( T_String const& pipeline , T_String const& name ); @@ -210,6 +232,15 @@ struct T_ShaderManager T_String const& pipeline , T_String const& name ); + // Load/use existing program for standalone use + void loadProgram( T_String const& name ); + bool useExistingProgram( T_String const& name ); + + // Program management + T_Program_& initProgramRecord( // Init management data + T_String const& record ); + uint32_t newProgramRecord( ); // Allocate entry in index + T_ShaderInput const* getInput( T_String const& name ); @@ -217,6 +248,8 @@ struct T_ShaderManager void dereferenceProgram( const uint32_t index , T_String const& pipeline ); + void dereferenceProgram( + const uint32_t index ); void initPipeline( T_Pipeline_& pipeline ) const; void initProgram( T_Program_& program );