diff --git a/demo.srd b/demo.srd index 7576a85..7f603ff 100644 --- a/demo.srd +++ b/demo.srd @@ -1,27 +1,82 @@ (init # Compute viewport size - (if (gt width height) + (if (cmp-gt width height) ( - (set vp-height height) - (set vp-width (mul height (div 16 9))) - (set vp-x (div (sub width vp-width) 2)) + (set vp-height $height) + (set vp-width (mul $height (div 16 9))) + (set vp-x (div (sub $width $vp-width) 2)) (set vp-y 0) )( - (set vp-width width) - (set vp-height (div width (div 16 9))) - (set vp-y (div (sub height vp-height) 2)) + (set vp-width $width) + (set vp-height (div $width (div 16 9))) + (set vp-y (div (sub $height $vp-height) 2)) (set vp-x 0) ) ) (program prg-fullscreen "fullscreen.v.glsl") + + (call scene-init) (call dof-init) ) (frame (profiling "Frame render" - { FIXME: other stages } - (call dof-main { FIXME: args here }) + (call scene-main) + (call dof-main tx-scene-output tx-scene-depth) + ) +) + + +################################################################################ +# Scene + +(fn scene-init () + (texture tx-scene-output rgb-f16 vp-width vp-height) + (texture tx-scene-depth r-f16 vp-width vp-height) + { NOT IMPLEMENTED + (framebuffer rt-scene + (colors tx-scene-output tx-scene-depth)) + } + + (program prg-scene-p1 "scene.f.glsl") + # NOT IMPLEMENTED (set-uniforms prg-scene-p1 1 $vp-width $vp-height) + (pipeline pl-scene-p1 prg-fullscreen prg-scene-p1) + + { NOT IMPLEMENTED + (odbg tx-scene-output hdr "Scene output") + (odbg tx-scene-depth depth "Scene depth") + } +) + +(fn scene-main () + (profiling "Scene render" + { NOT IMPLEMENTED + (set-uniforms prg-scene-p1 0 $time) + (set-uniforms prg-scene-p1 2 + (get-input "camera-pos-x") + (get-input "camera-pos-y") + (get-input "camera-pos-z") + ) + (set-uniforms prg-scene-p1 3 + (get-input "camera-lookat-x") + (get-input "camera-lookat-y") + (get-input "camera-lookat-z") + ) + (set-uniforms prg-scene-p1 4 + (get-input "camera-up-x") + (get-input "camera-up-y") + (get-input "camera-up-z") + ) + (set-uniforms prg-scene-p1 5 + (get-input "camera-nearplane") + ) + # FIXME MOAR UNIFORMS! + (use-pipeline pl-scene-p1) + (use-framebuffer rt-scene) + } + (viewport 0 0 $vp-width $vp-height) + (fullscreen) ) ) @@ -30,33 +85,43 @@ (fn dof-init () # Sampler used for the inputs - (sampler dof-sampler - (mipmaps no) - (wrapping clamp-edge) - (sampling linear) - (lod 0 0) - ) + { NOT IMPLEMENTED + (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) - (framebuffer rt-dof-pass1 (colors tx-dof-pass1)) + { NOT IMPLEMENTED + (framebuffer rt-dof-pass1 (colors tx-dof-pass1)) + } # Texture & RT for pass 2 (texture tx-dof-pass2 rgb-f16 vp-width vp-height) - (framebuffer rt-dof-pass2 (colors tx-dof-pass2)) - (alias tx-dof-output tx-dof-pass2) + { NOT IMPLEMENTED + (framebuffer rt-dof-pass2 (colors tx-dof-pass2)) + } + # MAYBE ? (alias tx-dof-output tx-dof-pass2) # Output debugging - (odbg tx-dof-pass1 hdr "DoF - First pass") - (odbg tx-dof-pass2 hdr "DoF - Output") + { NOT IMPLEMENTED + (odbg tx-dof-pass1 hdr "DoF - First pass") + (odbg tx-dof-pass2 hdr "DoF - Output") + } # Programs (program prg-dof-pass1 "dof-pass1.f.glsl") (program prg-dof-pass2 "dof-pass2.f.glsl") - (set-uniforms-integer prg-dof-pass1 0 1) - (set-uniforms-integer prg-dof-pass1 1 1) - (set-uniforms-integer prg-dof-pass2 0 1) - (set-uniforms-integer prg-dof-pass2 1 1) + { NOT IMPLEMENTED + (set-uniforms-integer prg-dof-pass1 0 1) + (set-uniforms-integer prg-dof-pass1 1 1) + (set-uniforms-integer prg-dof-pass2 0 1) + (set-uniforms-integer prg-dof-pass2 1 1) + } # Pipelines (pipeline pl-dof-pass1 prg-fullscreen prg-dof-pass1) @@ -70,24 +135,28 @@ (input dof-samples 16) # Input overrides - (ui-overrides "Post-processing" "Depth of Field" - (float dof-sharp-distance (min 0) (max 1000) (step .1)) - (float dof-sharp-range (min 0) (max 500) (step .1)) - (float dof-falloff (min 0) (max 500) (step .1)) - (float dof-max-blur (min 1) (max 64) (step .1)) - (int dof-samples (min 1) (max 64) (step .1)) - ) + { NOT IMPLEMENTED + (ui-overrides "Post-processing" "Depth of Field" + (float dof-sharp-distance (min 0) (max 1000) (step .1)) + (float dof-sharp-range (min 0) (max 500) (step .1)) + (float dof-falloff (min 0) (max 500) (step .1)) + (float dof-max-blur (min 1) (max 64) (step .1)) + (int dof-samples (min 1) (max 64) (step .1)) + ) + } ) (fn dof-set-uniforms (prog) - (set-uniforms prog 2 ( - (get-input dof-sharp-distance) - (get-input dof-sharp-range) - (get-input dof-falloff) - (get-input dof-max-blur) - )) - (set-uniforms prog 3 ((get-input dof-samples))) - (set-uniforms prog 4 (vp-width vp-height time)) + { NOT IMPLEMENTED + (set-uniforms prog 2 + (get-input dof-sharp-distance) + (get-input dof-sharp-range) + (get-input dof-falloff) + (get-input dof-max-blur) + ) + (set-uniforms prog 3 (get-input dof-samples)) + (set-uniforms prog 4 $vp-width $vp-height $time) + } ) (fn dof-main (in-image in-depth) @@ -104,8 +173,10 @@ # 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) (fullscreen) ) ) diff --git a/opast.cc b/opast.cc index 5398795..7e00c2a 100644 --- a/opast.cc +++ b/opast.cc @@ -97,8 +97,11 @@ A_Node* opast::ASTVisitorBrowser( // Nodes that do not have children case A_Node::EXPR_ID: case A_Node::EXPR_CONST: + case A_Node::EXPR_INPUT: case A_Node::OP_PROGRAM: case A_Node::OP_PIPELINE: - case A_Node::OP_INPUT: + case A_Node::OP_INPUT: case A_Node::OP_FULLSCREEN: + case A_Node::OP_USE_FRAMEBUFFER: case A_Node::OP_USE_PIPELINE: + case A_Node::OP_USE_PROGRAM: case A_Node::OP_USE_TEXTURE: break; // Profile instruction @@ -168,6 +171,24 @@ A_Node* opast::ASTVisitorBrowser( break; } + // Viewport instruction + case A_Node::OP_VIEWPORT: + { + auto& n( (T_ViewportInstrNode&) node ); + auto c = child; + for ( int i = 0 ; i < 4 ; i ++ ) { + T_ViewportInstrNode::E_Parameter p{ + T_ViewportInstrNode::E_Parameter( i ) }; + if ( n.hasParameter( p ) ) { + if ( c == 0 ) { + return &n.parameter( p ); + } + c --; + } + } + break; + } + } return nullptr; } @@ -314,6 +335,7 @@ struct T_ParserImpl_ { enum class E_InstrType { CALL , + FULLSCREEN , IF , INPUT , PIPELINE , @@ -321,6 +343,11 @@ struct T_ParserImpl_ PROGRAM , SET , TEXTURE , + USE_FRAMEBUFFER , + USE_PIPELINE , + USE_PROGRAM , + USE_TEXTURE , + VIEWPORT , }; const T_KeyValueTable< T_String , E_InstrType > instrMap{ ([]() { @@ -330,6 +357,7 @@ struct T_ParserImpl_ } }; add( "call" , E_InstrType::CALL ); + add( "fullscreen" , E_InstrType::FULLSCREEN ); add( "if" , E_InstrType::IF ); add( "input" , E_InstrType::INPUT ); add( "pipeline" , E_InstrType::PIPELINE ); @@ -337,6 +365,11 @@ struct T_ParserImpl_ add( "program" , E_InstrType::PROGRAM ); add( "set" , E_InstrType::SET ); add( "texture" , E_InstrType::TEXTURE ); + add( "use-framebuffer" , E_InstrType::USE_FRAMEBUFFER ); + add( "use-pipeline" , E_InstrType::USE_PIPELINE ); + add( "use-program" , E_InstrType::USE_PROGRAM ); + add( "use-texture" , E_InstrType::USE_TEXTURE ); + add( "viewport" , E_InstrType::VIEWPORT ); return temp; })( ) }; @@ -451,6 +484,15 @@ struct T_ParserImpl_ M_DPARSER_( Program ); M_DPARSER_( Set ); M_DPARSER_( Texture ); + M_DPARSER_( UseFramebuffer ); + M_DPARSER_( UsePipeline ); + M_DPARSER_( UseProgram ); + void parseUseCommon( + T_InstrListNode& instructions , + T_SRDList const& input , + T_UseInstrNode::E_Type type ) noexcept; + M_DPARSER_( UseTexture ); + M_DPARSER_( Viewport ); #undef M_DPARSER_ @@ -711,6 +753,15 @@ void T_ParserImpl_::parseInstructions( M_CASE_( PROGRAM , Program ); M_CASE_( SET , Set ); M_CASE_( TEXTURE , Texture ); + M_CASE_( USE_FRAMEBUFFER , UseFramebuffer ); + M_CASE_( USE_PIPELINE , UsePipeline ); + M_CASE_( USE_PROGRAM , UseProgram ); + M_CASE_( USE_TEXTURE , UseTexture ); + M_CASE_( VIEWPORT , Viewport ); + + case E_InstrType::FULLSCREEN: + instructions.add< T_FullscreenInstrNode >( ).location( ) = iname.location( ); + break; } #undef M_CASE_ } @@ -983,6 +1034,102 @@ M_INSTR_( Texture ) /*----------------------------------------------------------------------------*/ +M_INSTR_( UseFramebuffer ) +{ + parseUseCommon( instructions , input , T_UseInstrNode::FRAMEBUFFER ); +} + +M_INSTR_( UsePipeline ) +{ + parseUseCommon( instructions , input , T_UseInstrNode::PIPELINE ); +} + +M_INSTR_( UseProgram ) +{ + parseUseCommon( instructions , input , T_UseInstrNode::PROGRAM ); +} + +void T_ParserImpl_::parseUseCommon( + T_InstrListNode& instructions , + T_SRDList const& input , + T_UseInstrNode::E_Type type ) noexcept +{ + if ( input.size( ) == 1 || input[ 1 ].type( ) != E_SRDTokenType::WORD ) { + errors.addNew( "resource identifier expected" , + input[ input.size( ) == 1 ? 0 : 1 ].location( ) ); + return; + } + if ( input.size( ) > 2 ) { + errors.addNew( "too many arguments" , input[ 2 ].location( ) ); + } + + auto& instr{ instructions.add< T_UseInstrNode >( type , input[ 1 ] ) }; + instr.location( ) = input[ 0 ].location( ); +} + +/*----------------------------------------------------------------------------*/ + +M_INSTR_( UseTexture ) +{ + if ( input.size( ) == 1 || !input[ 1 ].isInteger( ) ) { + errors.addNew( "bank number expected" , + input[ input.size( ) == 1 ? 0 : 1 ].location( ) ); + return; + } + if ( input[ 1 ].longValue( ) < 0 || input[ 1 ].longValue( ) > UINT32_MAX ) { + errors.addNew( "invalid bank number" , input[ 1 ].location( ) ); + return; + } + + if ( input.size( ) == 2 || input[ 2 ].type( ) != E_SRDTokenType::WORD ) { + errors.addNew( "texture identifier expected" , + input[ input.size( ) == 2 ? 0 : 2 ].location( ) ); + return; + } + if ( input.size( ) == 3 || input[ 3 ].type( ) != E_SRDTokenType::WORD ) { + errors.addNew( "sampler identifier expected" , + input[ input.size( ) == 3 ? 0 : 3 ].location( ) ); + return; + } + if ( input.size( ) > 4 ) { + errors.addNew( "too many arguments" , input[ 4 ].location( ) ); + } + + auto& instr{ instructions.add< T_UseTextureInstrNode >( + input[ 1 ] , input[ 2 ] , input[ 3 ] ) }; + instr.location( ) = input[ 0 ].location( ); +} + +/*----------------------------------------------------------------------------*/ + +M_INSTR_( Viewport ) +{ + auto& instr{ instructions.add< T_ViewportInstrNode >( ) }; + instr.location( ) = input[ 0 ].location( ); + + for ( auto i = 1u ; i < 5 ; i ++ ) { + T_ViewportInstrNode::E_Parameter p{ + T_ViewportInstrNode::E_Parameter( i ) }; + if ( input.size( ) < i ) { + T_StringBuilder sb; + sb << "missing "; + switch ( p ) { + case T_ViewportInstrNode::PX: sb << "X"; break; + case T_ViewportInstrNode::PY: sb << "Y"; break; + case T_ViewportInstrNode::PWIDTH: sb << "width"; break; + case T_ViewportInstrNode::PHEIGHT: sb << "height"; break; + } + sb << " parameter"; + errors.addNew( std::move( sb ) , input[ 0 ].location( ) ); + return; + } else { + instr.setParameter( p , parseExpression( instr , input[ i ] ) ); + } + } +} + +/*----------------------------------------------------------------------------*/ + P_ExpressionNode T_ParserImpl_::parseExpression( A_Node& parent , T_SRDToken const& token ) noexcept @@ -1012,6 +1159,20 @@ P_ExpressionNode T_ParserImpl_::parseOperation( return {}; } + if ( opId.stringValue( ) == "get-input" ) { + if ( opList.size( ) == 1 || !opList[ 1 ].isText( ) ) { + errors.addNew( "input identifier expected" , + opList[ opList.size( ) == 1 ? 0 : 1 ].location( ) ); + return { }; + } + if ( opList.size( ) > 2 ) { + errors.addNew( "too many arguments" , opList[ 2 ].location( ) ); + } + auto node{ NewOwned< T_InputExprNode >( parent , opList[ 1 ] ) }; + node->location( ) = opList[ 0 ].location( ); + return node; + } + if ( binOpMap.contains( opId.stringValue( ) ) ) { return parseBinOp( parent , opList , *binOpMap.get( opId.stringValue( ) ) ); diff --git a/opast.hh b/opast.hh index 69fa112..092b833 100644 --- a/opast.hh +++ b/opast.hh @@ -25,12 +25,19 @@ class A_Node // OP_CALL , // Function call OP_COND , // Conditional instruction + OP_FULLSCREEN , // Draw a fullscreen quad OP_INPUT , // Input declaration OP_PIPELINE , // Shader pipeline declaration OP_PROFILE , // Profiling block OP_PROGRAM , // Shader program declaration OP_SET , // Set instruction OP_TEXTURE , // Define texture + OP_VIEWPORT , // Set viewport + // "Use-" instructions + OP_USE_FRAMEBUFFER , + OP_USE_PIPELINE , + OP_USE_PROGRAM , + OP_USE_TEXTURE , // Unary operators EXPR_NEG , EXPR_INV , EXPR_NOT , EXPR_SIN , EXPR_COS , EXPR_TAN , @@ -45,6 +52,7 @@ class A_Node EXPR_CMP_LT , EXPR_CMP_LE , // EXPR_ID , // Variable access + EXPR_INPUT , // Input value access EXPR_CONST , // Numeric constant }; @@ -361,6 +369,15 @@ class T_CondInstrNode : public A_InstructionNode { return *defaultCase_; } }; +// Fullscreen quad instruction +class T_FullscreenInstrNode : public A_InstructionNode +{ + public: + T_FullscreenInstrNode( T_InstrListNode& parent ) noexcept + : A_InstructionNode( OP_FULLSCREEN , parent , E_InstrRestriction::INIT ) + { } +}; + // Input declaration class T_InputInstrNode : public A_InstructionNode { @@ -421,6 +438,11 @@ class T_PipelineInstrNode : public A_InstructionNode idLocation_{ } { } + T_String const& id( ) const noexcept + { return id_; } + T_SRDLocation const& idLocation( ) const noexcept + { return idLocation_; } + // Add a program identifier. The token is assumed to be a valid word, // and the list of programs is assumed not to be full. If the identifer // is already in the pipeline's list, the location of the first @@ -482,6 +504,11 @@ class T_ProgramInstrNode : public A_InstructionNode path_( pathToken.stringValue( ) ) , pathLocation_( pathToken.location( ) ) { } + + T_String const& id( ) const noexcept + { return id_; } + T_SRDLocation const& idLocation( ) const noexcept + { return idLocation_; } }; // Setting a global variable @@ -495,12 +522,12 @@ class T_SetInstrNode : public A_InstructionNode public: T_SetInstrNode( T_InstrListNode& parent , T_SRDToken const& idToken ) noexcept - : A_InstructionNode( OP_PROGRAM , parent ) , + : A_InstructionNode( OP_SET , parent ) , id_( idToken.stringValue( ) ) , idLocation_( idToken.location( ) ) { } - T_String const& identifier( ) const noexcept + T_String const& id( ) const noexcept { return id_; } T_SRDLocation const& idLocation( ) const noexcept { return idLocation_; } @@ -528,11 +555,16 @@ class T_TextureInstrNode : public A_InstructionNode T_InstrListNode& parent , T_SRDToken const& id , E_TexType type ) noexcept - : A_InstructionNode( OP_PROGRAM , parent , E_InstrRestriction::FRAME ) , + : A_InstructionNode( OP_TEXTURE , parent , E_InstrRestriction::FRAME ) , id_( id.stringValue( ) ) , idLocation_( id.location( ) ) , type_( type ) { } + T_String const& id( ) const noexcept + { return id_; } + T_SRDLocation const& idLocation( ) const noexcept + { return idLocation_; } + void setWidth( P_ExpressionNode width ) noexcept { width_ = std::move( width ); } bool hasWidth( ) const noexcept @@ -548,6 +580,99 @@ class T_TextureInstrNode : public A_InstructionNode { return *height_; } }; +// Use-* instructions (framebuffers, programs, pipelines) +// Also serves as the base for use-texture +class T_UseInstrNode : public A_InstructionNode +{ + public: + enum E_Type { + FRAMEBUFFER , PIPELINE , PROGRAM , TEXTURE + }; + + private: + T_String id_; + T_SRDLocation idLocation_; + + public: + T_UseInstrNode( T_InstrListNode& parent , + const E_Type type , + T_SRDToken const& identifier ) noexcept + : A_InstructionNode( ([type]() { + switch ( type ) { + case FRAMEBUFFER: return OP_USE_FRAMEBUFFER; + case PIPELINE: return OP_USE_PIPELINE; + case PROGRAM: return OP_USE_PROGRAM; + case TEXTURE: return OP_USE_TEXTURE; + } + std::abort( ); + } )( ) , parent ) , + id_( identifier.stringValue( ) ) , + idLocation_( identifier.location( ) ) + { } + + T_String const& id( ) const noexcept + { return id_; } + T_SRDLocation const& idLocation( ) const noexcept + { return idLocation_; } +}; + +// Texture/sampler use instructions +class T_UseTextureInstrNode : public T_UseInstrNode +{ + private: + uint32_t bank_; + T_SRDLocation bankLocation_; + T_String samplerId_; + T_SRDLocation samplerIdLocation_; + + public: + T_UseTextureInstrNode( T_InstrListNode& parent , + T_SRDToken const& bank , + T_SRDToken const& identifier , + T_SRDToken const& sampler ) noexcept + : T_UseInstrNode( parent , TEXTURE , identifier ) , + bank_( bank.longValue( ) ) , + bankLocation_( bank.location( ) ) , + samplerId_( sampler.stringValue( ) ) , + samplerIdLocation_( sampler.location( ) ) + { } + + uint32_t bank( ) const noexcept + { return bank_; } + T_SRDLocation const& bankLocation( ) const noexcept + { return bankLocation_; } + + T_String const& samplerId( ) const noexcept + { return samplerId_; } + T_SRDLocation const& samplerIdLocation( ) const noexcept + { return samplerIdLocation_; } +}; + +// Viewport instruction +class T_ViewportInstrNode : public A_InstructionNode +{ + public: + enum E_Parameter { + PX , PY , PWIDTH , PHEIGHT + }; + + private: + P_ExpressionNode parameters_[ 4 ]; + + public: + T_ViewportInstrNode( T_InstrListNode& parent ) noexcept + : A_InstructionNode( OP_VIEWPORT , parent , + E_InstrRestriction::INIT ) + { } + + void setParameter( const E_Parameter p , P_ExpressionNode height ) noexcept + { parameters_[ int( p ) ] = std::move( height ); } + bool hasParameter( const E_Parameter p ) const noexcept + { return bool( parameters_[ int( p ) ] ); } + A_ExpressionNode& parameter( const E_Parameter p ) const noexcept + { return *parameters_[ int( p ) ]; } +}; + /*============================================================================*/ // A constant value @@ -608,6 +733,27 @@ class T_IdentifierExprNode : public A_ExpressionNode { return id_; } }; +// Access to an input value +class T_InputExprNode : public A_ExpressionNode +{ + private: + T_String id_; + T_SRDLocation idLocation_; + + public: + T_InputExprNode( A_Node& parent , + T_SRDToken const& token ) noexcept + : A_ExpressionNode( EXPR_INPUT , parent ) , + id_( token.stringValue( ) ) , + idLocation_( token.location( ) ) + { } + + T_String const& id( ) const noexcept + { return id_; } + T_SRDLocation const& idLocation( ) const noexcept + { return idLocation_; } +}; + // A unary operator class T_UnaryOperatorNode : public A_ExpressionNode {