Esempio n. 1
0
        public int UpdateList(int listId, uint stallAddress)
        {
            //if( listId == -1 )
            //{
            //    // TODO: figure out if this is valid
            //    Log.WriteLine( Verbosity.Critical, Feature.Video, "UpdateList called with listId = -1, using last list - probably wrong" );
            //    listId = _displayListIndex;
            //    //return unchecked( ( int )0x80000100 );
            //}
            if (listId < 0)
            {
                return(0);
            }

            DisplayList list = _displayLists[listId];

            //Debug.Assert( list.State == DisplayListState.Stalled );
            if (list.State != DisplayListState.Stalled)
            {
                return(-1);
            }

            list.StallAddress = stallAddress;
            list.State        = (stallAddress == 0) ? DisplayListState.Ready : DisplayListState.Stalled;

            // Process only if no stall address given - if given, then wait until it's all there
            if (list.State == DisplayListState.Ready)
            {
                this.ProcessList(list);
            }

            return(0);
        }
Esempio n. 2
0
        public int EnqueueList(uint listAddress, uint stallAddress, int callbackId, uint contextAddress, bool insertAtHead)
        {
            _hasFinished = false;

            _displayListIndex++;
            if (_displayListIndex >= DisplayListCount)
            {
                _displayListIndex = 0;
            }
            DisplayList list = _displayLists[_displayListIndex];

            Debug.Assert(list.State == DisplayListState.Done);
            list.State = DisplayListState.Stalled;

            list.Pointer        = ( uint * )this.MemorySystem.Translate(listAddress);
            list.StartAddress   = listAddress;
            list.StallAddress   = stallAddress;
            list.Base           = 0x08000000;
            list.StackIndex     = 0;
            list.CallbackID     = callbackId;
            list.ContextAddress = contextAddress;

            list.State = (stallAddress == 0) ? DisplayListState.Ready : DisplayListState.Stalled;

            // Process only if no stall address given - if given, then wait until it's all there
            if (list.State == DisplayListState.Ready)
            {
                this.ProcessList(list);
            }

            return(list.ID);
        }
Esempio n. 3
0
 private void SetupLists()
 {
     for (int n = 0; n < _displayLists.Length; n++)
     {
         _displayLists[n]       = new DisplayList();
         _displayLists[n].ID    = n;
         _displayLists[n].State = DisplayListState.Done;
     }
 }
Esempio n. 4
0
        public int SyncDraw(int syncType)
        {
            bool anyReady   = false;
            bool anyStalled = false;
            bool anyDrawing = false;

            for (int n = 0; n < _displayLists.Length; n++)
            {
                DisplayList list = _displayLists[n];
                switch (list.State)
                {
                case DisplayListState.Stalled:
                    anyStalled = true;
                    break;

                case DisplayListState.Ready:
                    anyReady = true;
                    break;

                case DisplayListState.Drawing:
                    anyDrawing = true;
                    break;
                }
            }

            // Force processing? We do it all inline, so we should never be drawing, only stalled
            bool block = (syncType == 0);

            if ((block == true) && (anyReady || anyStalled || anyDrawing))
            {
                // Wait until done drawing...
                this.ProcessAllLists();
                // TODO: kernel sleep thread?
            }

            // If paused, return that
            if (_isPaused == true)
            {
                return(4);
            }
            else if (anyStalled == true)
            {
                return(3);
            }
            else if (anyDrawing == true)
            {
                return(2);
            }
            else if (anyReady == true)
            {
                return(1);
            }
            else
            {
                return(0);
            }
        }
Esempio n. 5
0
 private void ProcessAllLists()
 {
     for (int n = 0; n < _displayLists.Length; n++)
     {
         DisplayList list = _displayLists[n];
         switch (list.State)
         {
         case DisplayListState.Ready:
         case DisplayListState.Stalled:
             this.ProcessList(list);
             break;
         }
     }
 }
Esempio n. 6
0
        private void ProcessList( DisplayList list )
        {
            if( _vsyncWaiting == true )
                this.NextFrame();

            // Lists are processed until they stall or CMD_END
            // CMD_FINISH means that the drawing is done and the frame can change (I think)
            // NOTE: I don't support signals yet - a CMD_SIGNAL is always followed by a CMD_END - it's ignored!
            // NOTE: CMD_SIGNAL can be used to simulate a jump, call, or ret - I DO support these

            //MGLStatistics.Print();

            uint* stallAddress = ( list.StallAddress > 0 ) ? ( uint* )this.MemorySystem.Translate( list.StallAddress ) : null;

            if( this.DrawWireframe == true )
                Gl.glPolygonMode( Gl.GL_FRONT_AND_BACK, Gl.GL_LINE );
            else
                Gl.glPolygonMode( Gl.GL_FRONT_AND_BACK, Gl.GL_FILL );

            bool listDone = false;
            bool didRealDrawing = false;
            uint commandCount = 0;
            while( listDone == false )
            {
                // Check for stall
                if( list.Pointer == stallAddress )
                {
                    MGLStatistics.StallCount++;
                    list.State = DisplayListState.Stalled;
                    listDone = true;
                    break;
                }

                uint p = *list.Pointer;
                VideoCommand cmd = ( VideoCommand )( ( byte )( p >> 24 ) );
                uint argi = p & 0x00FFFFFF;
                uint argx = argi << 8;
                float argf = *( ( float* )( ( uint* )( &argx ) ) );

                uint x, y;
                int i;
                uint* pp;
                float[] vector4 = new float[ 4 ];

                // Next packet
                list.Pointer++;
                commandCount++;

                MGLStatistics.CommandCounts[ ( int )cmd ]++;
                _ctx.Values[ ( int )cmd ] = argi;

                switch( cmd )
                {
                    // -- General -------------------------------------------------------
                    case VideoCommand.BASE:
                        list.Base = argx;
                        continue;
                    case VideoCommand.ORIGINADDR:
                        continue;
                    case VideoCommand.OFFSETADDR:
                        continue;

                    // -- Termination ---------------------------------------------------
                    case VideoCommand.FINISH:
                        if( didRealDrawing == true )
                        {
                            //Debug.WriteLine( "finished list" );
                            //this.NextFrame();
                            //Gl.glFlush();
                        }
                        list.State = DisplayListState.Done;
                        if( list.CallbackID > 0 )
                        {
                            if( _callbacks.FinishFunction != 0 )
                            {
                                Log.WriteLine( Verbosity.Verbose, Feature.Video, "calling GE finish callback at 0x{0:X8} with arg 0x{1:X8}", _callbacks.FinishFunction, _callbacks.FinishArgument );
                                this.Emu.Cpu.MarshalCall( -1, _callbacks.FinishFunction, new uint[] { ( uint )list.ID, _callbacks.FinishArgument }, null, 0 );
                            }
                        }
                        continue;
                    case VideoCommand.END:
                        listDone = true;
                        continue;
                    case VideoCommand.Unknown0x11:
                        // ?
                        continue;

                    // -- Flow control --------------------------------------------------
                    case VideoCommand.JUMP:
                        list.Pointer = ( uint* )this.MemorySystem.Translate( ( argi | list.Base ) & 0xFFFFFFFC );
                        continue;
                    case VideoCommand.CALL:
                        list.Stack[ list.StackIndex++ ] = list.Pointer;
                        list.Pointer = ( uint* )this.MemorySystem.Translate( ( argi | list.Base ) & 0xFFFFFFFC );
                        continue;
                    case VideoCommand.RET:
                        list.Pointer = list.Stack[ --list.StackIndex ];
                        continue;

                    // -- Signals -------------------------------------------------------
                    case VideoCommand.SIGNAL:
                        {
                            // Signal is ALWAYS followed by END - if not, we are dead
                            MGLStatistics.SignalCount++;
                            uint next = *list.Pointer;
                            list.Pointer++;
                            x = argi & 0x0000FFFF;
                            y = next & 0x0000FFFF;
                            switch( argi >> 16 )
                            {
                                case 0x01:
                                case 0x02:
                                case 0x03:
                                    Log.WriteLine( Verbosity.Critical, Feature.Video, "would have issued a signal" );
                                    break;
                                case 0x10: // JUMP
                                    y |= x << 16;
                                    list.Pointer = ( uint* )this.MemorySystem.Translate( y & 0xFFFFFFFC );
                                    break;
                                case 0x11: // CALL
                                    y |= x << 16;
                                    list.Stack[ list.StackIndex++ ] = list.Pointer;
                                    list.Pointer = ( uint* )this.MemorySystem.Translate( y & 0xFFFFFFFC );
                                    break;
                                case 0x12: // RET
                                    list.Pointer = list.Stack[ --list.StackIndex ];
                                    break;
                            }
                        }
                        continue;

                    // -- General State -------------------------------------------------
                    case VideoCommand.CLEAR:
                        if( ( argi & 0x1 ) == 0x1 )
                        {
                            //x = 0;
                            //if( ( argi & 0x100 ) != 0 )
                            //{
                            //    x |= Gl.GL_COLOR_BUFFER_BIT; // target
                            //}
                            //if( ( argi & 0x200 ) != 0 )
                            //    x |= Gl.GL_ACCUM_BUFFER_BIT | Gl.GL_STENCIL_BUFFER_BIT; // stencil/alpha
                            //if( ( argi & 0x400 ) != 0 )
                            //    x |= Gl.GL_DEPTH_BUFFER_BIT; // zbuffer

                            //Gl.glDepthMask( ( data >> 10 ) & 1 ); // Update Z?
                            Gl.glDepthMask( 0 );
                            int colMask = ( int )( ( argi >> 8 ) & 1 );
                            int alphaMask = ( int )( ( argi >> 9 ) & 1 );
                            Gl.glColorMask( colMask, colMask, colMask, alphaMask );
                            Gl.glDisable( Gl.GL_BLEND );
                            //if( ( argi & 0x100 ) != 0 )
                            //Gl.glClear( Gl.GL_COLOR_BUFFER_BIT );
                        }
                        else
                        {
                            Gl.glDepthMask( 1 );
                            Gl.glColorMask( 1, 1, 1, 1 );
                            Gl.glEnable( Gl.GL_BLEND );
                        }
                        continue;
                    case VideoCommand.SHADE:
                    case VideoCommand.BCE:
                        this.SetState( FeatureState.CullFaceMask, ( argi == 1 ) ? FeatureState.CullFaceMask : 0 );
                        continue;
                    case VideoCommand.FFACE:
                        Gl.glFrontFace( ( argi == 1 ) ? Gl.GL_CW : Gl.GL_CCW );
                        continue;
                    case VideoCommand.AAE:
                        // TODO: antialiasing
                        continue;
                    case VideoCommand.FBP:
                    case VideoCommand.FBW:
                        continue;

                    // -- Alpha Testing -------------------------------------------------
                    case VideoCommand.ATE:
                        if( this.DrawWireframe == true )
                            this.SetState( FeatureState.AlphaTestMask, 0 );
                        else
                            this.SetState( FeatureState.AlphaTestMask, ( argi == 1 ) ? FeatureState.AlphaTestMask : 0 );
                        continue;
                    case VideoCommand.ATST:
                        argf = ( ( argi >> 8 ) & 0xFF ) / 255.0f;
                        if( argf > 0.0f )
                            Gl.glAlphaFunc( AlphaTestMap[ argi & 0xFF ], argf );
                        // maybe disable if invalid?
                        // @param mask - Specifies the mask that both values are ANDed with before comparison.
                        x = ( argi >> 16 ) & 0xFF;
                        Debug.Assert( ( x == 0x0 ) || ( x == 0xFF ) );
                        continue;

                    // -- Depth Testing -------------------------------------------------
                    case VideoCommand.ZTE:
                        this.SetState( FeatureState.DepthTestMask, ( argi == 1 ) ? FeatureState.DepthTestMask : 0 );
                        continue;
                    case VideoCommand.ZTST:
                        Gl.glDepthFunc( DepthFuncMap[ argi ] );
                        continue;
                    case VideoCommand.NEARZ:
                        _ctx.NearZ = ( float )( int )( ( short )( ushort )argi );
                        continue;
                    case VideoCommand.FARZ:
                        if( _ctx.NearZ > argi )
                        {
                            _ctx.FarZ = _ctx.NearZ;
                            _ctx.NearZ = ( float )( int )( ( short )( ushort )argi );
                        }
                        else
                            _ctx.FarZ = ( float )( int )( ( short )( ushort )argi );
                        Gl.glDepthRange( _ctx.NearZ, _ctx.FarZ );
                        continue;

                    // -- Alpha Blending ------------------------------------------------
                    case VideoCommand.ABE:
                        this.SetState( FeatureState.AlphaBlendMask, ( argi == 1 ) ? FeatureState.AlphaBlendMask : 0 );
                        continue;
                    case VideoCommand.ALPHA:
                        Gl.glBlendEquation( AlphaBlendEquMap[ ( argi >> 8 ) & 0x3 ] );
                        Gl.glBlendFunc( AlphaBlendSrcMap[ argi & 0xF ], AlphaBlendDestMap[ ( argi >> 4 ) & 0xF ] );
                        continue;
                    case VideoCommand.SFIX:
                    case VideoCommand.DFIX:
                        continue;

                    // -- Viewport/Scissor ----------------------------------------------
                    case VideoCommand.SCISSOR1:
                    case VideoCommand.SCISSOR2:
                        continue;

                    // -- Fog -----------------------------------------------------------
                    case VideoCommand.FGE:
                        this.SetState( FeatureState.FogMask, ( argi == 1 ) ? FeatureState.FogMask : 0 );
                        continue;
                    case VideoCommand.FCOL:
                        vector4[ 0 ] = ( int )( argi & 0xFF ) / 255.0f;
                        vector4[ 1 ] = ( int )( ( argi >> 8 ) & 0xFF ) / 255.0f;
                        vector4[ 2 ] = ( int )( ( argi >> 16 ) & 0xFF ) / 255.0f;
                        vector4[ 3 ] = 1.0f;
                        Gl.glFogfv( Gl.GL_FOG_COLOR, vector4 );
                        continue;
                    case VideoCommand.FFAR:
                        _ctx.FogEnd = argf;
                        continue;
                    case VideoCommand.FDIST:
                        _ctx.FogDepth = argf;
                        // We get f precalculated, so need to derive start
                        {
                            if( ( _ctx.FogEnd != 0.0 ) &&
                                ( _ctx.FogDepth != 0.0 ) )
                            {
                                float end = _ctx.FogEnd;
                                float start = end - ( 1 / argf );
                                Gl.glFogf( Gl.GL_FOG_START, start );
                                Gl.glFogf( Gl.GL_FOG_END, end );
                            }
                        }
                        continue;

                    // -- Lighting ------------------------------------------------------
                    case VideoCommand.LTE:
                    case VideoCommand.LTE0:
                    case VideoCommand.LTE1:
                    case VideoCommand.LTE2:
                    case VideoCommand.LTE3:
                        continue;

                    case VideoCommand.ALA:
                    case VideoCommand.ALC:
                        continue;

                    // -- Materials -----------------------------------------------------
                    // AMA
                    // TODO: ensure AMC always follows AMA
                    case VideoCommand.AMC: // Ambient (alpha from AMA)
                        _ctx.AmbientModelColor[ 0 ] = ( int )( argi & 0xFF ) / 255.0f;
                        _ctx.AmbientModelColor[ 1 ] = ( int )( ( argi >> 8 ) & 0xFF ) / 255.0f;
                        _ctx.AmbientModelColor[ 2 ] = ( int )( ( argi >> 16 ) & 0xFF ) / 255.0f;
                        _ctx.AmbientModelColor[ 3 ] = ( int )( _ctx.Values[ ( int )VideoCommand.AMA ] & 0xFF ) / 255.0f;
                        Gl.glMaterialfv( Gl.GL_FRONT_AND_BACK, Gl.GL_AMBIENT, _ctx.AmbientModelColor );
                        continue;
                    case VideoCommand.DMC: // Diffuse
                        vector4[ 0 ] = ( int )( argi & 0xFF ) / 255.0f;
                        vector4[ 1 ] = ( int )( ( argi >> 8 ) & 0xFF ) / 255.0f;
                        vector4[ 2 ] = ( int )( ( argi >> 16 ) & 0xFF ) / 255.0f;
                        vector4[ 3 ] = 1.0f;
                        Gl.glMaterialfv( Gl.GL_FRONT_AND_BACK, Gl.GL_DIFFUSE, vector4 );
                        continue;
                    case VideoCommand.SMC: // Specular
                        vector4[ 0 ] = ( int )( argi & 0xFF ) / 255.0f;
                        vector4[ 1 ] = ( int )( ( argi >> 8 ) & 0xFF ) / 255.0f;
                        vector4[ 2 ] = ( int )( ( argi >> 16 ) & 0xFF ) / 255.0f;
                        vector4[ 3 ] = 1.0f;
                        Gl.glMaterialfv( Gl.GL_FRONT_AND_BACK, Gl.GL_SPECULAR, vector4 );
                        continue;
                    case VideoCommand.EMC: // Emissive
                        vector4[ 0 ] = ( int )( argi & 0xFF ) / 255.0f;
                        vector4[ 1 ] = ( int )( ( argi >> 8 ) & 0xFF ) / 255.0f;
                        vector4[ 2 ] = ( int )( ( argi >> 16 ) & 0xFF ) / 255.0f;
                        vector4[ 3 ] = 1.0f;
                        Gl.glMaterialfv( Gl.GL_FRONT_AND_BACK, Gl.GL_EMISSION, vector4 );
                        continue;

                    // -- Primitive Drawing ---------------------------------------------
                    // VTYPE, VADDR, IADDR
                    case VideoCommand.PRIM:
                        // Ignore clear mode
                        //if( ( _ctx.Values[ ( int )VideoCommand.CLEAR ] & 0x1 ) > 0 )
                        //	continue;
                        //Gl.glFlush();
                        didRealDrawing = true;
                        this.DrawPrimitive( list.Base, argi );
                        continue;

                    // -- Patches/Splines -----------------------------------------------
                    // PSUB, PFACE
                    case VideoCommand.BEZIER:
                        didRealDrawing = true;
                        this.DrawBezier( list.Base, argi );
                        continue;
                    case VideoCommand.SPLINE:
                        didRealDrawing = true;
                        this.DrawSpline( list.Base, argi );
                        continue;

                    // -- Textures ------------------------------------------------------
                    // TPSM
                    case VideoCommand.TME:
                        this.SetState( FeatureState.TexturesMask, ( argi == 1 ) ? FeatureState.TexturesMask : 0 );
                        continue;
                    case VideoCommand.TFLUSH:
                    case VideoCommand.TSYNC:
                        // Something?
                        continue;
                    case VideoCommand.TMODE:
                        _ctx.TexturesSwizzled = ( ( argi & 0x1 ) == 1 ) ? true : false;
                        _ctx.MipMapLevel = ( int )( ( argi >> 16 ) & 0x4 );
                        continue;
                    case VideoCommand.TFLT:
                        // TODO: Mipmapping - the & 0x1 limits everything to normal, non-mipmapped textures
                        i = TextureFilterMap[ ( int )( ( argi & 0x7 ) & 0x1 ) ];
                        _ctx.TextureMinFilter = i;
                        Gl.glTexParameteri( Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MIN_FILTER, i );
                        Gl.glTexParameteri( Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MAG_FILTER, TextureFilterMap[ ( int )( ( ( argi >> 8 ) & 0x7 ) & 0x1 ) ] );
                        continue;
                    case VideoCommand.TWRAP:
                        x = argi & 0x1;
                        y = ( argi >> 8 ) & 0x1;
                        this.SetState( FeatureState.ClampToEdgeMask, ( ( x | y ) > 0 ) ? FeatureState.ClampToEdgeMask : 0 );
                        Gl.glTexParameteri( Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_S, TextureWrapMap[ ( int )x ] );
                        Gl.glTexParameteri( Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_T, TextureWrapMap[ ( int )y ] );
                        continue;
                    case VideoCommand.TFUNC:
                        Gl.glTexEnvi( Gl.GL_TEXTURE_ENV, Gl.GL_TEXTURE_ENV_MODE, TextureFunctionMap[ ( int )( argi & 0x7 ) ] );
                        continue;
                    case VideoCommand.TEC:
                        vector4[ 0 ] = ( int )( ( argi >> 16 ) & 0xFF ) / 255.0f;
                        vector4[ 1 ] = ( int )( ( argi >> 8 ) & 0xFF ) / 255.0f;
                        vector4[ 2 ] = ( int )( argi & 0xFF ) / 255.0f;
                        vector4[ 3 ] = 1.0f;
                        Gl.glTexEnvfv( Gl.GL_TEXTURE_ENV, Gl.GL_TEXTURE_ENV_COLOR, vector4 );
                        continue;
                    case VideoCommand.USCALE:
                        _ctx.TextureScaleS = argf;
                        continue;
                    case VideoCommand.VSCALE:
                        _ctx.TextureScaleT = argf;
                        continue;
                    case VideoCommand.UOFFSET:
                        _ctx.TextureOffsetS = argf;
                        continue;
                    case VideoCommand.VOFFSET:
                        _ctx.TextureOffsetT = argf;
                        continue;
                    case VideoCommand.TBP0:
                    case VideoCommand.TBP1:
                    case VideoCommand.TBP2:
                    case VideoCommand.TBP3:
                    case VideoCommand.TBP4:
                    case VideoCommand.TBP5:
                    case VideoCommand.TBP6:
                    case VideoCommand.TBP7:
                        i = ( int )cmd - ( int )VideoCommand.TBP0;
                        _ctx.Textures[ i ].Address = ( _ctx.Textures[ i ].Address & 0xFF000000 ) | argi;
                        continue;
                    case VideoCommand.TBW0:
                    case VideoCommand.TBW1:
                    case VideoCommand.TBW2:
                    case VideoCommand.TBW3:
                    case VideoCommand.TBW4:
                    case VideoCommand.TBW5:
                    case VideoCommand.TBW6:
                    case VideoCommand.TBW7:
                        i = ( int )cmd - ( int )VideoCommand.TBW0;
                        _ctx.Textures[ i ].Address = ( ( argi << 8 ) & 0xFF000000 ) | ( _ctx.Textures[ i ].Address & 0x00FFFFFF );
                        _ctx.Textures[ i ].LineWidth = argi & 0x0000FFFF;
                        continue;
                    case VideoCommand.TSIZE0:
                    case VideoCommand.TSIZE1:
                    case VideoCommand.TSIZE2:
                    case VideoCommand.TSIZE3:
                    case VideoCommand.TSIZE4:
                    case VideoCommand.TSIZE5:
                    case VideoCommand.TSIZE6:
                    case VideoCommand.TSIZE7:
                        i = ( int )cmd - ( int )VideoCommand.TSIZE0;
                        _ctx.Textures[ i ].Width = ( uint )( 1 << ( int )( argi & 0x000000FF ) );
                        _ctx.Textures[ i ].Height = ( uint )( 1 << ( int )( ( argi >> 8 ) & 0x000000FF ) );
                        _ctx.Textures[ i ].PixelStorage = ( TexturePixelStorage )( _ctx.Values[ ( int )VideoCommand.TPSM ] & 0xF );
                        continue;

                    // -- CLUT ----------------------------------------------------------
                    // CBP, CBPH, CMODE
                    case VideoCommand.CLOAD:
                        x = ( ( _ctx.Values[ ( int )VideoCommand.CBPH ] << 8 ) & 0xFF000000 ) | _ctx.Values[ ( int )VideoCommand.CBP ];
                        y = _ctx.Values[ ( int )VideoCommand.CMODE ];
                        _ctx.Clut.Load( x, y, argi );
                        continue;

                    // -- Texture Transfer ----------------------------------------------
                    // TRXSBP, TRXSBW, TRXDBP, TRXDBW, TRXSIZE, TRXSPOS, TRXDPOS
                    case VideoCommand.TRXKICK:
                        didRealDrawing = true;
                        this.TransferTexture( argi );
                        continue;

                    // -- Matrices ------------------------------------------------------
                    // PROJ, VIEW, WORLD, TMATRIX
                    case VideoCommand.PMS:
                        pp = list.Pointer;
                        for( int n = 0; n < 16; n++ )
                        {
                            argx = ( *pp & 0x00FFFFFF ) << 8;
                            _ctx.ProjectionMatrix[ n ] = *( ( float* )( ( uint* )( &argx ) ) );
                            pp++;
                        }
                        list.Pointer += 16;
                        this.InvalidateMatrices();
                        continue;
                    case VideoCommand.VMS:
                        MGLUtilities.ReadMatrix3x4( list.Pointer, _ctx.ViewMatrix );
                        list.Pointer += 12;
                        this.InvalidateMatrices();
                        continue;
                    case VideoCommand.WMS:
                        MGLUtilities.ReadMatrix3x4( list.Pointer, _ctx.WorldMatrix );
                        list.Pointer += 12;
                        this.InvalidateMatrices();
                        continue;
                    case VideoCommand.TMS:
                        MGLUtilities.ReadMatrix3x4( list.Pointer, _ctx.TextureMatrix );
                        list.Pointer += 12;
                        this.InvalidateMatrices();
                        continue;
                }
            }

            MGLStatistics.DisplayListsProcessed++;
            MGLStatistics.CommandsProcessed += commandCount;
        }
Esempio n. 7
0
 private void SetupLists()
 {
     for( int n = 0; n < _displayLists.Length; n++ )
     {
         _displayLists[ n ] = new DisplayList();
         _displayLists[ n ].ID = n;
         _displayLists[ n ].State = DisplayListState.Done;
     }
 }
Esempio n. 8
0
        private void ProcessList(DisplayList list)
        {
            if (_vsyncWaiting == true)
            {
                this.NextFrame();
            }

            // Lists are processed until they stall or CMD_END
            // CMD_FINISH means that the drawing is done and the frame can change (I think)
            // NOTE: I don't support signals yet - a CMD_SIGNAL is always followed by a CMD_END - it's ignored!
            // NOTE: CMD_SIGNAL can be used to simulate a jump, call, or ret - I DO support these

            //MGLStatistics.Print();

            uint*stallAddress = (list.StallAddress > 0) ? ( uint * )this.MemorySystem.Translate(list.StallAddress) : null;

            if (this.DrawWireframe == true)
            {
                Gl.glPolygonMode(Gl.GL_FRONT_AND_BACK, Gl.GL_LINE);
            }
            else
            {
                Gl.glPolygonMode(Gl.GL_FRONT_AND_BACK, Gl.GL_FILL);
            }

            bool listDone       = false;
            bool didRealDrawing = false;
            uint commandCount   = 0;

            while (listDone == false)
            {
                // Check for stall
                if (list.Pointer == stallAddress)
                {
                    MGLStatistics.StallCount++;
                    list.State = DisplayListState.Stalled;
                    listDone   = true;
                    break;
                }

                uint         p    = *list.Pointer;
                VideoCommand cmd  = ( VideoCommand )(( byte )(p >> 24));
                uint         argi = p & 0x00FFFFFF;
                uint         argx = argi << 8;
                float        argf = *(( float * )(( uint * )(&argx)));

                uint    x, y;
                int     i;
                uint*   pp;
                float[] vector4 = new float[4];

                // Next packet
                list.Pointer++;
                commandCount++;

                MGLStatistics.CommandCounts[( int )cmd]++;
                _ctx.Values[( int )cmd] = argi;

                switch (cmd)
                {
                // -- General -------------------------------------------------------
                case VideoCommand.BASE:
                    list.Base = argx;
                    continue;

                case VideoCommand.ORIGINADDR:
                    continue;

                case VideoCommand.OFFSETADDR:
                    continue;

                // -- Termination ---------------------------------------------------
                case VideoCommand.FINISH:
                    if (didRealDrawing == true)
                    {
                        //Debug.WriteLine( "finished list" );
                        //this.NextFrame();
                        //Gl.glFlush();
                    }
                    list.State = DisplayListState.Done;
                    if (list.CallbackID > 0)
                    {
                        if (_callbacks.FinishFunction != 0)
                        {
                            Log.WriteLine(Verbosity.Verbose, Feature.Video, "calling GE finish callback at 0x{0:X8} with arg 0x{1:X8}", _callbacks.FinishFunction, _callbacks.FinishArgument);
                            this.Emu.Cpu.MarshalCall(-1, _callbacks.FinishFunction, new uint[] { ( uint )list.ID, _callbacks.FinishArgument }, null, 0);
                        }
                    }
                    continue;

                case VideoCommand.END:
                    listDone = true;
                    continue;

                case VideoCommand.Unknown0x11:
                    // ?
                    continue;

                // -- Flow control --------------------------------------------------
                case VideoCommand.JUMP:
                    list.Pointer = ( uint * )this.MemorySystem.Translate((argi | list.Base) & 0xFFFFFFFC);
                    continue;

                case VideoCommand.CALL:
                    list.Stack[list.StackIndex++] = list.Pointer;
                    list.Pointer = ( uint * )this.MemorySystem.Translate((argi | list.Base) & 0xFFFFFFFC);
                    continue;

                case VideoCommand.RET:
                    list.Pointer = list.Stack[--list.StackIndex];
                    continue;

                // -- Signals -------------------------------------------------------
                case VideoCommand.SIGNAL:
                {
                    // Signal is ALWAYS followed by END - if not, we are dead
                    MGLStatistics.SignalCount++;
                    uint next = *list.Pointer;
                    list.Pointer++;
                    x = argi & 0x0000FFFF;
                    y = next & 0x0000FFFF;
                    switch (argi >> 16)
                    {
                    case 0x01:
                    case 0x02:
                    case 0x03:
                        Log.WriteLine(Verbosity.Critical,Feature.Video,"would have issued a signal");
                        break;

                    case 0x10:                                             // JUMP
                        y           |= x << 16;
                        list.Pointer = ( uint* )this.MemorySystem.Translate(y & 0xFFFFFFFC);
                        break;

                    case 0x11:                                             // CALL
                        y |= x << 16;
                        list.Stack[list.StackIndex++] = list.Pointer;
                        list.Pointer = ( uint* )this.MemorySystem.Translate(y & 0xFFFFFFFC);
                        break;

                    case 0x12:                                             // RET
                        list.Pointer = list.Stack[--list.StackIndex];
                        break;
                    }
                }
                    continue;

                // -- General State -------------------------------------------------
                case VideoCommand.CLEAR:
                    if ((argi & 0x1) == 0x1)
                    {
                        //x = 0;
                        //if( ( argi & 0x100 ) != 0 )
                        //{
                        //    x |= Gl.GL_COLOR_BUFFER_BIT; // target
                        //}
                        //if( ( argi & 0x200 ) != 0 )
                        //    x |= Gl.GL_ACCUM_BUFFER_BIT | Gl.GL_STENCIL_BUFFER_BIT; // stencil/alpha
                        //if( ( argi & 0x400 ) != 0 )
                        //    x |= Gl.GL_DEPTH_BUFFER_BIT; // zbuffer

                        //Gl.glDepthMask( ( data >> 10 ) & 1 ); // Update Z?
                        Gl.glDepthMask(0);
                        int colMask   = ( int )((argi >> 8) & 1);
                        int alphaMask = ( int )((argi >> 9) & 1);
                        Gl.glColorMask(colMask,colMask,colMask,alphaMask);
                        Gl.glDisable(Gl.GL_BLEND);
                        //if( ( argi & 0x100 ) != 0 )
                        //Gl.glClear( Gl.GL_COLOR_BUFFER_BIT );
                    }
                    else
                    {
                        Gl.glDepthMask(1);
                        Gl.glColorMask(1,1,1,1);
                        Gl.glEnable(Gl.GL_BLEND);
                    }
                    continue;

                case VideoCommand.SHADE:
                case VideoCommand.BCE:
                    this.SetState(FeatureState.CullFaceMask,(argi == 1) ? FeatureState.CullFaceMask : 0);
                    continue;

                case VideoCommand.FFACE:
                    Gl.glFrontFace((argi == 1) ? Gl.GL_CW : Gl.GL_CCW);
                    continue;

                case VideoCommand.AAE:
                    // TODO: antialiasing
                    continue;

                case VideoCommand.FBP:
                case VideoCommand.FBW:
                    continue;

                // -- Alpha Testing -------------------------------------------------
                case VideoCommand.ATE:
                    if (this.DrawWireframe == true)
                    {
                        this.SetState(FeatureState.AlphaTestMask,0);
                    }
                    else
                    {
                        this.SetState(FeatureState.AlphaTestMask,(argi == 1) ? FeatureState.AlphaTestMask : 0);
                    }
                    continue;

                case VideoCommand.ATST:
                    argf = ((argi >> 8) & 0xFF) / 255.0f;
                    if (argf > 0.0f)
                    {
                        Gl.glAlphaFunc(AlphaTestMap[argi & 0xFF],argf);
                    }
                    // maybe disable if invalid?
                    // @param mask - Specifies the mask that both values are ANDed with before comparison.
                    x = (argi >> 16) & 0xFF;
                    Debug.Assert((x == 0x0) || (x == 0xFF));
                    continue;

                // -- Depth Testing -------------------------------------------------
                case VideoCommand.ZTE:
                    this.SetState(FeatureState.DepthTestMask,(argi == 1) ? FeatureState.DepthTestMask : 0);
                    continue;

                case VideoCommand.ZTST:
                    Gl.glDepthFunc(DepthFuncMap[argi]);
                    continue;

                case VideoCommand.NEARZ:
                    _ctx.NearZ = ( float )( int )(( short )( ushort )argi);
                    continue;

                case VideoCommand.FARZ:
                    if (_ctx.NearZ > argi)
                    {
                        _ctx.FarZ  = _ctx.NearZ;
                        _ctx.NearZ = ( float )( int )(( short )( ushort )argi);
                    }
                    else
                    {
                        _ctx.FarZ = ( float )( int )(( short )( ushort )argi);
                    }
                    Gl.glDepthRange(_ctx.NearZ,_ctx.FarZ);
                    continue;

                // -- Alpha Blending ------------------------------------------------
                case VideoCommand.ABE:
                    this.SetState(FeatureState.AlphaBlendMask,(argi == 1) ? FeatureState.AlphaBlendMask : 0);
                    continue;

                case VideoCommand.ALPHA:
                    Gl.glBlendEquation(AlphaBlendEquMap[(argi >> 8) & 0x3]);
                    Gl.glBlendFunc(AlphaBlendSrcMap[argi & 0xF],AlphaBlendDestMap[(argi >> 4) & 0xF]);
                    continue;

                case VideoCommand.SFIX:
                case VideoCommand.DFIX:
                    continue;

                // -- Viewport/Scissor ----------------------------------------------
                case VideoCommand.SCISSOR1:
                case VideoCommand.SCISSOR2:
                    continue;

                // -- Fog -----------------------------------------------------------
                case VideoCommand.FGE:
                    this.SetState(FeatureState.FogMask,(argi == 1) ? FeatureState.FogMask : 0);
                    continue;

                case VideoCommand.FCOL:
                    vector4[0] = ( int )(argi & 0xFF) / 255.0f;
                    vector4[1] = ( int )((argi >> 8) & 0xFF) / 255.0f;
                    vector4[2] = ( int )((argi >> 16) & 0xFF) / 255.0f;
                    vector4[3] = 1.0f;
                    Gl.glFogfv(Gl.GL_FOG_COLOR,vector4);
                    continue;

                case VideoCommand.FFAR:
                    _ctx.FogEnd = argf;
                    continue;

                case VideoCommand.FDIST:
                    _ctx.FogDepth = argf;
                    // We get f precalculated, so need to derive start
                    {
                        if ((_ctx.FogEnd != 0.0) &&
                            (_ctx.FogDepth != 0.0))
                        {
                            float end   = _ctx.FogEnd;
                            float start = end - (1 / argf);
                            Gl.glFogf(Gl.GL_FOG_START,start);
                            Gl.glFogf(Gl.GL_FOG_END,end);
                        }
                    }
                    continue;

                // -- Lighting ------------------------------------------------------
                case VideoCommand.LTE:
                case VideoCommand.LTE0:
                case VideoCommand.LTE1:
                case VideoCommand.LTE2:
                case VideoCommand.LTE3:
                    continue;

                case VideoCommand.ALA:
                case VideoCommand.ALC:
                    continue;

                // -- Materials -----------------------------------------------------
                // AMA
                // TODO: ensure AMC always follows AMA
                case VideoCommand.AMC:                         // Ambient (alpha from AMA)
                    _ctx.AmbientModelColor[0] = ( int )(argi & 0xFF) / 255.0f;
                    _ctx.AmbientModelColor[1] = ( int )((argi >> 8) & 0xFF) / 255.0f;
                    _ctx.AmbientModelColor[2] = ( int )((argi >> 16) & 0xFF) / 255.0f;
                    _ctx.AmbientModelColor[3] = ( int )(_ctx.Values[( int )VideoCommand.AMA] & 0xFF) / 255.0f;
                    Gl.glMaterialfv(Gl.GL_FRONT_AND_BACK,Gl.GL_AMBIENT,_ctx.AmbientModelColor);
                    continue;

                case VideoCommand.DMC:                         // Diffuse
                    vector4[0] = ( int )(argi & 0xFF) / 255.0f;
                    vector4[1] = ( int )((argi >> 8) & 0xFF) / 255.0f;
                    vector4[2] = ( int )((argi >> 16) & 0xFF) / 255.0f;
                    vector4[3] = 1.0f;
                    Gl.glMaterialfv(Gl.GL_FRONT_AND_BACK,Gl.GL_DIFFUSE,vector4);
                    continue;

                case VideoCommand.SMC:                         // Specular
                    vector4[0] = ( int )(argi & 0xFF) / 255.0f;
                    vector4[1] = ( int )((argi >> 8) & 0xFF) / 255.0f;
                    vector4[2] = ( int )((argi >> 16) & 0xFF) / 255.0f;
                    vector4[3] = 1.0f;
                    Gl.glMaterialfv(Gl.GL_FRONT_AND_BACK,Gl.GL_SPECULAR,vector4);
                    continue;

                case VideoCommand.EMC:                         // Emissive
                    vector4[0] = ( int )(argi & 0xFF) / 255.0f;
                    vector4[1] = ( int )((argi >> 8) & 0xFF) / 255.0f;
                    vector4[2] = ( int )((argi >> 16) & 0xFF) / 255.0f;
                    vector4[3] = 1.0f;
                    Gl.glMaterialfv(Gl.GL_FRONT_AND_BACK,Gl.GL_EMISSION,vector4);
                    continue;

                // -- Primitive Drawing ---------------------------------------------
                // VTYPE, VADDR, IADDR
                case VideoCommand.PRIM:
                    // Ignore clear mode
                    //if( ( _ctx.Values[ ( int )VideoCommand.CLEAR ] & 0x1 ) > 0 )
                    //	continue;
                    //Gl.glFlush();
                    didRealDrawing = true;
                    this.DrawPrimitive(list.Base,argi);
                    continue;

                // -- Patches/Splines -----------------------------------------------
                // PSUB, PFACE
                case VideoCommand.BEZIER:
                    didRealDrawing = true;
                    this.DrawBezier(list.Base,argi);
                    continue;

                case VideoCommand.SPLINE:
                    didRealDrawing = true;
                    this.DrawSpline(list.Base,argi);
                    continue;

                // -- Textures ------------------------------------------------------
                // TPSM
                case VideoCommand.TME:
                    this.SetState(FeatureState.TexturesMask,(argi == 1) ? FeatureState.TexturesMask : 0);
                    continue;

                case VideoCommand.TFLUSH:
                case VideoCommand.TSYNC:
                    // Something?
                    continue;

                case VideoCommand.TMODE:
                    _ctx.TexturesSwizzled = ((argi & 0x1) == 1) ? true : false;
                    _ctx.MipMapLevel      = ( int )((argi >> 16) & 0x4);
                    continue;

                case VideoCommand.TFLT:
                    // TODO: Mipmapping - the & 0x1 limits everything to normal, non-mipmapped textures
                    i = TextureFilterMap[( int )((argi & 0x7) & 0x1)];
                    _ctx.TextureMinFilter = i;
                    Gl.glTexParameteri(Gl.GL_TEXTURE_2D,Gl.GL_TEXTURE_MIN_FILTER,i);
                    Gl.glTexParameteri(Gl.GL_TEXTURE_2D,Gl.GL_TEXTURE_MAG_FILTER,TextureFilterMap[( int )(((argi >> 8) & 0x7) & 0x1)]);
                    continue;

                case VideoCommand.TWRAP:
                    x = argi & 0x1;
                    y = (argi >> 8) & 0x1;
                    this.SetState(FeatureState.ClampToEdgeMask,((x | y) > 0) ? FeatureState.ClampToEdgeMask : 0);
                    Gl.glTexParameteri(Gl.GL_TEXTURE_2D,Gl.GL_TEXTURE_WRAP_S,TextureWrapMap[( int )x]);
                    Gl.glTexParameteri(Gl.GL_TEXTURE_2D,Gl.GL_TEXTURE_WRAP_T,TextureWrapMap[( int )y]);
                    continue;

                case VideoCommand.TFUNC:
                    Gl.glTexEnvi(Gl.GL_TEXTURE_ENV,Gl.GL_TEXTURE_ENV_MODE,TextureFunctionMap[( int )(argi & 0x7)]);
                    continue;

                case VideoCommand.TEC:
                    vector4[0] = ( int )((argi >> 16) & 0xFF) / 255.0f;
                    vector4[1] = ( int )((argi >> 8) & 0xFF) / 255.0f;
                    vector4[2] = ( int )(argi & 0xFF) / 255.0f;
                    vector4[3] = 1.0f;
                    Gl.glTexEnvfv(Gl.GL_TEXTURE_ENV,Gl.GL_TEXTURE_ENV_COLOR,vector4);
                    continue;

                case VideoCommand.USCALE:
                    _ctx.TextureScaleS = argf;
                    continue;

                case VideoCommand.VSCALE:
                    _ctx.TextureScaleT = argf;
                    continue;

                case VideoCommand.UOFFSET:
                    _ctx.TextureOffsetS = argf;
                    continue;

                case VideoCommand.VOFFSET:
                    _ctx.TextureOffsetT = argf;
                    continue;

                case VideoCommand.TBP0:
                case VideoCommand.TBP1:
                case VideoCommand.TBP2:
                case VideoCommand.TBP3:
                case VideoCommand.TBP4:
                case VideoCommand.TBP5:
                case VideoCommand.TBP6:
                case VideoCommand.TBP7:
                    i = ( int )cmd - ( int )VideoCommand.TBP0;
                    _ctx.Textures[i].Address = (_ctx.Textures[i].Address & 0xFF000000) | argi;
                    continue;

                case VideoCommand.TBW0:
                case VideoCommand.TBW1:
                case VideoCommand.TBW2:
                case VideoCommand.TBW3:
                case VideoCommand.TBW4:
                case VideoCommand.TBW5:
                case VideoCommand.TBW6:
                case VideoCommand.TBW7:
                    i = ( int )cmd - ( int )VideoCommand.TBW0;
                    _ctx.Textures[i].Address   = ((argi << 8) & 0xFF000000) | (_ctx.Textures[i].Address & 0x00FFFFFF);
                    _ctx.Textures[i].LineWidth = argi & 0x0000FFFF;
                    continue;

                case VideoCommand.TSIZE0:
                case VideoCommand.TSIZE1:
                case VideoCommand.TSIZE2:
                case VideoCommand.TSIZE3:
                case VideoCommand.TSIZE4:
                case VideoCommand.TSIZE5:
                case VideoCommand.TSIZE6:
                case VideoCommand.TSIZE7:
                    i = ( int )cmd - ( int )VideoCommand.TSIZE0;
                    _ctx.Textures[i].Width        = ( uint )(1 << ( int )(argi & 0x000000FF));
                    _ctx.Textures[i].Height       = ( uint )(1 << ( int )((argi >> 8) & 0x000000FF));
                    _ctx.Textures[i].PixelStorage = ( TexturePixelStorage )(_ctx.Values[( int )VideoCommand.TPSM] & 0xF);
                    continue;

                // -- CLUT ----------------------------------------------------------
                // CBP, CBPH, CMODE
                case VideoCommand.CLOAD:
                    x = ((_ctx.Values[( int )VideoCommand.CBPH] << 8) & 0xFF000000) | _ctx.Values[( int )VideoCommand.CBP];
                    y = _ctx.Values[( int )VideoCommand.CMODE];
                    _ctx.Clut.Load(x,y,argi);
                    continue;

                // -- Texture Transfer ----------------------------------------------
                // TRXSBP, TRXSBW, TRXDBP, TRXDBW, TRXSIZE, TRXSPOS, TRXDPOS
                case VideoCommand.TRXKICK:
                    didRealDrawing = true;
                    this.TransferTexture(argi);
                    continue;

                // -- Matrices ------------------------------------------------------
                // PROJ, VIEW, WORLD, TMATRIX
                case VideoCommand.PMS:
                    pp = list.Pointer;
                    for (int n = 0; n < 16; n++)
                    {
                        argx = (*pp & 0x00FFFFFF) << 8;
                        _ctx.ProjectionMatrix[n] = *(( float* )(( uint* )(&argx)));
                        pp++;
                    }
                    list.Pointer += 16;
                    this.InvalidateMatrices();
                    continue;

                case VideoCommand.VMS:
                    MGLUtilities.ReadMatrix3x4(list.Pointer,_ctx.ViewMatrix);
                    list.Pointer += 12;
                    this.InvalidateMatrices();
                    continue;

                case VideoCommand.WMS:
                    MGLUtilities.ReadMatrix3x4(list.Pointer,_ctx.WorldMatrix);
                    list.Pointer += 12;
                    this.InvalidateMatrices();
                    continue;

                case VideoCommand.TMS:
                    MGLUtilities.ReadMatrix3x4(list.Pointer,_ctx.TextureMatrix);
                    list.Pointer += 12;
                    this.InvalidateMatrices();
                    continue;
                }
            }

            MGLStatistics.DisplayListsProcessed++;
            MGLStatistics.CommandsProcessed += commandCount;
        }
Esempio n. 9
0
        public int SyncList(int listId, int syncType)
        {
            if (listId == -1)
            {
                // TODO: figure out if this is valid
                Log.WriteLine(Verbosity.Critical, Feature.Video, "SyncList called with listId = -1, using last list - probably wrong");
                listId = _displayListIndex;
                //return unchecked( ( int )0x80000100 );
            }

            bool ready   = false;
            bool stalled = false;
            bool drawing = false;

            DisplayList list = _displayLists[listId];

            switch (list.State)
            {
            case DisplayListState.Done:
                return(0);

            case DisplayListState.Stalled:
                stalled = true;
                break;

            case DisplayListState.Ready:
                ready = true;
                break;

            case DisplayListState.Drawing:
                drawing = true;
                break;
            }

            // Force processing? We do it all inline, so we should never be drawing, only stalled
            bool block = (syncType == 0);

            if ((block == true) && (ready || stalled || drawing))
            {
                // Wait until done drawing...
                this.ProcessAllLists();
                // TODO: kernel sleep thread?
            }

            if (_isPaused == true)
            {
                return(4);
            }
            else if (stalled == true)
            {
                return(3);
            }
            else if (drawing == true)
            {
                return(2);
            }
            else if (ready == true)
            {
                return(1);
            }
            else
            {
                return(0);
            }
        }