diff --git a/demo.srd b/demo.srd index a919db8..334adec 100644 --- a/demo.srd +++ b/demo.srd @@ -80,23 +80,21 @@ (fn dof-init () # Sampler used for the inputs - { NOT IMPLEMENTED - (sampler dof-sampler - (mipmaps no) - (wrapping clamp-edge) - (sampling linear) - (lod 0 0) - ) - } + (sampler dof-sampler + (mipmaps no) + (wrapping clamp-edge) + (sampling linear) + (lod 0 0) + ) # Texture & RT for pass 1 - (texture tx-dof-pass1 rgb-f16 vp-width vp-height) + (texture tx-dof-pass1 rgb-f16 $vp-width $vp-height) (framebuffer rt-dof-pass1 tx-dof-pass1) # Texture & RT for pass 2 - (texture tx-dof-pass2 rgb-f16 vp-width vp-height) + (texture tx-dof-pass2 rgb-f16 $vp-width $vp-height) (framebuffer rt-dof-pass2 tx-dof-pass2) - # MAYBE ? (alias tx-dof-output tx-dof-pass2) + # TODO MAYBE ? (alias tx-dof-output tx-dof-pass2) # Output debugging (odbg tx-dof-pass1 hdr "DoF - First pass") @@ -158,7 +156,6 @@ # Second pass (call dof-set-uniforms prg-dof-pass2) (use-texture 0 tx-dof-pass1 dof-sampler) - (use-pipeline pl-dof-pass2) (use-framebuffer rt-dof-pass2) (viewport 0 0 $vp-width $vp-height) diff --git a/opast.cc b/opast.cc index 243a826..b4f9afd 100644 --- a/opast.cc +++ b/opast.cc @@ -174,6 +174,23 @@ A_Node* opast::ASTVisitorBrowser( break; } + // Sampler definition may have LOD expressions + case A_Node::OP_SAMPLER: + { + auto& n( (T_SamplerInstrNode&) node ); + auto c = child; + if ( n.minLod( ) ) { + if ( c == 0 ) { + return n.minLod( ); + } + c--; + } + if ( n.maxLod( ) && c == 0 ) { + return n.maxLod( ); + } + break; + } + // Uniforms instruction case A_Node::OP_UNIFORMS: { @@ -381,3 +398,61 @@ T_OutputDebugInstrNode::T_OutputDebugInstrNode( description_( description.stringValue( ) ) , locDescription_( description.location( ) ) { } + + +/*= T_SamplerInstrNode =========================================================*/ + +T_Optional< T_SRDLocation > T_SamplerInstrNode::setSampling( + E_TexSampling mode , + T_SRDLocation const& location ) noexcept +{ + if ( sampling_ ) { + return sampling_->location; + } + sampling_ = T_Sampling_{ location , mode }; + return {}; +} + +T_Optional< T_SRDLocation > T_SamplerInstrNode::setMipmapSampling( + E_TexSampling mode , + T_SRDLocation const& location ) noexcept +{ + if ( mipmaps_ ) { + return mipmaps_->location; + } + mipmaps_ = T_Mipmaps_{ location , mode }; + return {}; +} + +T_Optional< T_SRDLocation > T_SamplerInstrNode::setNoMipmap( + T_SRDLocation const& location ) noexcept +{ + if ( mipmaps_ ) { + return mipmaps_->location; + } + mipmaps_ = T_Mipmaps_{ location , {} }; + return {}; +} + +T_Optional< T_SRDLocation > T_SamplerInstrNode::setWrapping( + E_TexWrap mode , + T_SRDLocation const& location ) noexcept +{ + if ( wrapping_ ) { + return wrapping_->location; + } + wrapping_ = T_Wrapping_{ location , mode }; + return {}; +} + +T_Optional< T_SRDLocation > T_SamplerInstrNode::setLOD( + T_SRDLocation const& location , + P_ExpressionNode min , + P_ExpressionNode max ) noexcept +{ + if ( lod_ ) { + return lod_->location; + } + lod_ = T_LOD_{ location , std::move( min ) , std::move( max ) }; + return {}; +} diff --git a/opast.hh b/opast.hh index c31ab1e..46eb72e 100644 --- a/opast.hh +++ b/opast.hh @@ -29,6 +29,7 @@ class A_Node OP_PIPELINE , // Shader pipeline declaration OP_PROFILE , // Profiling block OP_PROGRAM , // Shader program declaration + OP_SAMPLER , // Define sampler OP_SET , // Set instruction OP_TEXTURE , // Define texture OP_UNIFORMS , // Set uniforms @@ -602,6 +603,89 @@ class T_ProgramInstrNode : public A_InstructionNode { return idLocation_; } }; +// Sampler definition +class T_SamplerInstrNode : public A_InstructionNode +{ + private: + struct T_Sampling_ + { + T_SRDLocation location; + E_TexSampling mode; + }; + + struct T_Mipmaps_ + { + T_SRDLocation location; + T_Optional< E_TexSampling > mode; + }; + + struct T_Wrapping_ + { + T_SRDLocation location; + E_TexWrap mode; + }; + + struct T_LOD_ + { + T_SRDLocation location; + P_ExpressionNode min; + P_ExpressionNode max; + }; + + T_String id_; + T_SRDLocation idLocation_; + + T_Optional< T_Sampling_ > sampling_; + T_Optional< T_Mipmaps_ > mipmaps_; + T_Optional< T_Wrapping_ > wrapping_; + T_Optional< T_LOD_ > lod_; + + public: + T_SamplerInstrNode( + T_InstrListNode& parent , + T_SRDToken const& id ) noexcept + : A_InstructionNode( OP_SAMPLER , parent ) , + id_( id.stringValue( ) ) , + idLocation_( id.location( ) ) + { } + + T_String const& id( ) const noexcept + { return id_; } + T_SRDLocation const& idLocation( ) const noexcept + { return idLocation_; } + + // Attempt to set sampling mode, mipmap mode, wrapping mode or + // LOD minimal/maximal, returning the location of the previous + // definition if there was one. + T_Optional< T_SRDLocation > setSampling( + E_TexSampling mode , + T_SRDLocation const& location ) noexcept; + T_Optional< T_SRDLocation > setMipmapSampling( + E_TexSampling mode , + T_SRDLocation const& location ) noexcept; + T_Optional< T_SRDLocation > setNoMipmap( + T_SRDLocation const& location ) noexcept; + T_Optional< T_SRDLocation > setWrapping( + E_TexWrap mode , + T_SRDLocation const& location ) noexcept; + T_Optional< T_SRDLocation > setLOD( + T_SRDLocation const& location , + P_ExpressionNode min , + P_ExpressionNode max ) noexcept; + + // Get either the defined values or the defaults + E_TexSampling sampling( ) const noexcept + { return sampling_ ? sampling_->mode : E_TexSampling::NEAREST; } + T_Optional< E_TexSampling > mipmap( ) const noexcept + { return mipmaps_ ? mipmaps_->mode : T_Optional< E_TexSampling >{}; } + E_TexWrap wrapping( ) const noexcept + { return wrapping_ ? wrapping_->mode : E_TexWrap::REPEAT; } + A_ExpressionNode* minLod( ) const noexcept + { return lod_ ? lod_->min.get( ) : nullptr; } + A_ExpressionNode* maxLod( ) const noexcept + { return lod_ ? lod_->max.get( ) : nullptr; } +}; + // Setting a global variable class T_SetInstrNode : public A_InstructionNode { diff --git a/opparser.cc b/opparser.cc index 7e853cb..e81533d 100644 --- a/opparser.cc +++ b/opparser.cc @@ -22,6 +22,7 @@ struct T_ParserImpl_ PIPELINE , PROFILE , PROGRAM , + SAMPLER , SET , TEXTURE , UNIFORMS_FLT , @@ -48,6 +49,7 @@ struct T_ParserImpl_ add( "pipeline" , E_InstrType::PIPELINE ); add( "profiling" , E_InstrType::PROFILE ); add( "program" , E_InstrType::PROGRAM ); + add( "sampler" , E_InstrType::SAMPLER ); add( "set" , E_InstrType::SET ); add( "texture" , E_InstrType::TEXTURE ); add( "uniforms" , E_InstrType::UNIFORMS_FLT ); @@ -193,6 +195,21 @@ struct T_ParserImpl_ M_DPARSER_( Pipeline ); M_DPARSER_( Profile ); M_DPARSER_( Program ); + + M_DPARSER_( Sampler ); + void parseSamplerSampling( + T_SamplerInstrNode& instruction , + T_SRDList const& input ); + void parseSamplerMipmaps( + T_SamplerInstrNode& instruction , + T_SRDList const& input ); + void parseSamplerWrapping( + T_SamplerInstrNode& instruction , + T_SRDList const& input ); + void parseSamplerLOD( + T_SamplerInstrNode& instruction , + T_SRDList const& input ); + M_DPARSER_( Set ); M_DPARSER_( Texture ); @@ -473,6 +490,7 @@ void T_ParserImpl_::parseInstructions( M_CASE_( PIPELINE , Pipeline ); M_CASE_( PROFILE , Profile ); M_CASE_( PROGRAM , Program ); + M_CASE_( SAMPLER , Sampler ); M_CASE_( SET , Set ); M_CASE_( TEXTURE , Texture ); M_CASE_( UNIFORMS_FLT , Uniforms ); @@ -797,6 +815,176 @@ M_INSTR_( Program ) /*----------------------------------------------------------------------------*/ +M_INSTR_( Sampler ) +{ + const auto ni{ input.size( ) }; + if ( ni == 1 || input[ 0 ].type( ) != E_SRDTokenType::WORD ) { + errors.addNew( "sampler identifier expected" , + input[ ni == 1 ? 0 : 1 ].location( ) ); + return; + } + + auto& instr{ instructions.add< T_SamplerInstrNode >( input[ 1 ] ) }; + instr.location( ) = input[ 0 ].location( ); + + for ( auto i = 2u ; i < ni ; i ++ ) { + T_SRDToken const& token( input[ i ] ); + if ( token.type( ) != E_SRDTokenType::LIST || token.list( ).empty( ) ) { + errors.addNew( "list expected" , token.location( ) ); + continue; + } + + T_SRDToken const& et( token.list( )[ 0 ] ); + if ( et.type( ) != E_SRDTokenType::WORD ) { + errors.addNew( "'sampling', 'mipmaps', 'wrapping' or 'lod' expected" , + et.location( ) ); + continue; + } + + T_String const& etn( et.stringValue( ) ); + if ( etn == "sampling" ) { + parseSamplerSampling( instr , token.list( ) ); + } else if ( etn == "mipmaps" ) { + parseSamplerMipmaps( instr , token.list( ) ); + } else if ( etn == "wrapping" ) { + parseSamplerWrapping( instr , token.list( ) ); + } else if ( etn == "lod" ) { + parseSamplerLOD( instr , token.list( ) ); + } else { + errors.addNew( "'sampling', 'mipmaps', 'wrapping' or 'lod' expected" , + et.location( ) ); + } + } +} + +void T_ParserImpl_::parseSamplerSampling( + T_SamplerInstrNode& instruction , + T_SRDList const& input ) +{ + if ( input.size( ) == 1 || input[ 1 ].type( ) != E_SRDTokenType::WORD ) { + errors.addNew( "sampling mode expected" , + input[ input.size( ) == 1 ? 0 : 1 ].location( ) ); + return; + } + + bool ok = true; + T_String const& sMode{ input[ 1 ].stringValue( ) }; + E_TexSampling smp{ E_TexSampling::NEAREST }; + if ( sMode == "linear" ) { + smp = E_TexSampling::LINEAR; + } else if ( sMode != "nearest" ) { + errors.addNew( "'nearest' or 'linear' expected" , input[ 1 ].location( ) ); + ok = false; + } + + if ( input.size( ) > 2 ) { + errors.addNew( "too many arguments" , input[ 2 ].location( ) ); + } + + const auto prev{ instruction.setSampling( smp , input[ 0 ].location( ) ) }; + if ( prev && ok ) { + T_StringBuilder sb; + sb << "sampling mode already set at " << *prev; + errors.addNew( std::move( sb ) , input[ 0 ].location( ) ); + } +} + +void T_ParserImpl_::parseSamplerMipmaps( + T_SamplerInstrNode& instruction , + T_SRDList const& input ) +{ + if ( input.size( ) == 1 || input[ 1 ].type( ) != E_SRDTokenType::WORD ) { + errors.addNew( "mipmap sampling mode expected" , + input[ input.size( ) == 1 ? 0 : 1 ].location( ) ); + return; + } + + bool ok = true; + T_String const& sMode{ input[ 1 ].stringValue( ) }; + T_Optional< E_TexSampling > smp{ }; + if ( sMode == "linear" ) { + smp = E_TexSampling::LINEAR; + } else if ( sMode == "nearest" ) { + smp = E_TexSampling::NEAREST; + } else if ( sMode != "no" ) { + errors.addNew( "'no', 'nearest' or 'linear' expected" , input[ 1 ].location( ) ); + ok = false; + } + + if ( input.size( ) > 2 ) { + errors.addNew( "too many arguments" , input[ 2 ].location( ) ); + } + + const auto prev{ smp + ? instruction.setMipmapSampling( *smp , input[ 0 ].location( ) ) + : instruction.setNoMipmap( input[ 0 ].location( ) ) }; + if ( prev && ok ) { + T_StringBuilder sb; + sb << "mipmap sampling mode already set at " << *prev; + errors.addNew( std::move( sb ) , input[ 0 ].location( ) ); + } +} + +void T_ParserImpl_::parseSamplerWrapping( + T_SamplerInstrNode& instruction , + T_SRDList const& input ) +{ + if ( input.size( ) == 1 || input[ 1 ].type( ) != E_SRDTokenType::WORD ) { + errors.addNew( "wrapping mode expected" , + input[ input.size( ) == 1 ? 0 : 1 ].location( ) ); + return; + } + + bool ok = true; + T_String const& sMode{ input[ 1 ].stringValue( ) }; + E_TexWrap smp{ E_TexWrap::REPEAT }; + if ( sMode == "clamp-border" ) { + smp = E_TexWrap::CLAMP_BORDER; + } else if ( sMode == "clamp-edge" ) { + smp = E_TexWrap::CLAMP_EDGE; + } else if ( sMode != "repeat" ) { + errors.addNew( "'repeat', 'clamp-border' or 'clamp-edge' expected" , + input[ 1 ].location( ) ); + ok = false; + } + + if ( input.size( ) > 2 ) { + errors.addNew( "too many arguments" , input[ 2 ].location( ) ); + } + + const auto prev{ instruction.setWrapping( smp , input[ 0 ].location( ) ) }; + if ( prev && ok ) { + T_StringBuilder sb; + sb << "wrapping mode already set at " << *prev; + errors.addNew( std::move( sb ) , input[ 0 ].location( ) ); + } +} + +void T_ParserImpl_::parseSamplerLOD( + T_SamplerInstrNode& instruction , + T_SRDList const& input ) +{ + if ( input.size( ) < 3 ) { + errors.addNew( "min/max LODs expected" , input[ 0 ].location( ) ); + return; + } + if ( input.size( ) > 3 ) { + errors.addNew( "too many arguments" , input[ 2 ].location( ) ); + } + + P_ExpressionNode min{ parseExpression( instruction , input[ 1 ] ) }; + P_ExpressionNode max{ parseExpression( instruction , input[ 2 ] ) }; + const auto prev{ instruction.setLOD( input[ 0 ].location( ) , + std::move( min ) , std::move( max ) ) }; + if ( prev ) { + T_StringBuilder sb; + sb << "min/max LOD already set at " << *prev; + errors.addNew( std::move( sb ) , input[ 0 ].location( ) ); + } +} + +/*----------------------------------------------------------------------------*/ + M_INSTR_( Set ) { bool ok{ true };