UI - More refactoring
The idea is to split off all UI/display code from e.g. the parser. This could take a while.
This commit is contained in:
parent
88e5724fe9
commit
4774426962
12 changed files with 846 additions and 830 deletions
12
Makefile
12
Makefile
|
@ -21,12 +21,12 @@ COMMON = \
|
||||||
texture.cc \
|
texture.cc \
|
||||||
rendertarget.cc \
|
rendertarget.cc \
|
||||||
camera.cc \
|
camera.cc \
|
||||||
colorgrading.cc \
|
|
||||||
\
|
\
|
||||||
filewatcher.cc \
|
filewatcher.cc \
|
||||||
window.cc \
|
window.cc \
|
||||||
dialogs.cc \
|
|
||||||
ui-actions.cc \
|
ui-actions.cc \
|
||||||
|
ui-colorgrading.cc \
|
||||||
|
ui-dialogs.cc \
|
||||||
globals.cc \
|
globals.cc \
|
||||||
profiling.cc \
|
profiling.cc \
|
||||||
shaders.cc \
|
shaders.cc \
|
||||||
|
@ -47,6 +47,7 @@ COMMON = \
|
||||||
DEMO = \
|
DEMO = \
|
||||||
demo.cc \
|
demo.cc \
|
||||||
main.cc \
|
main.cc \
|
||||||
|
opemu.cc \
|
||||||
syncview.cc \
|
syncview.cc \
|
||||||
# END DEMO
|
# END DEMO
|
||||||
|
|
||||||
|
@ -88,9 +89,12 @@ parsercheck: $(LIBEBCL) $(PARSERCHECK_BUILD)
|
||||||
clean:
|
clean:
|
||||||
rm -f $(ALL_OBJS) $(FILEDUMPS) demo parsercheck $(PCH) $(OUTDIR)/font-awesome.inl
|
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
|
@+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
|
.PHONY: all clean fullclean
|
||||||
|
|
||||||
|
|
2
demo.cc
2
demo.cc
|
@ -3,7 +3,7 @@
|
||||||
#include "sync.hh"
|
#include "sync.hh"
|
||||||
#include "rendertarget.hh"
|
#include "rendertarget.hh"
|
||||||
#include "globals.hh"
|
#include "globals.hh"
|
||||||
#include "ops.hh"
|
#include "opemu.hh"
|
||||||
#include "opcomp.hh"
|
#include "opcomp.hh"
|
||||||
#include <ebcl/Files.hh>
|
#include <ebcl/Files.hh>
|
||||||
#include <ebcl/SRDText.hh>
|
#include <ebcl/SRDText.hh>
|
||||||
|
|
754
opemu.cc
Normal file
754
opemu.cc
Normal file
|
@ -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" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
79
opemu.hh
Normal file
79
opemu.hh
Normal file
|
@ -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
|
748
ops.cc
748
ops.cc
|
@ -1,9 +1,5 @@
|
||||||
#include "externals.hh"
|
#include "externals.hh"
|
||||||
#include "ops.hh"
|
#include "ops.hh"
|
||||||
#include "globals.hh"
|
|
||||||
#include "profiling.hh"
|
|
||||||
#include "rendertarget.hh"
|
|
||||||
#include "sync.hh"
|
|
||||||
|
|
||||||
using namespace ops;
|
using namespace ops;
|
||||||
using namespace ebcl;
|
using namespace ebcl;
|
||||||
|
@ -198,747 +194,3 @@ T_StringBuilder& ops::operator<<(
|
||||||
}
|
}
|
||||||
return sb;
|
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" );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
73
ops.hh
73
ops.hh
|
@ -148,77 +148,4 @@ struct T_OpProgram
|
||||||
};
|
};
|
||||||
using P_OpProgram = T_OwnPtr< 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
|
} // namespace ops
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#include "externals.hh"
|
#include "externals.hh"
|
||||||
#include "globals.hh"
|
#include "globals.hh"
|
||||||
#include "syncoverrides.hh"
|
#include "syncoverrides.hh"
|
||||||
#include "colorgrading.hh"
|
#include "ui-colorgrading.hh"
|
||||||
|
|
||||||
#include <imgui_internal.h>
|
#include <imgui_internal.h>
|
||||||
#include <ebcl/SRDParser.hh>
|
#include <ebcl/SRDParser.hh>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#include "externals.hh"
|
#include "externals.hh"
|
||||||
#include "colorgrading.hh"
|
#include "ui-colorgrading.hh"
|
||||||
|
|
||||||
#define IMGUI_DEFINE_MATH_OPERATORS
|
#define IMGUI_DEFINE_MATH_OPERATORS
|
||||||
#include <imgui_internal.h>
|
#include <imgui_internal.h>
|
|
@ -1,5 +1,5 @@
|
||||||
#include "externals.hh"
|
#include "externals.hh"
|
||||||
#include "dialogs.hh"
|
#include "ui-dialogs.hh"
|
||||||
#include <imgui_internal.h>
|
#include <imgui_internal.h>
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "dialogs.hh"
|
#include "ui-dialogs.hh"
|
||||||
#include "mousectrl.hh"
|
#include "mousectrl.hh"
|
||||||
#include "ui-actions.hh"
|
#include "ui-actions.hh"
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue