//================ Copyright (c) Valve Corporation. All Rights Reserved. =========================== // // // //================================================================================================== //-------------------------------------------------------------------------------------------------- // Inlcudes //-------------------------------------------------------------------------------------------------- #include #include "SpuMgr_spu.h" #include "gcmdraw_spu.h" #include "gcmdrawstate.h" #include "gcmstate.h" //-------------------------------------------------------------------------------------------------- // Globals //-------------------------------------------------------------------------------------------------- ALIGN16 VertexShader9Data_t gVertexShaderData ALIGN16_POST; ALIGN16 PixelShader9Data_t gPixelShaderData ALIGN16_POST; ALIGN16 CellGcmContextData gGcmContext ALIGN16_POST ALIGN16_POST; ALIGN16 CPs3gcmGlobalState g_ps3gcmGlobalState ALIGN16_POST ; ALIGN16 CPs3gcmTextureLayout::Format_t g_ps3texFormats[PS3_TEX_MAX_FORMAT_COUNT] ALIGN16_POST; ALIGN16 IDirect3DVertexDeclaration9 gDecl ALIGN16_POST; ALIGN16 CellGcmContextData* gpGcmContext = &gGcmContext ALIGN16_POST; ALIGN16 uint8 gFp[0x2000] ALIGN16_POST; ALIGN16 uint8 gVp[0x2000] ALIGN16_POST; ALIGN16 CPs3gcmTextureLayout gaLayout[D3D_MAX_TEXTURES] ALIGN16_POST; ALIGN16 uint8 gaECB[3][0x1000]; ALIGN16 CPs3gcmLocalMemoryBlock gLmBlock ALIGN16_POST; int gEA; //-------------------------------------------------------------------------------------------------- // Routine to DMA in texture Layouts //-------------------------------------------------------------------------------------------------- void GetTextureLayouts() { // Loop and DMA in texture layouts for (uint32 lp = 0; lp < ARRAYSIZE(gaLayout); lp++) { uintp ea = gpGcmDrawState->m_textures[lp].m_eaLayout; gEA = ea; if (ea) gSpuMgr.DmaGetSAFE( &gaLayout[lp], ea, sizeof(CPs3gcmTextureLayout), SPU_DMAGET_TAG ); } gSpuMgr.DmaDone( SPU_DMAGET_TAG_WAIT ); } //-------------------------------------------------------------------------------------------------- // main() //-------------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------------- // Protocol // // Simplest possible for starters : // PPU sends SPU Mbx the last part of the drawcall to perform. // SPU performs it and DMAs down the data. When it's complete it send the PPUMbx the length of the drawcall // PPU prepares next packet which waits on PPUMbx completion before sending another. // // Relies on PPU calling cellGcmReserveMethodSize with 16k, so that the SPU can go ahead and DMA back the // draw.. //-------------------------------------------------------------------------------------------------- int main(void) { gSpuMgr.Init(); // Initialise SPUs drawstate class uint32 eaGcmDrawState; gpGcmDrawState->Init(); uint8* pData = gpGcmDrawState->m_pData; // Initialise context gGcmContext.begin = (uint32*)MemAlloc_AllocAligned(GCM_DS_FIFOPERDRAW * GCM_NUMDRAWCALLS_SPU, 128); gGcmContext.end = gGcmContext.begin + (GCM_DS_FIFOPERDRAW * GCM_NUMDRAWCALLS_SPU)/4; gGcmContext.callback = NULL; // Pull in globalstate volatile uint32 eagGlobalState; gSpuMgr.ReadMailbox( (uint32_t *) &eagGlobalState ); gSpuMgr.DmaGetUNSAFE( &g_ps3gcmGlobalState, eagGlobalState, SPUMGR_ALIGN_UP( sizeof(g_ps3gcmGlobalState), 16 ), SPU_DMAGET_TAG ); gSpuMgr.DmaDone( SPU_DMAGET_TAG_WAIT ); while(1) { uint32 startidx, count, loop; gSpuMgr.ReadMailbox( (uint32_t *) &startidx ); count = startidx >>16; startidx &= 0xFFFF; gpGcmContext->current = gpGcmContext->begin; // Loop over the drawstates for (loop = 0; loop < count; loop++) { uint32 idx = (startidx +loop) % GCM_DRAWSTATE_MAX; eaGcmDrawState = g_ps3gcmGlobalState.m_eaDrawStates + (idx*sizeof(CGcmDrawState)); // Read drawstate gSpuMgr.DmaGetUNSAFE( gpGcmDrawState, eaGcmDrawState, SPUMGR_ALIGN_UP( DRAWSTATE_SIZEOFDMA, 16 ), SPU_DMAGET_TAG ); gSpuMgr.DmaDone( SPU_DMAGET_TAG_WAIT ); // Read Fixed Data gSpuMgr.DmaGetUNSAFE( &gFixedData[0], uintp(gpGcmDrawState->m_pFixed), SPUMGR_ALIGN_UP(sizeof(gFixedData[0]), 16), SPU_DMAGET_TAG ); gSpuMgr.DmaDone( SPU_DMAGET_TAG_WAIT ); gpGcmDrawState->m_pFixed = &gFixedData[0]; // Read Packed Data uint32* pParam = gpGcmDrawState->m_param; if (gpGcmDrawState->m_cmd & 0x80000000) snPause(); gpGcmDrawState->m_cmd &= 0x7fffffff; uint32 packSize = gpGcmDrawState->m_pDataCursor - gpGcmDrawState->m_pData; gSpuMgr.DmaGetUNSAFE( pData, uintp(gpGcmDrawState->m_pData), SPUMGR_ALIGN_UP( packSize, 16 ), SPU_DMAGET_TAG ); gpGcmDrawState->m_pData = pData; gpGcmDrawState->m_pDataCursor = pData + packSize; // DMA in any ECBs we will need... for ( uint32 lp = 0; lp < 3; lp++ ) { if (gpGcmDrawState->m_aECB[lp]) { gSpuMgr.DmaGetSAFE( gaECB[lp], uintp(gpGcmDrawState->m_aECB[lp]), gpGcmDrawState->m_aSizeECB[lp], SPU_DMAGET_TAG ); gpGcmDrawState->m_aECB[lp] = gaECB[lp]; } } gSpuMgr.DmaDone( SPU_DMAGET_TAG_WAIT ); // Read Pixel Shader and Vertex Shader if ( (gpGcmDrawState->m_cmd != CmdCommitStates) && (gpGcmDrawState->m_cmd != CmdEndFrame )) { if(gpGcmDrawState->m_pVertexShaderData) { gSpuMgr.DmaGetUNSAFE( &gVertexShaderData, uintp(gpGcmDrawState->m_pVertexShaderData), SPUMGR_ALIGN_UP( sizeof(gVertexShaderData), 16 ), SPU_DMAGET_TAG ); gpGcmDrawState->m_pVertexShaderData = &gVertexShaderData; gSpuMgr.DmaDone( SPU_DMAGET_TAG_WAIT ); // FPHeader, UCode, patches etc... uintp ea = uintp(gVertexShaderData.m_pVertexShaderCmdBuffer); gSpuMgr.DmaGetUNSAFE( &gVp, ea, SPUMGR_ALIGN_UP((gVertexShaderData.m_nVertexShaderCmdBufferWords*4),16), SPU_DMAGET_TAG ); gVertexShaderData.m_pVertexShaderCmdBuffer = (uint32*)gVp; } if(gpGcmDrawState->m_pPixelShaderData) { // PS Data gSpuMgr.DmaGetUNSAFE( &gPixelShaderData, uintp(gpGcmDrawState->m_pPixelShaderData), SPUMGR_ALIGN_UP( sizeof(gPixelShaderData), 16 ), SPU_DMAGET_TAG ); gpGcmDrawState->m_pPixelShaderData = &gPixelShaderData; gSpuMgr.DmaDone( SPU_DMAGET_TAG_WAIT ); // FPHeader, UCode, patches etc... uintp ea = uintp(gPixelShaderData.m_eaFp); gSpuMgr.DmaGetUNSAFE( &gFp, ea, SPUMGR_ALIGN_UP(gPixelShaderData.m_nTotalSize,16), SPU_DMAGET_TAG ); gPixelShaderData.m_eaFp = (FpHeader_t*)gFp; } // Decl gSpuMgr.DmaGetUNSAFE( &gDecl, uintp(pParam[0]), SPUMGR_ALIGN_UP( sizeof(gDecl), 16 ), SPU_DMAGET_TAG ); // Texture Fomrats gSpuMgr.DmaGetUNSAFE( &g_ps3texFormats, uintp(pParam[4]), SPUMGR_ALIGN_UP( sizeof(g_ps3texFormats), 16 ), SPU_DMAGET_TAG ); gSpuMgr.DmaDone( SPU_DMAGET_TAG_WAIT ); } // Process command switch(gpGcmDrawState->m_cmd) { case CmdCommitStates: case CmdEndFrame: gpGcmDrawState->CommitStates(); break; case CmdDrawPrim: gpGcmDrawState->CommitAll(&gDecl, pParam[1]); // Draw GCM_FUNC( cellGcmSetDrawIndexArray, pParam[2], pParam[5], CELL_GCM_DRAW_INDEX_ARRAY_TYPE_16, CELL_GCM_LOCATION_LOCAL, pParam[3] ); break; case CmdDrawPrimUP: { D3DStreamDesc &dsd = g_dxGcmVertexStreamSources[0]; dsd.m_offset = 0; dsd.m_stride = pParam[2]; dsd.m_vtxBuffer = ( IDirect3DVertexBuffer9 * )( uintp )1; // invalid pointer, but non-NULL to signal it's a real vertex buffer; dsd.m_nLocalBufferOffset = 0; gpGcmDrawState->CommitAll(&gDecl, 0); GCM_FUNC(cellGcmSetCallCommand, pParam[1]); } break; } } // End Loop over drawstates // DMA out packet // first fill context to a 16B boundary while (uintp(gpGcmContext->current) & 0xf) { *gpGcmContext->current = 0; gpGcmContext->current++; } // Send to fifo uint32 bytesUsed = (uint8*)gpGcmContext->current - (uint8*)gpGcmContext->begin; gSpuMgr.DmaSync(); gSpuMgr.DmaPut(gpGcmDrawState->m_eaOutputFIFO, (void*)gpGcmContext->begin, bytesUsed, SPU_DMAPUT_TAG); gSpuMgr.DmaDone(SPU_DMAPUT_TAG_WAIT); // Send to SPU mailbox gSpuMgr.WriteMailbox(gpGcmDrawState->m_eaOutputFIFO + bytesUsed); } }