Shaders - Made it possible to load programs separately

This commit is contained in:
Emmanuel BENOîT 2017-11-14 15:27:25 +01:00
parent 71f6fed1ee
commit 96d821828f
2 changed files with 237 additions and 45 deletions

View file

@ -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::T_ShaderPipeline( ) T_ShaderPipeline::T_ShaderPipeline( )
@ -332,6 +440,7 @@ void T_ShaderPipeline::enable( ) const
auto const* pl( Globals::Shaders( ).pipelines_.get( id_ ) ); auto const* pl( Globals::Shaders( ).pipelines_.get( id_ ) );
if ( pl && pl->id ) { if ( pl && pl->id ) {
glUseProgram( 0 );
glBindProgramPipeline( pl->id ); 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( T_ShaderPipeline T_ShaderManager::pipeline(
std::initializer_list< T_String > shaders ) std::initializer_list< T_String > shaders )
{ {
@ -576,7 +693,7 @@ T_ShaderPipeline T_ShaderManager::pipeline(
pipelines_.add( T_Pipeline_{ id , shaders } ); pipelines_.add( T_Pipeline_{ id , shaders } );
auto& p( *pipelines_.get( id ) ); auto& p( *pipelines_.get( id ) );
for ( auto const& pName : shaders ) { for ( auto const& pName : shaders ) {
loadProgram( p.idString , (char*)( pName.toOSString( ).data( ) ) ); loadProgram( p.idString , pName );
} }
initPipeline( p ); initPipeline( p );
@ -623,7 +740,7 @@ void T_ShaderManager::update( )
auto const* p( programIndex_.get( *it ) ); auto const* p( programIndex_.get( *it ) );
if ( p ) { if ( p ) {
auto& pr( programs_[ *p ] ); auto& pr( programs_[ *p ] );
for ( auto const& ref : pr.references ) { for ( auto const& ref : pr.plReferences ) {
if ( !temp.contains( ref ) ) { if ( !temp.contains( ref ) ) {
temp.add( 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( void T_ShaderManager::loadProgram(
T_String const& pipeline , T_String const& pipeline ,
T_String const& name ) T_String const& name )
{ {
if ( useExistingProgram( pipeline , name ) ) { if ( !useExistingProgram( pipeline , name ) ) {
return; 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( bool T_ShaderManager::useExistingProgram(
@ -716,12 +803,67 @@ bool T_ShaderManager::useExistingProgram(
if ( !pos ) { if ( !pos ) {
return false; return false;
} }
auto& refs( programs_[ *pos ].references ); auto& refs( programs_[ *pos ].plReferences );
assert( !refs.contains( pipeline ) ); assert( !refs.contains( pipeline ) );
refs.add( pipeline ); refs.add( pipeline );
return true; 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_ShaderInput const* T_ShaderManager::getInput(
T_String const& name ) T_String const& name )
@ -772,11 +914,25 @@ void T_ShaderManager::dereferenceProgram(
T_String const& pipeline ) T_String const& pipeline )
{ {
auto& program( programs_[ index ] ); auto& program( programs_[ index ] );
auto& refs( program.references ); auto& refs( program.plReferences );
const auto plidx( refs.indexOf( pipeline ) ); const auto plidx( refs.indexOf( pipeline ) );
assert( plidx >= 0 ); assert( plidx >= 0 );
refs.remove( plidx ); 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; return;
} }
resetProgram( program ); resetProgram( program );
@ -997,12 +1153,15 @@ void T_ShaderManager::makeUI( )
ImGui::Begin( "Shaders" ); ImGui::Begin( "Shaders" );
const auto n( std::count_if( programs_.begin( ) , programs_.end( ) , 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; std::vector< size_t > indices;
const auto rn = programs_.size( ); const auto rn = programs_.size( );
for ( auto i = 0u ; i < rn ; i ++ ) { 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 ); indices.push_back( i );
} }
} }
@ -1013,8 +1172,8 @@ void T_ShaderManager::makeUI( )
if ( pa.code.errors.size( ) != pb.code.errors.size( ) ) { if ( pa.code.errors.size( ) != pb.code.errors.size( ) ) {
return pa.code.errors.size( ) > pb.code.errors.size( ); return pa.code.errors.size( ) > pb.code.errors.size( );
} }
if ( pa.references.size( ) != pb.references.size( ) ) { if ( pa.plReferences.size( ) != pb.plReferences.size( ) ) {
return pa.references.size( ) > pb.references.size( ); return pa.plReferences.size( ) > pb.plReferences.size( );
} }
return programs_[ a ].name < programs_[ b ].name; return programs_[ a ].name < programs_[ b ].name;
} ); } );
@ -1034,7 +1193,7 @@ void T_ShaderManager::makeUI( )
} }
ImGui::SameLine( 400 ); ImGui::SameLine( 400 );
ImGui::Text( "Usage: %u" , program.references.size( ) ); ImGui::Text( "Usage: %u" , program.plReferences.size( ) + program.saReferences );
ImGui::SameLine( 550 ); ImGui::SameLine( 550 );
if ( program.code.errors.empty( ) ) { if ( program.code.errors.empty( ) ) {
ImGui::PushStyleColor( ImGuiCol_Text , ImVec4( .6 , 1 , .6 , 1 ) ); ImGui::PushStyleColor( ImGuiCol_Text , ImVec4( .6 , 1 , .6 , 1 ) );

View file

@ -119,6 +119,26 @@ struct T_ShaderError
struct T_ShaderManager; 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 struct T_ShaderPipeline
{ {
friend struct T_ShaderManager; friend struct T_ShaderManager;
@ -143,6 +163,7 @@ struct T_ShaderPipeline
struct T_ShaderManager struct T_ShaderManager
{ {
friend struct T_ShaderPipeline; friend struct T_ShaderPipeline;
friend struct T_ShaderProgram;
struct T_ShaderCode struct T_ShaderCode
{ {
@ -157,6 +178,7 @@ struct T_ShaderManager
T_ShaderManager( ) noexcept; T_ShaderManager( ) noexcept;
T_ShaderProgram program( T_String const& name );
T_ShaderPipeline pipeline( T_ShaderPipeline pipeline(
std::initializer_list< T_String > shaders ); std::initializer_list< T_String > shaders );
@ -183,7 +205,8 @@ struct T_ShaderManager
struct T_Program_ struct T_Program_
{ {
T_String name; T_String name;
T_Array< T_String > references; T_Array< T_String > plReferences;
uint32_t saReferences{ 0 };
T_ShaderCode code; T_ShaderCode code;
GLuint id; GLuint id;
T_Optional< T_WatchedFiles > watch; T_Optional< T_WatchedFiles > watch;
@ -201,8 +224,7 @@ struct T_ShaderManager
T_KeyValueTable< T_String , T_Array< T_String > > missing_; T_KeyValueTable< T_String , T_Array< T_String > > missing_;
T_Array< T_String > updates_; T_Array< T_String > updates_;
uint32_t newProgramRecord( ); // Load/use existing program for use with pipelines
void loadProgram( void loadProgram(
T_String const& pipeline , T_String const& pipeline ,
T_String const& name ); T_String const& name );
@ -210,6 +232,15 @@ struct T_ShaderManager
T_String const& pipeline , T_String const& pipeline ,
T_String const& name ); 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_ShaderInput const* getInput(
T_String const& name ); T_String const& name );
@ -217,6 +248,8 @@ struct T_ShaderManager
void dereferenceProgram( void dereferenceProgram(
const uint32_t index , const uint32_t index ,
T_String const& pipeline ); T_String const& pipeline );
void dereferenceProgram(
const uint32_t index );
void initPipeline( T_Pipeline_& pipeline ) const; void initPipeline( T_Pipeline_& pipeline ) const;
void initProgram( T_Program_& program ); void initProgram( T_Program_& program );