diff --git a/Makefile b/Makefile index 36d1554..8a1c3c4 100644 --- a/Makefile +++ b/Makefile @@ -21,12 +21,12 @@ COMMON = \ texture.cc \ rendertarget.cc \ camera.cc \ - colorgrading.cc \ \ filewatcher.cc \ window.cc \ - dialogs.cc \ ui-actions.cc \ + ui-colorgrading.cc \ + ui-dialogs.cc \ globals.cc \ profiling.cc \ shaders.cc \ @@ -47,6 +47,7 @@ COMMON = \ DEMO = \ demo.cc \ main.cc \ + opemu.cc \ syncview.cc \ # END DEMO @@ -88,9 +89,12 @@ parsercheck: $(LIBEBCL) $(PARSERCHECK_BUILD) clean: rm -f $(ALL_OBJS) $(FILEDUMPS) demo parsercheck $(PCH) $(OUTDIR)/font-awesome.inl -fullclean: clean +depclean: clean + rm -f $(ALL_DEPS) + +fullclean: depclean @+make -C 3rdparty/ebcl fullclean CONFIG=../../ebcl-config - rm -f $(ALL_DEPS) $(OUTDIR)/font-to-c + rm -f $(OUTDIR)/font-to-c .PHONY: all clean fullclean diff --git a/demo.cc b/demo.cc index 5af075d..0945b2f 100644 --- a/demo.cc +++ b/demo.cc @@ -3,7 +3,7 @@ #include "sync.hh" #include "rendertarget.hh" #include "globals.hh" -#include "ops.hh" +#include "opemu.hh" #include "opcomp.hh" #include #include diff --git a/opemu.cc b/opemu.cc new file mode 100644 index 0000000..8f9aeb0 --- /dev/null +++ b/opemu.cc @@ -0,0 +1,754 @@ +#include "externals.hh" +#include "opemu.hh" +#include "globals.hh" +#include "profiling.hh" +#include "rendertarget.hh" +#include "sync.hh" + +using namespace ops; +using namespace ebcl; + + +/*= EMULATOR ===================================================================*/ + +X_OpFailure::X_OpFailure( + T_Op const& op , + T_String error ) noexcept + : op_( &op ) , error_( std::move( error ) ) +{ + T_StringBuilder sb; + sb << "operation (" << op << ") failed: " + << error_ << "; source: " << op.location << '\0'; + fullMessage_ = std::move( sb ); +} + +char const* X_OpFailure::what( ) const noexcept +{ + return fullMessage_.data( ); +} + +/*------------------------------------------------------------------------------*/ + +T_OpContext::T_OpContext( + T_OpProgram& program ) noexcept + : program( program ) +{ + stack.ensureCapacity( stack.growth( ) ); + + const auto nc{ program.constants.size( ) }; + const auto ts{ 3 + nc + program.nVariables + + program.nFramebuffers + program.nPrograms + + program.nPipelines + program.nSamplers + + program.nTextures }; + values.resize( ts ); + initialInputs.resize( program.inputs.size( ) ); + + framebuffers.resize( program.nFramebuffers ); + pipelines.resize( program.nPipelines ); + samplers.resize( program.nSamplers ); + textures.resize( program.nTextures ); + + memset( &values[ 0 ] , 0 , values.size( ) * 4 ); + for ( auto i = 0u ; i < nc ; i ++ ) { + values[ i + 3 + program.nVariables ] = program.constants[ i ]; + } +} + +namespace { +struct T_RunGuard +{ + T_OpContext& context; + T_RunGuard( T_OpContext& ctx ) noexcept : context( ctx ) {} + + ~T_RunGuard( ) + { + while ( !context.profiling.empty( ) ) { + Globals::Profiler( ).end( context.profiling.last( ) ); + context.profiling.removeLast( ); + } + glUseProgram( 0 ); + glBindProgramPipeline( 0 ); + glBindFramebuffer( GL_FRAMEBUFFER , 0 ); + Globals::Textures( ).reset( ); + } +}; +} + +void T_OpContext::run( + const E_RunTarget target , + const float time , + const float width , + const float height ) +{ + assert( !aborted ); + + T_RunGuard rg( *this ); + x87sp = 0; + instrPtr = program.ops.firstOf( target == R_INIT ? program.init : program.frame ); + values[ 0 ] = time; + values[ 1 ] = width; + values[ 2 ] = height; + + stack.clear( ); + stack.add( 0xffffffff ); + installOverrides.clear( ); + + while ( !stack.empty( ) ) { + auto const& instr{ program.ops[ instrPtr ] }; + +//#define YOUR_MUM_IS_A_TRACE +#ifdef YOUR_MUM_IS_A_TRACE + GL_ASSERT( ); + T_StringBuilder sb; + sb << "\nEXECUTE " << instrPtr << ":\t(" << instr << ") {" + << instr.location << "}\nSTACK:"; + for ( auto i = 0u ; i < stack.size( ) ; i ++ ) { + sb << ' ' << stack[ i ].u; + } + sb << "\nFPU STACK:"; + for ( auto i = 0u ; i < x87sp ; i ++ ) { + sb << ' ' << x87stack[ i ]; + } + sb << "\nWREG: " << wreg.f << '/' << wreg.u << '\n' << '\0'; + printf( "%s" , sb.data( ) ); + + printf( "VALUES\n00" ); + for ( auto i = 0u ; i < values.size( ) ; i ++ ) { + printf( " %08x" , values[ i ].u ); + if ( i % 4 == 3 ) { + printf( "\n%02x" , i + 1 ); + } + } + if ( values.size( ) % 4 != 0 ) { + printf( "\n" ); + } +#endif + + switch ( instr.op ) { + + case OP_END: + throw X_OpFailure{ instr , "invalid instruction" }; + + // -------------------------------------------------------------------------------- + + case OP_CALL: + if ( program.ops.size( ) <= instr.args[ 0 ] ) { + throw X_OpFailure{ instr , "invalid function index" }; + } + stack.add( instrPtr + 1 ); + instrPtr = program.ops.firstOf( instr.args[ 0 ] ); + continue; + + case OP_RET: + ensureStack( instr , 1 + instr.args[ 0 ] ); + instrPtr = stack.last( ).u; + stack.resize( stack.size( ) - instr.args[ 0 ] - 1 ); + continue; + + case OP_SKIP: + // FIXME: make sure we don't go past the end + instrPtr += instr.args[ 0 ]; + break; + + case OP_COND_SKIP: + ensureStack( instr , 1 ); + if ( stack.last( ).u != instr.args[ 1 ] ) { + // FIXME: make sure we don't go past the end + instrPtr += instr.args[ 0 ]; + } + break; + + // -------------------------------------------------------------------------------- + + case OP_RES_STACK: + stack.resize( stack.size( ) + instr.args[ 0 ] + 1 ); + break; + + case OP_PUSH: + stack.add( wreg ); + break; + + case OP_POP: + ensureStack( instr , instr.args[ 0 ] + 1 ); + stack.resize( stack.size( ) - instr.args[ 0 ] - 1 ); + break; + + case OP_DUP: + ensureStack( instr , instr.args[ 0 ] + 1 ); + stack.add( stack[ stack.size( ) - instr.args[ 0 ] - 1 ] ); + break; + + // -------------------------------------------------------------------------------- + + case OP_LOAD: + checkAddress( instr , instr.args[ 0 ] ); + wreg = values[ instr.args[ 0 ] ]; + break; + + case OP_STORE: + checkAddress( instr , instr.args[ 0 ] ); + values[ instr.args[ 0 ] ] = wreg; + break; + + case OP_SLOAD: + ensureStack( instr , instr.args[ 0 ] + 1 ); + wreg = stack[ stack.size( ) - instr.args[ 0 ] - 1 ]; + break; + + case OP_CONST: + case OP_OFFSET: + wreg = instr.args[ 0 ]; + break; + + // -------------------------------------------------------------------------------- + + case OP_GET_INPUT: + ensureFpuStack( instr , 0 , 1 ); + x87stack[ x87sp ++ ] = Globals::Sync( ).inputs( )[ instr.args[ 0 ] ]; + break; + + case OP_FP_LOAD: + ensureFpuStack( instr , 0 , 1 ); + checkAddress( instr , instr.args[ 0 ] ); + x87stack[ x87sp ++ ] = values[ instr.args[ 0 ] ].f; + break; + + case OP_FP_STORE: + ensureFpuStack( instr , 1 , 0 ); + checkAddress( instr , instr.args[ 0 ] ); + values[ instr.args[ 0 ] ].f = x87stack[ -- x87sp ]; + break; + + case OP_FP_SLOAD: + ensureFpuStack( instr , 0 , 1 ); + ensureStack( instr , instr.args[ 0 ] + 1 ); + x87stack[ x87sp ++ ] = stack[ stack.size( ) - instr.args[ 0 ] - 1 ].f; + break; + + case OP_FP_SSTORE: + ensureFpuStack( instr , 1 , 0 ); + ensureStack( instr , instr.args[ 0 ] + 1 ); + stack[ stack.size( ) - instr.args[ 0 ] - 1 ].f = x87stack[ -- x87sp ]; + break; + + case OP_FP_SSTORE_INT: + ensureFpuStack( instr , 1 , 0 ); + ensureStack( instr , instr.args[ 0 ] + 1 ); + stack[ stack.size( ) - instr.args[ 0 ] - 1 ].i = int32_t( x87stack[ -- x87sp ] ); + break; + + // -------------------------------------------------------------------------------- + + case OP_FP_CMP: + { + ensureFpuStack( instr , 2 , 0 ); + const auto v2( x87stack[ x87sp - 1 ] ) , + v1( x87stack[ x87sp - 2 ] ); + x87sp --; + + const bool rv{ ([&]( ) -> bool { + switch ( instr.args[ 0 ] ) { + case 0: return v1 == v2; + case 1: return v1 != v2; + case 2: return v1 > v2; + case 3: return v1 >= v2; + case 4: return v1 < v2; + case 5: return v1 <= v2; + } + throw X_OpFailure( instr , "invalid operation" ); + })() }; + x87stack[ x87sp - 1 ] = rv ? 1 : 0; + break; + } + + case OP_FP_ADD: + { + ensureFpuStack( instr , 2 , 0 ); + x87stack[ x87sp - 2 ] += x87stack[ x87sp - 1 ]; + x87sp --; + break; + } + + case OP_FP_SUB: + { + ensureFpuStack( instr , 2 , 0 ); + x87stack[ x87sp - 2 ] -= x87stack[ x87sp - 1 ]; + x87sp --; + break; + } + + case OP_FP_MUL: + { + ensureFpuStack( instr , 2 , 0 ); + x87stack[ x87sp - 2 ] *= x87stack[ x87sp - 1 ]; + x87sp --; + break; + } + + case OP_FP_DIV: + { + ensureFpuStack( instr , 2 , 0 ); + if ( x87stack[ x87sp - 1 ] == 0 ) { + throw X_OpFailure{ instr , "arithmetic error" }; + } + x87stack[ x87sp - 2 ] /= x87stack[ x87sp - 1 ]; + x87sp --; + break; + } + + case OP_FP_POW: + { + ensureFpuStack( instr , 2 , 0 ); + x87stack[ x87sp - 2 ] = pow( x87stack[ x87sp - 2 ] , + x87stack[ x87sp - 1 ] ); + x87sp --; + break; + } + + // -------------------------------------------------------------------------------- + + case OP_FP_NEG: + { + ensureFpuStack( instr , 1 , 1 ); + x87stack[ x87sp - 1 ] = -x87stack[ x87sp - 1 ]; + break; + } + + case OP_FP_INV: + { + ensureFpuStack( instr , 1 , 1 ); + if ( x87stack[ x87sp - 1 ] == 0 ) { + throw X_OpFailure{ instr , "arithmetic error" }; + } + x87stack[ x87sp - 1 ] = 1.0 / x87stack[ x87sp - 1 ]; + break; + } + + case OP_FP_NOT: + { + ensureFpuStack( instr , 1 , 0 ); + x87stack[ x87sp - 1 ] = x87stack[ x87sp - 1 ] == 0 ? 1 : 0; + break; + } + + case OP_FP_SIN: + { + ensureFpuStack( instr , 1 , 0 ); + x87stack[ x87sp - 1 ] = sin( x87stack[ x87sp - 1 ] ); + break; + } + + case OP_FP_COS: + { + ensureFpuStack( instr , 1 , 0 ); + x87stack[ x87sp - 1 ] = cos( x87stack[ x87sp - 1 ] ); + break; + } + + case OP_FP_TAN: + { + ensureFpuStack( instr , 1 , 1 ); + const auto c( cos( x87stack[ x87sp - 1 ] ) ); + if ( c == 0 ) { + throw X_OpFailure{ instr , "arithmetic error" }; + } + x87stack[ x87sp - 1 ] = sin( x87stack[ x87sp - 1 ] ) / c; + break; + } + + case OP_FP_SQRT: + { + ensureFpuStack( instr , 1 , 0 ); + const auto v( x87stack[ x87sp - 1 ] ); + if ( v < 0 ) { + throw X_OpFailure{ instr , "arithmetic error" }; + } + x87stack[ x87sp - 1 ] = sqrt( v ); + break; + } + + case OP_FP_EXP: + { + ensureFpuStack( instr , 1 , 0 ); // FIXME: need FPU stack space + x87stack[ x87sp - 1 ] = exp( x87stack[ x87sp - 1 ] ); + break; + } + + case OP_FP_LN: + { + ensureFpuStack( instr , 1 , 0 ); // FIXME: need FPU stack space + x87stack[ x87sp - 1 ] = log( x87stack[ x87sp - 1 ] ); + break; + } + + // -------------------------------------------------------------------------------- + + case OP_GEN_ASSETS: + { + auto idx = 0u; + switch ( instr.args[ 0 ] ) { + case 3: idx += program.nSamplers; + // fallthrough + case 2: idx += program.nPrograms + program.nPipelines; + // fallthrough + case 1: idx += program.nFramebuffers; + // fallthrough + case 0: idx += 3 + program.nVariables + program.constants.size( ); break; + + default: + throw X_OpFailure( instr , "invalid argument" ); + } + + auto count = 0u; + switch ( instr.args[ 0 ] ) { + case 3: count = program.nTextures; break; + case 2: count = program.nSamplers; break; + case 1: count = program.nPipelines; break; + case 0: count = program.nFramebuffers; break; + } + + + for ( auto i = 0u ; i < count ; i ++ ) { + values[ idx + i ].u = i + 1; + } + break; + } + + case OP_INIT_PIPELINE: + { + ensureStack( instr , 2 + instr.args[ 0 ] ); + + const auto sv( stack.last( ).u ); + stack.removeLast( ); + if ( sv == 0 || sv > pipelines.size( ) ) { + throw X_OpFailure{ instr , "invalid pipeline" }; + } + const auto plIndex( sv - 1 ); + + T_String progNames[ 6 ]; + for ( auto i = 0u ; i <= instr.args[ 0 ] ; i ++ ) { + const auto prIndex( stack.last( ).u ); + stack.removeLast( ); + if ( !prIndex ) { + throw X_OpFailure{ instr , "pipeline uses uninitialised program" }; + } + progNames[ i ] = programs[ prIndex - 1 ]->name( ); + } + + pipelines[ plIndex ] = NewOwned< T_ShaderPipeline >( + Globals::Shaders( ).pipeline( progNames , instr.args[ 0 ] + 1 ) ); + break; + } + + case OP_INIT_PROGRAM: + { + if ( instr.args[ 0 ] >= program.progNames.size( ) ) { + throw X_OpFailure{ instr , "invalid argument" }; + } + programs.add( NewOwned< T_ShaderProgram >( + Globals::Shaders( ).program( program.progNames[ instr.args[ 0 ] ] ) ) ); + wreg = programs.size( ); + break; + } + + case OP_INIT_SAMPLER: + { + ensureStack( instr , 3 ); + const auto sv( stack.last( ).u ); + stack.removeLast( ); + if ( sv == 0 || sv > samplers.size( ) ) { + throw X_OpFailure{ instr , "invalid sampler" }; + } + + const auto samplerIndex( sv - 1 ); + if ( !samplers[ samplerIndex ] ) { + samplers[ samplerIndex ] = NewOwned< T_TextureSampler >( ); + } + + const float max( stack.last( ).f ); + stack.removeLast( ); + const float min( stack.last( ).f ); + stack.removeLast( ); + + samplers[ samplerIndex ]->sampling( E_TexSampling( ( instr.args[ 0 ] & 4 ) >> 2 ) ) + .wrap( E_TexWrap( instr.args[ 1 ] ) ) + .lod( min , max ); + if ( ( instr.args[ 0 ] & 2 ) == 0 ) { + samplers[ samplerIndex ]->noMipmap( ); + } else { + samplers[ samplerIndex ]->mipmap( E_TexSampling( instr.args[ 0 ] & 1 ) ); + } + + break; + } + + case OP_INIT_TEXTURE: + { + ensureStack( instr , 3 + ( instr.args[ 1 ] ? 1 : 0 ) ); + + const auto sv( stack.last( ).u ); + stack.removeLast( ); + if ( sv == 0 || sv > textures.size( ) ) { + throw X_OpFailure{ instr , "invalid texture" }; + } + + const auto index( sv - 1 ); + const uint32_t w( stack.last( ).f ); + stack.removeLast( ); + const uint32_t h( stack.last( ).f ); + stack.removeLast( ); + const uint32_t lods( instr.args[ 1 ] ? stack.last( ).f : 1 ); + if ( instr.args[ 1 ] ) { + stack.removeLast( ); + } + + textures[ index ] = NewOwned< T_Texture >( + w , h , E_TexType( instr.args[ 0 ] ) , lods ); + break; + } + + case OP_FB_ATTACH: + { + // instr[ 0 ] = id (0 for depth attachment, 1+ for color attachments) + // instr[ 1 ] = has LOD? + // stack: TOP < TEX ( < LOD if has LOD ) + ensureStack( instr , 1 + ( instr.args[ 1 ] ? 1 : 0 ) ); + if ( curFb < 0 ) { + throw X_OpFailure{ instr , "no framebuffer selected" }; + } + + const auto svt( stack.last( ).u ); + stack.removeLast( ); + if ( svt == 0 || svt > textures.size( ) || !textures[ svt - 1 ] ) { + throw X_OpFailure{ instr , "invalid texture" }; + } + const auto& texture( *textures[ svt - 1 ] ); + + const uint32_t lod( instr.args[ 1 ] ? uint32_t( stack.last( ).f ) : 0 ); + if ( instr.args[ 1 ] ) { + stack.removeLast( ); + } + framebuffers[ curFb ]->attach( texture , lod , instr.args[ 0 ] ); + + break; + } + + // -------------------------------------------------------------------------------- + + case OP_USE_TEXTURE: + { + ensureStack( instr , 2 ); + + const auto svt( stack.last( ).u ); + stack.removeLast( ); + if ( svt == 0 || svt > textures.size( ) || !textures[ svt - 1 ] ) { + throw X_OpFailure{ instr , "invalid texture" }; + } + + const auto svs( stack.last( ).u ); + stack.removeLast( ); + if ( svs == 0 || svs > samplers.size( ) || !samplers[ svs - 1 ] ) { + throw X_OpFailure{ instr , "invalid sampler" }; + } + + Globals::Textures( ).bind( instr.args[ 0 ] , + *textures[ svt - 1 ] , *samplers[ svs - 1 ] ); + break; + } + + case OP_USE_PIPELINE: + { + ensureStack( instr , 1 ); + + const auto sv( stack.last( ).u ); + stack.removeLast( ); + if ( sv == 0 || sv > pipelines.size( ) || !pipelines[ sv - 1 ] ) { + throw X_OpFailure{ instr , "invalid pipeline" }; + } + pipelines[ sv - 1 ]->enable( ); + break; + } + + case OP_USE_PROGRAM: + { + ensureStack( instr , 1 ); + + const auto sv( stack.last( ).u ); + stack.removeLast( ); + if ( sv == 0 || sv > programs.size( ) || !programs[ sv - 1 ] ) { + throw X_OpFailure{ instr , "invalid program" }; + } + programs[ sv - 1 ]->enable( ); + break; + } + + case OP_FB_TOGGLE: + { + if ( curFb < 0 ) { + throw X_OpFailure{ instr , "no framebuffer selected" }; + } + framebuffers[ curFb ]->toggle( instr.args[ 0 ] , instr.args[ 1 ] ); + break; + } + + case OP_UNIFORMS: + { + ensureStack( instr , 3 + instr.args[ 0 ] ); + + const auto ss( stack.size( ) ); + T_OpValue values[ 4 ]; +// printf( "OP_UNIFORMS %d %d" , instr.args[ 0 ] , instr.args[ 1 ] ); + for ( auto i = 0u ; i <= instr.args[ 0 ] ; i ++ ) { + if ( instr.args[ 1 ] ) { + values[ i ] = uint32_t( stack[ ss - 3 - i ].f ); +// printf( " %d" , values[ i ].i ); + } else { + values[ i ] = stack[ ss - 3 - i ]; +// printf( " %f" , values[ i ].f ); + } + } + + const auto sv( stack.last( ).u ); + if ( sv == 0 || sv > programs.size( ) || !programs[ sv - 1 ] ) { + throw X_OpFailure{ instr , "invalid program" }; + } +// printf( " -> %s %d\n" , programs[ sv - 1 ]->name( ).toOSString( ).data( ) , stack[ ss - 2 ].u ); + + typedef void (*F_SetUniform_)( int , int , int , void* ); + void const* const funcs[] = { + &glProgramUniform1fv , &glProgramUniform2fv , &glProgramUniform3fv , &glProgramUniform4fv , + &glProgramUniform1iv , &glProgramUniform2iv , &glProgramUniform3iv , &glProgramUniform4iv , + }; + const F_SetUniform_ func{ *(F_SetUniform_*) funcs[ + instr.args[ 0 ] + ( instr.args[ 1 ] ? 4 : 0 ) ] }; + func( programs[ sv - 1 ]->id( ) , stack[ ss - 2 ].u , 1 , values ); + stack.resize( ss - 3 - instr.args[ 0 ] ); + break; + } + + case OP_VIEWPORT: + { + ensureStack( instr , 4 ); + const auto ss( stack.size( ) ); + glViewport( int32_t( stack[ ss - 1 ].f ) , + int32_t( stack[ ss - 2 ].f ) , + int32_t( stack[ ss - 3 ].f ) , + int32_t( stack[ ss - 4 ].f ) ); + stack.resize( ss - 4 ); + break; + } + + case OP_USE_FRAMEBUFFER: + { + ensureStack( instr , 1 ); + const auto sv( stack.last( ).u ); + stack.removeLast( ); + if ( sv == 0 ) { + glBindFramebuffer( GL_FRAMEBUFFER , 0 ); + curFb = -1; + break; + } + + const auto index( sv - 1 ); + if ( !framebuffers[ index ] ) { + framebuffers[ index ] = NewOwned< T_Rendertarget >( ); + } + glBindFramebuffer( GL_FRAMEBUFFER , framebuffers[ index ]->id( ) ); + curFb = index; + break; + } + + // -------------------------------------------------------------------------------- + + case OP_FULLSCREEN: + glDrawArrays( GL_TRIANGLE_STRIP , 0 , 4 ); + break; + + case OP_CLEAR: + { + ensureStack( instr , 4 ); + const auto ss( stack.size( ) ); + glClearColor( stack[ ss - 1 ].f , stack[ ss - 2 ].f , + stack[ ss - 3 ].f , stack[ ss - 4 ].f ); + glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); + stack.resize( ss - 4 ); + break; + } + + // -------------------------------------------------------------------------------- + + case OP_UI_PENTER: + { + T_String const& section( program.uiStrings[ instr.args[ 0 ] ] ); + Globals::Profiler( ).start( section ); + profiling.add( section ); + break; + } + + case OP_UI_PEXIT: + glFinish( ); + Globals::Profiler( ).end( profiling.last( ) ); + profiling.removeLast( ); + break; + + case OP_UI_INPUT_DFT: + initialInputs[ instr.args[ 0 ] ] = values[ instr.args[ 1 ] ].f; + break; + + case OP_UI_INPUT_OVR: + if ( !installOverrides ) { + installOverrides = NewOwned< T_SyncOverrideSection >( "*" ); + } + installOverrides->merge( *( program.overrides[ instr.args[ 0 ] ] ) ); + break; + + case OP_UI_ODBG: + { + ensureStack( instr , 1 ); + const auto svt( stack.last( ).u ); + stack.removeLast( ); + if ( svt == 0 || svt > textures.size( ) || !textures[ svt - 1 ] ) { + throw X_OpFailure{ instr , "invalid texture" }; + } + Globals::ODbg( ).registerTexture( *textures[ svt - 1 ] , + E_ODbgMode( instr.args[ 0 ] ) , + program.uiStrings[ instr.args[ 1 ] ] ); + break; + } + } + + instrPtr ++; + } +} + +void T_OpContext::ensureStack( + T_Op const& op , + const uint32_t min ) +{ + if ( stack.size( ) < min ) { + throw X_OpFailure{ op , "stack underrun" }; + } +} + +void T_OpContext::ensureFpuStack( + T_Op const& op , + const uint32_t minStacked , + const uint32_t minFree ) +{ + if ( x87sp < minStacked ) { + throw X_OpFailure{ op , "FPU stack underrun" }; + } + if ( 8 - x87sp < minFree ) { + throw X_OpFailure{ op , "FPU stack overflow" }; + } +} + +void T_OpContext::checkAddress( + T_Op const& op , + const uint32_t address ) +{ + if ( address >= values.size( ) ) { + throw X_OpFailure( op , "invalid access" ); + } +} + diff --git a/opemu.hh b/opemu.hh new file mode 100644 index 0000000..037d027 --- /dev/null +++ b/opemu.hh @@ -0,0 +1,79 @@ +#pragma once +#include "ops.hh" + + +namespace ops { + +struct T_OpContext +{ + T_OpProgram& program; // The program + + uint32_t instrPtr; // Instruction pointer + bool aborted{ false }; // Did the program fail? + + T_Array< T_OpValue > values; // VM data + T_Array< T_OpValue > stack; // Main VM stack + T_Array< float > initialInputs; // Initial input values + + T_OpValue wreg; // Work register + double x87stack[ 8 ]; // x87 FPU emulation stack + uint32_t x87sp; // x87 FPU emulation stack pointer + + P_SyncOverrideSection installOverrides; // Install UI overrides + + // Allocated resources + T_Array< T_OwnPtr< T_Rendertarget > > framebuffers; + T_Array< T_OwnPtr< T_ShaderProgram > > programs; + T_Array< T_OwnPtr< T_ShaderPipeline > > pipelines; + T_Array< T_OwnPtr< T_TextureSampler > > samplers; + T_Array< T_OwnPtr< T_Texture > > textures; + + T_Array< T_String > profiling; // Profiling sections that have been started + int32_t curFb{ -1 }; // Index of current framebuffer + + enum E_RunTarget { + R_INIT , + R_RENDER + }; + + explicit T_OpContext( T_OpProgram& program ) noexcept; + void run( E_RunTarget target , + float time , + float width , + float height ); + + private: + void ensureStack( T_Op const& op , + uint32_t min ); + void ensureFpuStack( T_Op const& op , + uint32_t minStacked , + uint32_t minFree ); + void checkAddress( T_Op const& op , + uint32_t address ); +}; + +class X_OpFailure : public std::exception +{ + public: + X_OpFailure( ) = delete; + DEF_COPY( X_OpFailure ); + DEF_MOVE( X_OpFailure ); + + X_OpFailure( + T_Op const& op , + T_String error ) noexcept; + + T_Op const& op( ) const noexcept + { return *op_; } + T_String const& error( ) const noexcept + { return error_; } + + char const* what( ) const noexcept override; + + private: + T_Op const* op_; + T_String error_; + T_String fullMessage_; +}; + +} // namespace ops diff --git a/ops.cc b/ops.cc index 84bea88..52bc69e 100644 --- a/ops.cc +++ b/ops.cc @@ -1,9 +1,5 @@ #include "externals.hh" #include "ops.hh" -#include "globals.hh" -#include "profiling.hh" -#include "rendertarget.hh" -#include "sync.hh" using namespace ops; using namespace ebcl; @@ -198,747 +194,3 @@ T_StringBuilder& ops::operator<<( } return sb; } - - -/*= EMULATOR ===================================================================*/ - -X_OpFailure::X_OpFailure( - T_Op const& op , - T_String error ) noexcept - : op_( &op ) , error_( std::move( error ) ) -{ - T_StringBuilder sb; - sb << "operation (" << op << ") failed: " - << error_ << "; source: " << op.location << '\0'; - fullMessage_ = std::move( sb ); -} - -char const* X_OpFailure::what( ) const noexcept -{ - return fullMessage_.data( ); -} - -/*------------------------------------------------------------------------------*/ - -T_OpContext::T_OpContext( - T_OpProgram& program ) noexcept - : program( program ) -{ - stack.ensureCapacity( stack.growth( ) ); - - const auto nc{ program.constants.size( ) }; - const auto ts{ 3 + nc + program.nVariables - + program.nFramebuffers + program.nPrograms - + program.nPipelines + program.nSamplers - + program.nTextures }; - values.resize( ts ); - initialInputs.resize( program.inputs.size( ) ); - - framebuffers.resize( program.nFramebuffers ); - pipelines.resize( program.nPipelines ); - samplers.resize( program.nSamplers ); - textures.resize( program.nTextures ); - - memset( &values[ 0 ] , 0 , values.size( ) * 4 ); - for ( auto i = 0u ; i < nc ; i ++ ) { - values[ i + 3 + program.nVariables ] = program.constants[ i ]; - } -} - -namespace { -struct T_RunGuard -{ - T_OpContext& context; - T_RunGuard( T_OpContext& ctx ) noexcept : context( ctx ) {} - - ~T_RunGuard( ) - { - while ( !context.profiling.empty( ) ) { - Globals::Profiler( ).end( context.profiling.last( ) ); - context.profiling.removeLast( ); - } - glUseProgram( 0 ); - glBindProgramPipeline( 0 ); - glBindFramebuffer( GL_FRAMEBUFFER , 0 ); - Globals::Textures( ).reset( ); - } -}; -} - -void T_OpContext::run( - const E_RunTarget target , - const float time , - const float width , - const float height ) -{ - assert( !aborted ); - - T_RunGuard rg( *this ); - x87sp = 0; - instrPtr = program.ops.firstOf( target == R_INIT ? program.init : program.frame ); - values[ 0 ] = time; - values[ 1 ] = width; - values[ 2 ] = height; - - stack.clear( ); - stack.add( 0xffffffff ); - installOverrides.clear( ); - - while ( !stack.empty( ) ) { - auto const& instr{ program.ops[ instrPtr ] }; - -//#define YOUR_MUM_IS_A_TRACE -#ifdef YOUR_MUM_IS_A_TRACE - GL_ASSERT( ); - T_StringBuilder sb; - sb << "\nEXECUTE " << instrPtr << ":\t(" << instr << ") {" - << instr.location << "}\nSTACK:"; - for ( auto i = 0u ; i < stack.size( ) ; i ++ ) { - sb << ' ' << stack[ i ].u; - } - sb << "\nFPU STACK:"; - for ( auto i = 0u ; i < x87sp ; i ++ ) { - sb << ' ' << x87stack[ i ]; - } - sb << "\nWREG: " << wreg.f << '/' << wreg.u << '\n' << '\0'; - printf( "%s" , sb.data( ) ); - - printf( "VALUES\n00" ); - for ( auto i = 0u ; i < values.size( ) ; i ++ ) { - printf( " %08x" , values[ i ].u ); - if ( i % 4 == 3 ) { - printf( "\n%02x" , i + 1 ); - } - } - if ( values.size( ) % 4 != 0 ) { - printf( "\n" ); - } -#endif - - switch ( instr.op ) { - - case OP_END: - throw X_OpFailure{ instr , "invalid instruction" }; - - // -------------------------------------------------------------------------------- - - case OP_CALL: - if ( program.ops.size( ) <= instr.args[ 0 ] ) { - throw X_OpFailure{ instr , "invalid function index" }; - } - stack.add( instrPtr + 1 ); - instrPtr = program.ops.firstOf( instr.args[ 0 ] ); - continue; - - case OP_RET: - ensureStack( instr , 1 + instr.args[ 0 ] ); - instrPtr = stack.last( ).u; - stack.resize( stack.size( ) - instr.args[ 0 ] - 1 ); - continue; - - case OP_SKIP: - // FIXME: make sure we don't go past the end - instrPtr += instr.args[ 0 ]; - break; - - case OP_COND_SKIP: - ensureStack( instr , 1 ); - if ( stack.last( ).u != instr.args[ 1 ] ) { - // FIXME: make sure we don't go past the end - instrPtr += instr.args[ 0 ]; - } - break; - - // -------------------------------------------------------------------------------- - - case OP_RES_STACK: - stack.resize( stack.size( ) + instr.args[ 0 ] + 1 ); - break; - - case OP_PUSH: - stack.add( wreg ); - break; - - case OP_POP: - ensureStack( instr , instr.args[ 0 ] + 1 ); - stack.resize( stack.size( ) - instr.args[ 0 ] - 1 ); - break; - - case OP_DUP: - ensureStack( instr , instr.args[ 0 ] + 1 ); - stack.add( stack[ stack.size( ) - instr.args[ 0 ] - 1 ] ); - break; - - // -------------------------------------------------------------------------------- - - case OP_LOAD: - checkAddress( instr , instr.args[ 0 ] ); - wreg = values[ instr.args[ 0 ] ]; - break; - - case OP_STORE: - checkAddress( instr , instr.args[ 0 ] ); - values[ instr.args[ 0 ] ] = wreg; - break; - - case OP_SLOAD: - ensureStack( instr , instr.args[ 0 ] + 1 ); - wreg = stack[ stack.size( ) - instr.args[ 0 ] - 1 ]; - break; - - case OP_CONST: - case OP_OFFSET: - wreg = instr.args[ 0 ]; - break; - - // -------------------------------------------------------------------------------- - - case OP_GET_INPUT: - ensureFpuStack( instr , 0 , 1 ); - x87stack[ x87sp ++ ] = Globals::Sync( ).inputs( )[ instr.args[ 0 ] ]; - break; - - case OP_FP_LOAD: - ensureFpuStack( instr , 0 , 1 ); - checkAddress( instr , instr.args[ 0 ] ); - x87stack[ x87sp ++ ] = values[ instr.args[ 0 ] ].f; - break; - - case OP_FP_STORE: - ensureFpuStack( instr , 1 , 0 ); - checkAddress( instr , instr.args[ 0 ] ); - values[ instr.args[ 0 ] ].f = x87stack[ -- x87sp ]; - break; - - case OP_FP_SLOAD: - ensureFpuStack( instr , 0 , 1 ); - ensureStack( instr , instr.args[ 0 ] + 1 ); - x87stack[ x87sp ++ ] = stack[ stack.size( ) - instr.args[ 0 ] - 1 ].f; - break; - - case OP_FP_SSTORE: - ensureFpuStack( instr , 1 , 0 ); - ensureStack( instr , instr.args[ 0 ] + 1 ); - stack[ stack.size( ) - instr.args[ 0 ] - 1 ].f = x87stack[ -- x87sp ]; - break; - - case OP_FP_SSTORE_INT: - ensureFpuStack( instr , 1 , 0 ); - ensureStack( instr , instr.args[ 0 ] + 1 ); - stack[ stack.size( ) - instr.args[ 0 ] - 1 ].i = int32_t( x87stack[ -- x87sp ] ); - break; - - // -------------------------------------------------------------------------------- - - case OP_FP_CMP: - { - ensureFpuStack( instr , 2 , 0 ); - const auto v2( x87stack[ x87sp - 1 ] ) , - v1( x87stack[ x87sp - 2 ] ); - x87sp --; - - const bool rv{ ([&]( ) -> bool { - switch ( instr.args[ 0 ] ) { - case 0: return v1 == v2; - case 1: return v1 != v2; - case 2: return v1 > v2; - case 3: return v1 >= v2; - case 4: return v1 < v2; - case 5: return v1 <= v2; - } - throw X_OpFailure( instr , "invalid operation" ); - })() }; - x87stack[ x87sp - 1 ] = rv ? 1 : 0; - break; - } - - case OP_FP_ADD: - { - ensureFpuStack( instr , 2 , 0 ); - x87stack[ x87sp - 2 ] += x87stack[ x87sp - 1 ]; - x87sp --; - break; - } - - case OP_FP_SUB: - { - ensureFpuStack( instr , 2 , 0 ); - x87stack[ x87sp - 2 ] -= x87stack[ x87sp - 1 ]; - x87sp --; - break; - } - - case OP_FP_MUL: - { - ensureFpuStack( instr , 2 , 0 ); - x87stack[ x87sp - 2 ] *= x87stack[ x87sp - 1 ]; - x87sp --; - break; - } - - case OP_FP_DIV: - { - ensureFpuStack( instr , 2 , 0 ); - if ( x87stack[ x87sp - 1 ] == 0 ) { - throw X_OpFailure{ instr , "arithmetic error" }; - } - x87stack[ x87sp - 2 ] /= x87stack[ x87sp - 1 ]; - x87sp --; - break; - } - - case OP_FP_POW: - { - ensureFpuStack( instr , 2 , 0 ); - x87stack[ x87sp - 2 ] = pow( x87stack[ x87sp - 2 ] , - x87stack[ x87sp - 1 ] ); - x87sp --; - break; - } - - // -------------------------------------------------------------------------------- - - case OP_FP_NEG: - { - ensureFpuStack( instr , 1 , 1 ); - x87stack[ x87sp - 1 ] = -x87stack[ x87sp - 1 ]; - break; - } - - case OP_FP_INV: - { - ensureFpuStack( instr , 1 , 1 ); - if ( x87stack[ x87sp - 1 ] == 0 ) { - throw X_OpFailure{ instr , "arithmetic error" }; - } - x87stack[ x87sp - 1 ] = 1.0 / x87stack[ x87sp - 1 ]; - break; - } - - case OP_FP_NOT: - { - ensureFpuStack( instr , 1 , 0 ); - x87stack[ x87sp - 1 ] = x87stack[ x87sp - 1 ] == 0 ? 1 : 0; - break; - } - - case OP_FP_SIN: - { - ensureFpuStack( instr , 1 , 0 ); - x87stack[ x87sp - 1 ] = sin( x87stack[ x87sp - 1 ] ); - break; - } - - case OP_FP_COS: - { - ensureFpuStack( instr , 1 , 0 ); - x87stack[ x87sp - 1 ] = cos( x87stack[ x87sp - 1 ] ); - break; - } - - case OP_FP_TAN: - { - ensureFpuStack( instr , 1 , 1 ); - const auto c( cos( x87stack[ x87sp - 1 ] ) ); - if ( c == 0 ) { - throw X_OpFailure{ instr , "arithmetic error" }; - } - x87stack[ x87sp - 1 ] = sin( x87stack[ x87sp - 1 ] ) / c; - break; - } - - case OP_FP_SQRT: - { - ensureFpuStack( instr , 1 , 0 ); - const auto v( x87stack[ x87sp - 1 ] ); - if ( v < 0 ) { - throw X_OpFailure{ instr , "arithmetic error" }; - } - x87stack[ x87sp - 1 ] = sqrt( v ); - break; - } - - case OP_FP_EXP: - { - ensureFpuStack( instr , 1 , 0 ); // FIXME: need FPU stack space - x87stack[ x87sp - 1 ] = exp( x87stack[ x87sp - 1 ] ); - break; - } - - case OP_FP_LN: - { - ensureFpuStack( instr , 1 , 0 ); // FIXME: need FPU stack space - x87stack[ x87sp - 1 ] = log( x87stack[ x87sp - 1 ] ); - break; - } - - // -------------------------------------------------------------------------------- - - case OP_GEN_ASSETS: - { - auto idx = 0u; - switch ( instr.args[ 0 ] ) { - case 3: idx += program.nSamplers; - // fallthrough - case 2: idx += program.nPrograms + program.nPipelines; - // fallthrough - case 1: idx += program.nFramebuffers; - // fallthrough - case 0: idx += 3 + program.nVariables + program.constants.size( ); break; - - default: - throw X_OpFailure( instr , "invalid argument" ); - } - - auto count = 0u; - switch ( instr.args[ 0 ] ) { - case 3: count = program.nTextures; break; - case 2: count = program.nSamplers; break; - case 1: count = program.nPipelines; break; - case 0: count = program.nFramebuffers; break; - } - - - for ( auto i = 0u ; i < count ; i ++ ) { - values[ idx + i ].u = i + 1; - } - break; - } - - case OP_INIT_PIPELINE: - { - ensureStack( instr , 2 + instr.args[ 0 ] ); - - const auto sv( stack.last( ).u ); - stack.removeLast( ); - if ( sv == 0 || sv > pipelines.size( ) ) { - throw X_OpFailure{ instr , "invalid pipeline" }; - } - const auto plIndex( sv - 1 ); - - T_String progNames[ 6 ]; - for ( auto i = 0u ; i <= instr.args[ 0 ] ; i ++ ) { - const auto prIndex( stack.last( ).u ); - stack.removeLast( ); - if ( !prIndex ) { - throw X_OpFailure{ instr , "pipeline uses uninitialised program" }; - } - progNames[ i ] = programs[ prIndex - 1 ]->name( ); - } - - pipelines[ plIndex ] = NewOwned< T_ShaderPipeline >( - Globals::Shaders( ).pipeline( progNames , instr.args[ 0 ] + 1 ) ); - break; - } - - case OP_INIT_PROGRAM: - { - if ( instr.args[ 0 ] >= program.progNames.size( ) ) { - throw X_OpFailure{ instr , "invalid argument" }; - } - programs.add( NewOwned< T_ShaderProgram >( - Globals::Shaders( ).program( program.progNames[ instr.args[ 0 ] ] ) ) ); - wreg = programs.size( ); - break; - } - - case OP_INIT_SAMPLER: - { - ensureStack( instr , 3 ); - const auto sv( stack.last( ).u ); - stack.removeLast( ); - if ( sv == 0 || sv > samplers.size( ) ) { - throw X_OpFailure{ instr , "invalid sampler" }; - } - - const auto samplerIndex( sv - 1 ); - if ( !samplers[ samplerIndex ] ) { - samplers[ samplerIndex ] = NewOwned< T_TextureSampler >( ); - } - - const float max( stack.last( ).f ); - stack.removeLast( ); - const float min( stack.last( ).f ); - stack.removeLast( ); - - samplers[ samplerIndex ]->sampling( E_TexSampling( ( instr.args[ 0 ] & 4 ) >> 2 ) ) - .wrap( E_TexWrap( instr.args[ 1 ] ) ) - .lod( min , max ); - if ( ( instr.args[ 0 ] & 2 ) == 0 ) { - samplers[ samplerIndex ]->noMipmap( ); - } else { - samplers[ samplerIndex ]->mipmap( E_TexSampling( instr.args[ 0 ] & 1 ) ); - } - - break; - } - - case OP_INIT_TEXTURE: - { - ensureStack( instr , 3 + ( instr.args[ 1 ] ? 1 : 0 ) ); - - const auto sv( stack.last( ).u ); - stack.removeLast( ); - if ( sv == 0 || sv > textures.size( ) ) { - throw X_OpFailure{ instr , "invalid texture" }; - } - - const auto index( sv - 1 ); - const uint32_t w( stack.last( ).f ); - stack.removeLast( ); - const uint32_t h( stack.last( ).f ); - stack.removeLast( ); - const uint32_t lods( instr.args[ 1 ] ? stack.last( ).f : 1 ); - if ( instr.args[ 1 ] ) { - stack.removeLast( ); - } - - textures[ index ] = NewOwned< T_Texture >( - w , h , E_TexType( instr.args[ 0 ] ) , lods ); - break; - } - - case OP_FB_ATTACH: - { - // instr[ 0 ] = id (0 for depth attachment, 1+ for color attachments) - // instr[ 1 ] = has LOD? - // stack: TOP < TEX ( < LOD if has LOD ) - ensureStack( instr , 1 + ( instr.args[ 1 ] ? 1 : 0 ) ); - if ( curFb < 0 ) { - throw X_OpFailure{ instr , "no framebuffer selected" }; - } - - const auto svt( stack.last( ).u ); - stack.removeLast( ); - if ( svt == 0 || svt > textures.size( ) || !textures[ svt - 1 ] ) { - throw X_OpFailure{ instr , "invalid texture" }; - } - const auto& texture( *textures[ svt - 1 ] ); - - const uint32_t lod( instr.args[ 1 ] ? uint32_t( stack.last( ).f ) : 0 ); - if ( instr.args[ 1 ] ) { - stack.removeLast( ); - } - framebuffers[ curFb ]->attach( texture , lod , instr.args[ 0 ] ); - - break; - } - - // -------------------------------------------------------------------------------- - - case OP_USE_TEXTURE: - { - ensureStack( instr , 2 ); - - const auto svt( stack.last( ).u ); - stack.removeLast( ); - if ( svt == 0 || svt > textures.size( ) || !textures[ svt - 1 ] ) { - throw X_OpFailure{ instr , "invalid texture" }; - } - - const auto svs( stack.last( ).u ); - stack.removeLast( ); - if ( svs == 0 || svs > samplers.size( ) || !samplers[ svs - 1 ] ) { - throw X_OpFailure{ instr , "invalid sampler" }; - } - - Globals::Textures( ).bind( instr.args[ 0 ] , - *textures[ svt - 1 ] , *samplers[ svs - 1 ] ); - break; - } - - case OP_USE_PIPELINE: - { - ensureStack( instr , 1 ); - - const auto sv( stack.last( ).u ); - stack.removeLast( ); - if ( sv == 0 || sv > pipelines.size( ) || !pipelines[ sv - 1 ] ) { - throw X_OpFailure{ instr , "invalid pipeline" }; - } - pipelines[ sv - 1 ]->enable( ); - break; - } - - case OP_USE_PROGRAM: - { - ensureStack( instr , 1 ); - - const auto sv( stack.last( ).u ); - stack.removeLast( ); - if ( sv == 0 || sv > programs.size( ) || !programs[ sv - 1 ] ) { - throw X_OpFailure{ instr , "invalid program" }; - } - programs[ sv - 1 ]->enable( ); - break; - } - - case OP_FB_TOGGLE: - { - if ( curFb < 0 ) { - throw X_OpFailure{ instr , "no framebuffer selected" }; - } - framebuffers[ curFb ]->toggle( instr.args[ 0 ] , instr.args[ 1 ] ); - break; - } - - case OP_UNIFORMS: - { - ensureStack( instr , 3 + instr.args[ 0 ] ); - - const auto ss( stack.size( ) ); - T_OpValue values[ 4 ]; -// printf( "OP_UNIFORMS %d %d" , instr.args[ 0 ] , instr.args[ 1 ] ); - for ( auto i = 0u ; i <= instr.args[ 0 ] ; i ++ ) { - if ( instr.args[ 1 ] ) { - values[ i ] = uint32_t( stack[ ss - 3 - i ].f ); -// printf( " %d" , values[ i ].i ); - } else { - values[ i ] = stack[ ss - 3 - i ]; -// printf( " %f" , values[ i ].f ); - } - } - - const auto sv( stack.last( ).u ); - if ( sv == 0 || sv > programs.size( ) || !programs[ sv - 1 ] ) { - throw X_OpFailure{ instr , "invalid program" }; - } -// printf( " -> %s %d\n" , programs[ sv - 1 ]->name( ).toOSString( ).data( ) , stack[ ss - 2 ].u ); - - typedef void (*F_SetUniform_)( int , int , int , void* ); - void const* const funcs[] = { - &glProgramUniform1fv , &glProgramUniform2fv , &glProgramUniform3fv , &glProgramUniform4fv , - &glProgramUniform1iv , &glProgramUniform2iv , &glProgramUniform3iv , &glProgramUniform4iv , - }; - const F_SetUniform_ func{ *(F_SetUniform_*) funcs[ - instr.args[ 0 ] + ( instr.args[ 1 ] ? 4 : 0 ) ] }; - func( programs[ sv - 1 ]->id( ) , stack[ ss - 2 ].u , 1 , values ); - stack.resize( ss - 3 - instr.args[ 0 ] ); - break; - } - - case OP_VIEWPORT: - { - ensureStack( instr , 4 ); - const auto ss( stack.size( ) ); - glViewport( int32_t( stack[ ss - 1 ].f ) , - int32_t( stack[ ss - 2 ].f ) , - int32_t( stack[ ss - 3 ].f ) , - int32_t( stack[ ss - 4 ].f ) ); - stack.resize( ss - 4 ); - break; - } - - case OP_USE_FRAMEBUFFER: - { - ensureStack( instr , 1 ); - const auto sv( stack.last( ).u ); - stack.removeLast( ); - if ( sv == 0 ) { - glBindFramebuffer( GL_FRAMEBUFFER , 0 ); - curFb = -1; - break; - } - - const auto index( sv - 1 ); - if ( !framebuffers[ index ] ) { - framebuffers[ index ] = NewOwned< T_Rendertarget >( ); - } - glBindFramebuffer( GL_FRAMEBUFFER , framebuffers[ index ]->id( ) ); - curFb = index; - break; - } - - // -------------------------------------------------------------------------------- - - case OP_FULLSCREEN: - glDrawArrays( GL_TRIANGLE_STRIP , 0 , 4 ); - break; - - case OP_CLEAR: - { - ensureStack( instr , 4 ); - const auto ss( stack.size( ) ); - glClearColor( stack[ ss - 1 ].f , stack[ ss - 2 ].f , - stack[ ss - 3 ].f , stack[ ss - 4 ].f ); - glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); - stack.resize( ss - 4 ); - break; - } - - // -------------------------------------------------------------------------------- - - case OP_UI_PENTER: - { - T_String const& section( program.uiStrings[ instr.args[ 0 ] ] ); - Globals::Profiler( ).start( section ); - profiling.add( section ); - break; - } - - case OP_UI_PEXIT: - glFinish( ); - Globals::Profiler( ).end( profiling.last( ) ); - profiling.removeLast( ); - break; - - case OP_UI_INPUT_DFT: - initialInputs[ instr.args[ 0 ] ] = values[ instr.args[ 1 ] ].f; - break; - - case OP_UI_INPUT_OVR: - if ( !installOverrides ) { - installOverrides = NewOwned< T_SyncOverrideSection >( "*" ); - } - installOverrides->merge( *( program.overrides[ instr.args[ 0 ] ] ) ); - break; - - case OP_UI_ODBG: - { - ensureStack( instr , 1 ); - const auto svt( stack.last( ).u ); - stack.removeLast( ); - if ( svt == 0 || svt > textures.size( ) || !textures[ svt - 1 ] ) { - throw X_OpFailure{ instr , "invalid texture" }; - } - Globals::ODbg( ).registerTexture( *textures[ svt - 1 ] , - E_ODbgMode( instr.args[ 0 ] ) , - program.uiStrings[ instr.args[ 1 ] ] ); - break; - } - } - - instrPtr ++; - } -} - -void T_OpContext::ensureStack( - T_Op const& op , - const uint32_t min ) -{ - if ( stack.size( ) < min ) { - throw X_OpFailure{ op , "stack underrun" }; - } -} - -void T_OpContext::ensureFpuStack( - T_Op const& op , - const uint32_t minStacked , - const uint32_t minFree ) -{ - if ( x87sp < minStacked ) { - throw X_OpFailure{ op , "FPU stack underrun" }; - } - if ( 8 - x87sp < minFree ) { - throw X_OpFailure{ op , "FPU stack overflow" }; - } -} - -void T_OpContext::checkAddress( - T_Op const& op , - const uint32_t address ) -{ - if ( address >= values.size( ) ) { - throw X_OpFailure( op , "invalid access" ); - } -} diff --git a/ops.hh b/ops.hh index 1ce4b3d..2da222f 100644 --- a/ops.hh +++ b/ops.hh @@ -148,77 +148,4 @@ struct T_OpProgram }; using P_OpProgram = T_OwnPtr< T_OpProgram >; - -struct T_OpContext -{ - T_OpProgram& program; // The program - - uint32_t instrPtr; // Instruction pointer - bool aborted{ false }; // Did the program fail? - - T_Array< T_OpValue > values; // VM data - T_Array< T_OpValue > stack; // Main VM stack - T_Array< float > initialInputs; // Initial input values - - T_OpValue wreg; // Work register - double x87stack[ 8 ]; // x87 FPU emulation stack - uint32_t x87sp; // x87 FPU emulation stack pointer - - P_SyncOverrideSection installOverrides; // Install UI overrides - - // Allocated resources - T_Array< T_OwnPtr< T_Rendertarget > > framebuffers; - T_Array< T_OwnPtr< T_ShaderProgram > > programs; - T_Array< T_OwnPtr< T_ShaderPipeline > > pipelines; - T_Array< T_OwnPtr< T_TextureSampler > > samplers; - T_Array< T_OwnPtr< T_Texture > > textures; - - T_Array< T_String > profiling; // Profiling sections that have been started - int32_t curFb{ -1 }; // Index of current framebuffer - - enum E_RunTarget { - R_INIT , - R_RENDER - }; - - explicit T_OpContext( T_OpProgram& program ) noexcept; - void run( E_RunTarget target , - float time , - float width , - float height ); - - private: - void ensureStack( T_Op const& op , - uint32_t min ); - void ensureFpuStack( T_Op const& op , - uint32_t minStacked , - uint32_t minFree ); - void checkAddress( T_Op const& op , - uint32_t address ); -}; - -class X_OpFailure : public std::exception -{ - public: - X_OpFailure( ) = delete; - DEF_COPY( X_OpFailure ); - DEF_MOVE( X_OpFailure ); - - X_OpFailure( - T_Op const& op , - T_String error ) noexcept; - - T_Op const& op( ) const noexcept - { return *op_; } - T_String const& error( ) const noexcept - { return error_; } - - char const* what( ) const noexcept override; - - private: - T_Op const* op_; - T_String error_; - T_String fullMessage_; -}; - } // namespace ops diff --git a/syncoverrides.cc b/syncoverrides.cc index 0ed92be..14b8a9b 100644 --- a/syncoverrides.cc +++ b/syncoverrides.cc @@ -1,7 +1,7 @@ #include "externals.hh" #include "globals.hh" #include "syncoverrides.hh" -#include "colorgrading.hh" +#include "ui-colorgrading.hh" #include #include diff --git a/colorgrading.cc b/ui-colorgrading.cc similarity index 99% rename from colorgrading.cc rename to ui-colorgrading.cc index b023bda..5f12257 100644 --- a/colorgrading.cc +++ b/ui-colorgrading.cc @@ -1,5 +1,5 @@ #include "externals.hh" -#include "colorgrading.hh" +#include "ui-colorgrading.hh" #define IMGUI_DEFINE_MATH_OPERATORS #include diff --git a/colorgrading.hh b/ui-colorgrading.hh similarity index 100% rename from colorgrading.hh rename to ui-colorgrading.hh diff --git a/dialogs.cc b/ui-dialogs.cc similarity index 99% rename from dialogs.cc rename to ui-dialogs.cc index d6a0459..c1ec979 100644 --- a/dialogs.cc +++ b/ui-dialogs.cc @@ -1,5 +1,5 @@ #include "externals.hh" -#include "dialogs.hh" +#include "ui-dialogs.hh" #include diff --git a/dialogs.hh b/ui-dialogs.hh similarity index 100% rename from dialogs.hh rename to ui-dialogs.hh diff --git a/window.hh b/window.hh index 4e284e6..b4bd029 100644 --- a/window.hh +++ b/window.hh @@ -1,5 +1,5 @@ #pragma once -#include "dialogs.hh" +#include "ui-dialogs.hh" #include "mousectrl.hh" #include "ui-actions.hh"