Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

848 lines
26 KiB

  1. //================ Copyright (c) Valve Corporation. All Rights Reserved. ===========================
  2. //
  3. // Gcm renderer state and util functions
  4. //
  5. //==================================================================================================
  6. #ifndef SPU
  7. #define CELL_GCM_MEMCPY memcpy // PPU SNC has no such intrinsic
  8. #endif
  9. #include "sys/memory.h"
  10. #include "sysutil/sysutil_sysparam.h"
  11. #include "cell/sysmodule.h"
  12. #include "tier0/platform.h"
  13. #include "tier0/dbg.h"
  14. #include "tier1/utlbuffer.h"
  15. #include "cell/gcm.h"
  16. #include "gcmconfig.h"
  17. #include "ps3gcmmemory.h"
  18. #include "gcmstate.h"
  19. #include "gcmlabels.h"
  20. #include "gcmdrawstate.h"
  21. #include "ps3/ps3_helpers.h"
  22. #include <cell/gem.h> // PS3 move controller lib
  23. #include "inputsystem/iinputsystem.h"
  24. #include "memdbgon.h"
  25. //--------------------------------------------------------------------------------------------------
  26. // Golobals, GCM context, flip control init proto
  27. //--------------------------------------------------------------------------------------------------
  28. ALIGN128 CPs3gcmGlobalState g_ps3gcmGlobalState ALIGN128_POST;
  29. ALIGN16 CellGcmContextData gGcmContext ALIGN16_POST;
  30. CellGcmContextData* gpGcmContext;
  31. CellGcmContextData gCallContext;
  32. CellGcmContextData* gpCallContext = &gCallContext;
  33. static void Gcm_InitFlipControl(void);
  34. static volatile uint32_t *s_label_call_cmd_ring_seg; // pointer to the call cmd label
  35. volatile uint32_t *g_label_fppatch_ring_seg; // Fp pacth label
  36. //--------------------------------------------------------------------------------------------------
  37. // Empty Ps
  38. //--------------------------------------------------------------------------------------------------
  39. uint8 g_dataShaderPsEmpty[] = {
  40. 0x00, 0x00, 0x1B, 0x5C, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0xB0, 0x00, 0x00, 0x00, 0x01
  41. , 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x80
  42. , 0x00, 0x00, 0x04, 0x18, 0x00, 0x00, 0x0A, 0xC5, 0x00, 0x00, 0x10, 0x05, 0xFF, 0xFF, 0xFF, 0xFF
  43. , 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50
  44. , 0x00, 0x00, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00
  45. , 0x43, 0x4F, 0x4C, 0x4F, 0x52, 0x00, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
  46. , 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF
  47. , 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
  48. , 0x1E, 0x7E, 0x7E, 0x00, 0xC8, 0x00, 0x1C, 0x9D, 0xC8, 0x00, 0x00, 0x01, 0xC8, 0x00, 0x00, 0x01
  49. , 0x1E, 0x01, 0x01, 0x00, 0x28, 0x02, 0x1C, 0x9C, 0xC8, 0x00, 0x00, 0x01, 0xC8, 0x00, 0x00, 0x01
  50. , 0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
  51. };
  52. //--------------------------------------------------------------------------------------------------
  53. // Global GCM state class
  54. //
  55. // Global state, command buffers, RSX draw display buffers etc etc
  56. //--------------------------------------------------------------------------------------------------
  57. int32 CPs3gcmGlobalState::Init()
  58. {
  59. MEM_ALLOC_CREDIT_( "GCM INIT" );
  60. Msg(">>>> Sizeof(CGcmDrawStateDma) %d \n", DRAWSTATE_SIZEOFDMA);
  61. Msg(">>>> Sizeof(CGcmDrawState) %d \n", sizeof(CGcmDrawState));
  62. // Create Raw SPU task for renderer acceleration
  63. gSpuMgr.Init(1);
  64. gSpuMgr.CreateSpuTask("rawspu_gcmdraw_spu.self", &m_spuHandle);
  65. // Default to 60Hz
  66. m_flipMode = 30;
  67. // Video : display res, video buffer, gamma, RGB colour range
  68. if( int nError= InitVideo() )
  69. return nError;
  70. // Alloc IO memory, Set address, size of main memory pool for RSX
  71. CreateIoBuffers();
  72. // Init GCM : Map IO memory, Create command buffers
  73. if( int nError = InitGcm() )
  74. return nError;
  75. // Retrieve RSX local memory config
  76. CellGcmConfig rsxConfig;
  77. cellGcmGetConfiguration( &rsxConfig );
  78. m_pLocalBaseAddress = rsxConfig.localAddress;
  79. m_nLocalSize = rsxConfig.localSize;
  80. cellGcmAddressToOffset( m_pLocalBaseAddress, &m_nLocalBaseOffset );
  81. Assert( m_nLocalBaseOffset == 0 );
  82. // Init local memory mgr
  83. Ps3gcmLocalMemoryAllocator_Init();
  84. // Create display buffers etc..
  85. CreateRsxBuffers();
  86. // Create Empty PS
  87. m_pShaderPsEmpty = reinterpret_cast< CgBinaryProgram * >( g_dataShaderPsEmpty );
  88. m_pShaderPsEmptyBuffer.Alloc( kAllocPs3GcmShader, m_pShaderPsEmpty->ucodeSize );
  89. V_memcpy( m_pShaderPsEmptyBuffer.DataInLocalMemory(), ( (char*)m_pShaderPsEmpty ) + m_pShaderPsEmpty->ucode, m_pShaderPsEmpty->ucodeSize );
  90. CgBinaryFragmentProgram *pCgFragmentProgram = ( CgBinaryFragmentProgram * )( uintp( m_pShaderPsEmpty ) + m_pShaderPsEmpty->program );
  91. m_nPsEmptyAttributeInputMask = pCgFragmentProgram->attributeInputMask;
  92. uint registerCount = pCgFragmentProgram->registerCount;
  93. // NOTE: actual register count can be modified by specifying an artificial e.g. PS3REGCOUNT48 static combo to force it to 48
  94. Assert( registerCount <= 48 );
  95. if (registerCount < 2)
  96. {
  97. // register count must be [2, 48]
  98. registerCount = 2;
  99. }
  100. uint8_t controlTxp = CELL_GCM_FALSE;
  101. uint32 shCtrl0 = ( CELL_GCM_COMMAND_CAST( controlTxp ) << CELL_GCM_SHIFT_SET_SHADER_CONTROL_CONTROL_TXP )
  102. & CELL_GCM_MASK_SET_SHADER_CONTROL_CONTROL_TXP;
  103. shCtrl0 |= ( 1<<10 ) | ( registerCount << 24 );
  104. shCtrl0 |= pCgFragmentProgram->depthReplace ? 0xE : 0x0;
  105. shCtrl0 |= pCgFragmentProgram->outputFromH0 ? 0x00 : 0x40;
  106. shCtrl0 |= pCgFragmentProgram->pixelKill ? 0x80 : 0x00;
  107. m_nPsEmptyShaderControl0 = shCtrl0;
  108. // Init glip control
  109. m_fastFlip = 0;
  110. Gcm_InitFlipControl();
  111. // Address of draw states
  112. m_eaDrawStates = uintp(gGcmDrawState);
  113. // Give SPU program this class
  114. gSpuMgr.WriteMailbox(&m_spuHandle, uintp(this));
  115. return CELL_OK;
  116. }
  117. void CPs3gcmGlobalState::CreateIoBuffers()
  118. {
  119. m_nIoSize = GCM_IOSIZE;
  120. if ((m_nIoSize & 0xFFFFF) != 0) // MB aligned
  121. {
  122. Error("No MB alignment %x\n\n", m_nIoSize);
  123. }
  124. // Try to allocate main memory that will be mapped to IO address space
  125. // Actually mapped in in GcmInit, once gcm is going
  126. sys_addr_t pIoAddress = NULL;
  127. int nError = sys_memory_allocate( m_nIoSize, SYS_MEMORY_PAGE_SIZE_1M, &pIoAddress );
  128. if ( CELL_OK != nError )
  129. {
  130. Error( "sys_memory_allocate failed to allocate %d bytes (err: %d)\n", m_nIoSize, nError );
  131. }
  132. m_pIoAddress = (void *)pIoAddress;
  133. Msg( "======== GCM IO memory allocated @0x%p size = %d MB ========\n", m_pIoAddress, m_nIoSize / 1024 / 1024 );
  134. // Call command buffer
  135. m_pCallCmdBuffer = (void*)(uintp(pIoAddress) + GCM_DEFCMDBUFFSIZE);
  136. // RSX main memory pool buffer
  137. m_nRsxMainMemoryPoolBufferSize = GCM_MAINPOOLSIZE;
  138. m_pRsxMainMemoryPoolBuffer = (void*)(uintp(pIoAddress) + GCM_DEFCMDBUFFSIZE + GCM_CALLCMDBUFFSIZE);
  139. // Patch buffers
  140. m_pPatchBuff = (uint8*)m_pRsxMainMemoryPoolBuffer + GCM_MAINPOOLSIZE;
  141. }
  142. int CPs3gcmGlobalState::InitGcm()
  143. {
  144. int32 result = cellGcmInit( GCM_DEFCMDBUFFSIZE, m_nIoSize, m_pIoAddress );
  145. if ( result < CELL_OK )
  146. return result;
  147. gGcmContext = *gCellGcmCurrentContext;
  148. gpGcmContext = &gGcmContext;
  149. gpGcmContext->callback = CmdBufferFull;
  150. // Set the flip mode etc...
  151. // Get the offset delta
  152. cellGcmAddressToOffset( m_pIoAddress, &m_nIoOffsetDelta );
  153. m_nIoOffsetDelta -= uintp( m_pIoAddress );
  154. // Setup call cmd buffer
  155. m_nCallCmdBufferoffset = uintp(m_pCallCmdBuffer) + m_nIoOffsetDelta;
  156. m_nCallWritePos = 0;
  157. m_nCallReadSegment = 0;
  158. s_label_call_cmd_ring_seg = cellGcmGetLabelAddress(GCM_LABEL_CALL_CMD_RING_SEG);
  159. *s_label_call_cmd_ring_seg = 0;
  160. // Setup Patch Buffers
  161. m_nPatchIdx = 0;
  162. m_nPatchReadSeg = 0;
  163. g_label_fppatch_ring_seg = cellGcmGetLabelAddress(GCM_LABEL_FPPATCH_RING_SEG);
  164. *g_label_fppatch_ring_seg = 0;
  165. return CELL_OK;
  166. }
  167. int CPs3gcmGlobalState::InitVideo()
  168. {
  169. //////////////////////////////////////////////////////////////////////////
  170. //
  171. // Initialize m_display
  172. //
  173. CellVideoOutState videoOutState;
  174. int result = cellVideoOutGetState( CELL_VIDEO_OUT_PRIMARY, 0, &videoOutState);
  175. if ( result < CELL_OK )
  176. return result;
  177. CellVideoOutResolution resolution;
  178. result = cellVideoOutGetResolution( videoOutState.displayMode.resolutionId, &resolution );
  179. if ( result < CELL_OK )
  180. return result;
  181. // Always output scanout in system m_display resolution
  182. m_nRenderSize[0] = resolution.width;
  183. m_nRenderSize[1] = resolution.height;
  184. // Handle special case: 1080p will be upsampled from 720p
  185. if ( resolution.height >= 720 && CommandLine()->FindParm( "-480p" ) )
  186. {
  187. m_nRenderSize[0] = 640;
  188. m_nRenderSize[1] = 480;
  189. videoOutState.displayMode.resolutionId = CELL_VIDEO_OUT_RESOLUTION_480;
  190. }
  191. else if ( resolution.height >= 1080 && !CommandLine()->FindParm( "-1080p" ) )
  192. {
  193. m_nRenderSize[0] = 1280;
  194. m_nRenderSize[1] = 720;
  195. videoOutState.displayMode.resolutionId = CELL_VIDEO_OUT_RESOLUTION_720;
  196. }
  197. //////////////////////////////////////////////////////////////////////////
  198. //
  199. // Set video output
  200. //
  201. CellVideoOutConfiguration videocfg;
  202. memset( &videocfg, 0, sizeof(videocfg) );
  203. videocfg.resolutionId = videoOutState.displayMode.resolutionId;
  204. videocfg.format = CELL_VIDEO_OUT_BUFFER_COLOR_FORMAT_X8R8G8B8;
  205. videocfg.pitch = cellGcmGetTiledPitchSize( m_nRenderSize[0] * 4 );
  206. m_nSurfaceRenderPitch = videocfg.pitch;
  207. // Configure video output
  208. result = cellVideoOutConfigure( CELL_VIDEO_OUT_PRIMARY, &videocfg, NULL, 0 );
  209. if ( result < CELL_OK )
  210. return result;
  211. // Get the new video output
  212. result = cellVideoOutGetState( CELL_VIDEO_OUT_PRIMARY, 0, &videoOutState );
  213. if ( result < CELL_OK )
  214. return result;
  215. m_flRenderAspect = ( videoOutState.displayMode.aspect == CELL_VIDEO_OUT_ASPECT_4_3 ) ? ( 4.0f/3.0f ) : ( 16.0f / 9.0f );
  216. // Set the gamma to deal with TV's having a darker gamma than computer monitors
  217. result = cellSysmoduleLoadModule( CELL_SYSMODULE_AVCONF_EXT );
  218. if ( result == CELL_OK )
  219. {
  220. cellVideoOutSetGamma( CELL_VIDEO_OUT_PRIMARY, 2.2f / 2.5f );
  221. }
  222. else
  223. {
  224. Warning( "***** ERROR calling cellSysmoduleLoadModule( CELL_SYSMODULE_AVCONF_EXT )! Gamma not set!\n" );
  225. return result;
  226. }
  227. // Output video color settings
  228. CellVideoOutDeviceInfo info;
  229. cellVideoOutGetDeviceInfo( CELL_VIDEO_OUT_PRIMARY, 0, &info );
  230. if ( info.rgbOutputRange == CELL_VIDEO_OUT_RGB_OUTPUT_RANGE_LIMITED )
  231. {
  232. DevMsg( "***** Video Out - Limited Range (16-235) - Gamma=%d *****\n", info.colorInfo.gamma );
  233. }
  234. else
  235. {
  236. DevMsg( "***** Video Out - Full Range (0-255) - Gamma=%d *****\n", info.colorInfo.gamma );
  237. }
  238. return CELL_OK;
  239. }
  240. void CPs3gcmGlobalState::CreateRsxBuffers()
  241. {
  242. //////////////////////////////////////////////////////////////////////////
  243. //
  244. // Create automatic display objects
  245. //
  246. if( m_nSurfaceRenderPitch != cellGcmGetTiledPitchSize( m_nRenderSize[0] * 4 ) )
  247. {
  248. Error("Pre-computed surface render pitch %u != %u = cellGcmGetTiledPitchSize( %u * 4 ) ", m_nSurfaceRenderPitch, cellGcmGetTiledPitchSize( m_nRenderSize[0] * 4 ), m_nRenderSize[0] );
  249. }
  250. m_display.surfaceFlipIdx = 0;
  251. // Color buffers
  252. for ( int k = 0; k < ARRAYSIZE( m_display.surfaceColor ); ++ k )
  253. {
  254. uint32 nRenderSize32bpp = GetRenderSurfaceBytes(); // 32-line vertical alignment required in local memory
  255. m_display.surfaceColor[k].Alloc( kAllocPs3gcmColorBufferFB, nRenderSize32bpp );
  256. cellGcmSetDisplayBuffer( k, m_display.surfaceColor[k].Offset(), m_nSurfaceRenderPitch, m_nRenderSize[0], m_nRenderSize[1] );
  257. }
  258. // Depth buffer
  259. {
  260. uint32 zcullSize[2] = { AlignValue( m_nRenderSize[0], 64 ), AlignValue( m_nRenderSize[1], 64 ) };
  261. uint32 nDepthPitch = cellGcmGetTiledPitchSize( zcullSize[0] * 4 );
  262. uint32 uDepthBufferSize32bpp = nDepthPitch * zcullSize[1];
  263. uDepthBufferSize32bpp = AlignValue( uDepthBufferSize32bpp, PS3GCMALLOCATIONALIGN( kAllocPs3gcmDepthBuffer ) );
  264. m_display.surfaceDepth.Alloc( kAllocPs3gcmDepthBuffer, uDepthBufferSize32bpp );
  265. uint32 uiZcullIndex = m_display.surfaceDepth.ZcullMemoryIndex();
  266. cellGcmBindZcull( uiZcullIndex,
  267. m_display.surfaceDepth.Offset(),
  268. zcullSize[0], zcullSize[1],
  269. m_display.surfaceDepth.ZcullMemoryStart(),
  270. CELL_GCM_ZCULL_Z24S8,
  271. CELL_GCM_SURFACE_CENTER_1,
  272. CELL_GCM_ZCULL_LESS,
  273. CELL_GCM_ZCULL_LONES,
  274. CELL_GCM_SCULL_SFUNC_ALWAYS,
  275. 0, 0 // sRef, sMask
  276. );
  277. uint32 uiTileIndex = m_display.surfaceDepth.TiledMemoryIndex();
  278. cellGcmSetTileInfo( uiTileIndex, CELL_GCM_LOCATION_LOCAL, m_display.surfaceDepth.Offset(),
  279. uDepthBufferSize32bpp, m_nSurfaceRenderPitch, CELL_GCM_COMPMODE_Z32_SEPSTENCIL_REGULAR,
  280. m_display.surfaceDepth.TiledMemoryTagAreaBase(), // The area base + size/0x10000 will be allocated as the tag area.
  281. 3 ); // Default depth buffer on bank 3
  282. cellGcmBindTile( uiTileIndex );
  283. }
  284. }
  285. void CPs3gcmGlobalState::Shutdown()
  286. {
  287. gpGcmDrawState->EndFrame();
  288. gpGcmDrawState->CmdBufferFinish();
  289. cellGcmSetFlipHandler(NULL);
  290. cellGcmSetVBlankHandler(NULL);
  291. cellSysmoduleUnloadModule( CELL_SYSMODULE_AVCONF_EXT );
  292. }
  293. //--------------------------------------------------------------------------------------------------
  294. // DawPrimUp code...
  295. //--------------------------------------------------------------------------------------------------
  296. uint32 CPs3gcmGlobalState::DrawPrimitiveUP(D3DPRIMITIVETYPE nPrimitiveType,UINT nPrimitiveCount,
  297. CONST void *pVertexStreamZeroData, UINT nVertexStreamZeroStride )
  298. {
  299. // First Determine size required for this call
  300. uint32 size = 0;
  301. uint32 nIndexCount = GetGcmCount( nPrimitiveType, nPrimitiveCount );
  302. uint32 nDataWords = ( nVertexStreamZeroStride * nIndexCount + 3 ) / sizeof( uint32 );
  303. size = cellGcmSetWriteTextureLabelMeasureSize(size, GCM_LABEL_CALL_CMD_RING_SEG, 0 );
  304. size = cellGcmSetInvalidateVertexCacheMeasureSize(size);
  305. size = cellGcmSetDrawInlineArrayMeasureSize(size, GetGcmMode( nPrimitiveType ), nDataWords, pVertexStreamZeroData );
  306. size = cellGcmSetReturnCommandMeasureSize(size);
  307. size *=4;
  308. // Check there is no space in the current segment
  309. uint32 endPos, nextSeg, readSeg, writeSeg;
  310. endPos = m_nCallWritePos + size;
  311. writeSeg = m_nCallWritePos/GCM_CALLCMDSEGSIZE;
  312. if ((endPos/GCM_CALLCMDSEGSIZE) != writeSeg)
  313. {
  314. // Move to the next segment
  315. uint32 nextSeg = (writeSeg + 1) % (GCM_CALLCMDBUFFSIZE / GCM_CALLCMDSEGSIZE);
  316. // Wait for RSX to not be in this segment
  317. readSeg = m_nCallReadSegment;
  318. if(nextSeg == readSeg) readSeg = *s_label_call_cmd_ring_seg;
  319. gpGcmDrawState->CmdBufferFlush();
  320. uint32 spins = 0;
  321. while(nextSeg == readSeg)
  322. {
  323. spins++;
  324. sys_timer_usleep(60);
  325. readSeg = *s_label_call_cmd_ring_seg;
  326. }
  327. //if (spins > 1) Msg("Spins %d\n", spins);
  328. // Move to next segmend abnd record new readSeg
  329. m_nCallWritePos = (nextSeg * GCM_CALLCMDSEGSIZE);
  330. writeSeg = nextSeg;
  331. m_nCallReadSegment = readSeg;
  332. // Msg("new Segment 0x%x\n", m_nCallWritePos);
  333. }
  334. uint32 ret = m_nCallWritePos + uintp(m_pCallCmdBuffer);
  335. // Write Data
  336. // Setup a context to do so
  337. CellGcmContextData context;
  338. context.begin = (uint32*)m_pCallCmdBuffer;
  339. context.current = (uint32*)((uint8*)m_pCallCmdBuffer + m_nCallWritePos);
  340. context.end = (uint32*)((uint8*)m_pCallCmdBuffer + GCM_CALLCMDBUFFSIZE);
  341. context.callback = 0;
  342. cellGcmSetWriteTextureLabelUnsafeInline(&context, GCM_LABEL_CALL_CMD_RING_SEG, writeSeg );
  343. cellGcmSetInvalidateVertexCacheUnsafeInline(&context);
  344. cellGcmSetDrawInlineArrayUnsafeInline(&context, GetGcmMode( nPrimitiveType ), nDataWords, pVertexStreamZeroData );
  345. cellGcmSetReturnCommandUnsafeInline(&context);
  346. // Update pointers
  347. m_nCallWritePos += size;
  348. return ret;
  349. }
  350. //--------------------------------------------------------------------------------------------------
  351. // Command Buffer callback
  352. //--------------------------------------------------------------------------------------------------
  353. #define SEGSIZE 0x40000
  354. #define SEGMASK 0x3FFFF
  355. int32 CPs3gcmGlobalState::CmdBufferFull(struct CellGcmContextData * pGcmContext, uint32_t size)
  356. {
  357. // move to next SEGSIZE, and then wrap to start
  358. // Determine where the next buffer will be
  359. uint32 nIoAddress = (uint32)g_ps3gcmGlobalState.m_pIoAddress;
  360. uint32 nextBufferStart = ((uint32)pGcmContext->begin + SEGSIZE) & (~SEGMASK);
  361. nextBufferStart -= nIoAddress;
  362. nextBufferStart &= (GCM_DEFCMDBUFFSIZE-1);
  363. nextBufferStart = nextBufferStart ? (nextBufferStart + nIoAddress) : (SEGSIZE + nIoAddress);
  364. // Flush RSX to this point
  365. cellGcmFlushUnsafeInline(pGcmContext);
  366. // put jump command to beginning of next buffer
  367. uint32 nextBufferOffset = nextBufferStart - nIoAddress;
  368. uint32 nextBufferEndOffset = ((nextBufferOffset + SEGSIZE) & (~SEGMASK)) - 4;
  369. cellGcmSetJumpCommandUnsafeInline(pGcmContext, nextBufferStart - nIoAddress );
  370. // get put/get/ref register address
  371. volatile CellGcmControl* control = cellGcmGetControlRegister();
  372. int count = 500000;
  373. // wait for RSX to finish all commands in next buffer (it's a ring buffer)
  374. volatile uint32_t get = (volatile uint32_t)control->get;
  375. while( (get < 0x1000 ) || ( (get >= nextBufferOffset) && (get < nextBufferEndOffset) ) )
  376. {
  377. sys_timer_usleep( 30 );
  378. get = (volatile uint32_t)control->get;
  379. // count--;
  380. // if (count < 1)
  381. // {
  382. // Msg("\n*****>>>> CmdBufferFull : get 0x%x : nextBufferOffset 0x%x : nextBufferEndOffset 0x%x\n", get, nextBufferOffset, nextBufferEndOffset );
  383. // count = 1;
  384. // }
  385. }
  386. // Set Command buffer context struct
  387. pGcmContext->begin = (uint32*)nextBufferStart;
  388. pGcmContext->end = (uint32*)(nextBufferEndOffset + nIoAddress);
  389. pGcmContext->current = (uint32*)nextBufferStart;
  390. return CELL_OK;
  391. }
  392. //--------------------------------------------------------------------------------------------------
  393. // Flip Control
  394. //
  395. // Summary :
  396. //
  397. // Label used to cap the framerate. ie label to ensure flips no faster than 1 (60hz) or 2 (30Hz) vblanks.
  398. // PPU blocks if previous flip not complete, so can't run too far ahead
  399. // vblanks and flips noted by callbacks
  400. //--------------------------------------------------------------------------------------------------
  401. enum {
  402. LABEL_FLIP_CONTROL_READY=1, // when label-before-flip is released
  403. LABEL_FLIP_CONTROL_WAIT, // when label-before-flip is not released
  404. /*
  405. label_flip_control:
  406. LABEL_FLIP_CONTROL_WAIT
  407. => (when releasing flip by ppu) => LABEL_FLIP_CONTROL_READY,
  408. => (when flip is finished by rsx) => LABEL_FLIP_CONTROL_WAIT,
  409. */
  410. FLIP_STATE_V1=1,
  411. FLIP_STATE_FLIP_RELEASED,
  412. FLIP_STATE_FLIPPED,
  413. /*
  414. flip_status sequence (30fps or slower):
  415. FLIP_STATE_FLIPPED
  416. (at vblank callback) => FLIP_STATE_V1
  417. (at vblank callback) =<release flip>=> FLIP_STATE_FLIP_RELEASED
  418. (at flip callback) => FLIP_STATE_FLIPPED
  419. */
  420. /*
  421. flip_status sequence (60fps or slower):
  422. FLIP_STATE_FLIPPED
  423. (at vblank callback) =<release flip>=> FLIP_STATE_FLIP_RELEASED
  424. (at flip callback) => FLIP_STATE_FLIPPED
  425. */
  426. };
  427. static volatile uint32_t *s_label_flip_control; // pointer to the flip control label
  428. static int s_flip_status=FLIP_STATE_FLIPPED; // status variable to control flip
  429. //--------------------------------------------------------------------------------------------------
  430. static bool Gcm_ReleaseFlip(void)
  431. {
  432. if (*s_label_flip_control==LABEL_FLIP_CONTROL_READY) {
  433. /* just in case rsx is running very slow somehow */
  434. /* and flip_control label is not updated even after the real flip */
  435. return false;
  436. }
  437. *s_label_flip_control=LABEL_FLIP_CONTROL_READY;
  438. return true;
  439. }
  440. void updateCursorPosition(const int pixelX, const int pixelY)
  441. {
  442. cellGcmSetCursorPosition(pixelX, pixelY);
  443. int32_t result = cellGcmUpdateCursor();
  444. if( result == CELL_GCM_ERROR_FAILURE)
  445. {
  446. // [dkorus] this case happens until we initialize the cursor
  447. //Msg(" hardware cursor error: cellGcmInitCursor() has not been called\n");
  448. }
  449. else if( result == CELL_GCM_ERROR_INVALID_VALUE )
  450. {
  451. Msg(" hardware cursor error: cursor bitmap is not correctly set\n");
  452. }
  453. }
  454. void enableCursor()
  455. {
  456. if (cellGcmSetCursorEnable() != CELL_OK )
  457. {
  458. Msg( "Hardware Cursor Error: trouble with enable\n" );
  459. }
  460. if ( cellGcmUpdateCursor() != CELL_OK )
  461. {
  462. Msg( "Hardware Cursor Error: trouble with update\n" );
  463. }
  464. }
  465. static void Gcm_VblankCallbackFunction(const uint32_t head)
  466. {
  467. // unused arg
  468. (void)head;
  469. int pixelX, pixelY;
  470. if ( g_pInputSystem )
  471. {
  472. bool cursorEnabled = g_pInputSystem->GetPS3CursorPos( pixelX, pixelY );
  473. if( cursorEnabled )
  474. {
  475. updateCursorPosition(pixelX,pixelY);
  476. }
  477. }
  478. switch (s_flip_status){
  479. case FLIP_STATE_FLIPPED:
  480. if (g_ps3gcmGlobalState.m_flipMode == 30){
  481. s_flip_status=FLIP_STATE_V1;
  482. } else if (g_ps3gcmGlobalState.m_flipMode == 60){
  483. if (Gcm_ReleaseFlip()){
  484. s_flip_status=FLIP_STATE_FLIP_RELEASED;
  485. }
  486. }
  487. break;
  488. case FLIP_STATE_V1:
  489. if (Gcm_ReleaseFlip()){
  490. s_flip_status=FLIP_STATE_FLIP_RELEASED;
  491. }
  492. break;
  493. case FLIP_STATE_FLIP_RELEASED:
  494. break;
  495. default:
  496. assert(0);
  497. }
  498. }
  499. static void Gcm_FlipCallbackFunction(const uint32_t head)
  500. {
  501. (void)head;
  502. switch (s_flip_status){
  503. case FLIP_STATE_FLIP_RELEASED:
  504. s_flip_status=FLIP_STATE_FLIPPED;
  505. break;
  506. default:
  507. break;
  508. }
  509. }
  510. // initialize flip control state machine
  511. static void Gcm_InitFlipControl(void)
  512. {
  513. cellGcmSetFlipMode( CELL_GCM_DISPLAY_HSYNC );
  514. g_ps3gcmGlobalState.m_frameNo = 0;
  515. g_ps3gcmGlobalState.m_finishIdx = 0;
  516. s_label_flip_control=cellGcmGetLabelAddress(GCM_LABEL_FLIP_CONTROL);
  517. *s_label_flip_control=LABEL_FLIP_CONTROL_WAIT;
  518. cellGcmSetFlipHandler(Gcm_FlipCallbackFunction);
  519. cellGcmSetVBlankHandler(Gcm_VblankCallbackFunction);
  520. }
  521. //--------------------------------------------------------------------------------------------------
  522. // Beginscene, endscene and flip
  523. //--------------------------------------------------------------------------------------------------
  524. uint32 gCmdBufferHighWater = 0;
  525. uint32 gCmdBufferStart = 0;
  526. void CPs3gcmGlobalState::BeginScene()
  527. {
  528. gCmdBufferStart = (uint32)gpGcmContext->current;
  529. gpGcmDrawState->BeginScene();
  530. }
  531. void CPs3gcmGlobalState::EndScene()
  532. {
  533. if ( (uint32)gpGcmContext->current > gCmdBufferStart )
  534. {
  535. uint32 bytes = (uint32)gpGcmContext->current - gCmdBufferStart;
  536. if (bytes > gCmdBufferHighWater ) gCmdBufferHighWater = bytes;
  537. }
  538. gpGcmDrawState->EndScene();
  539. }
  540. float g_fliptime = 0;
  541. void CPs3gcmGlobalState::SetFastFlip(bool onoff)
  542. {
  543. m_fastFlip = onoff;
  544. g_fliptime = Plat_FloatTime();
  545. }
  546. extern void OnFrameTimestampAvailableRsx( float ms );
  547. void CPs3gcmGlobalState::Flip()
  548. {
  549. cellSysutilCheckCallback();
  550. if(m_fastFlip)
  551. {
  552. Gcm_ReleaseFlip();
  553. float time = Plat_FloatTime();
  554. if ( (time - g_fliptime) > 0.05) goto fullflip;
  555. // Just end the frame, no point in flipping here...
  556. gpGcmDrawState->EndFrame();
  557. GCM_FUNC( cellGcmFlush );
  558. goto newframe;
  559. }
  560. fullflip:
  561. int idx, startIdx, endIdx;
  562. //--------------------------------------------------------------------------------------------------
  563. // Ensure any buffered state, copies etc... goes to GPU
  564. //--------------------------------------------------------------------------------------------------
  565. gpGcmDrawState->EndFrame();
  566. //--------------------------------------------------------------------------------------------------
  567. // Wait for previous frame Flip
  568. //--------------------------------------------------------------------------------------------------
  569. while (cellGcmGetFlipStatus()!=0){
  570. g_pGcmSharedData->CheckForAudioRequest();
  571. g_pGcmSharedData->CheckForServerRequest();
  572. sys_timer_usleep(300);
  573. }
  574. // Insert end of gpu timestamp
  575. idx = m_frameNo&1;
  576. endIdx = GCM_REPORT_TIMESTAMP_FRAME_FIRST + (idx*2) + 1;
  577. GCM_FUNC( cellGcmSetTimeStamp, endIdx );
  578. //--------------------------------------------------------------------------------------------------
  579. // If requested, lets defrag VRAM
  580. //--------------------------------------------------------------------------------------------------
  581. if (g_pGcmSharedData->m_bDeFrag)
  582. {
  583. g_pGcmSharedData->m_bDeFrag = 0;
  584. extern void Ps3gcmLocalMemoryAllocator_CompactWithReason( char const *szReason );
  585. Ps3gcmLocalMemoryAllocator_CompactWithReason( "End of Round" );
  586. }
  587. //--------------------------------------------------------------------------------------------------
  588. // Get Timestamps
  589. //--------------------------------------------------------------------------------------------------
  590. if (m_frameNo)
  591. {
  592. idx = ((m_frameNo-1) & 1);
  593. startIdx = GCM_REPORT_TIMESTAMP_FRAME_FIRST + (idx*2);
  594. endIdx = startIdx+1;
  595. uint64 uiStartTimestamp = cellGcmGetTimeStamp( startIdx );
  596. uint64 uiEndTimestamp = cellGcmGetTimeStamp( endIdx );
  597. uint64 uiRsxTimeInNanoSeconds = uiEndTimestamp - uiStartTimestamp;
  598. OnFrameTimestampAvailableRsx( uiRsxTimeInNanoSeconds / 1000000.0f );
  599. }
  600. //--------------------------------------------------------------------------------------------------
  601. // Insert new flip command and flush gpu
  602. //--------------------------------------------------------------------------------------------------
  603. // reset FlipStatus = 1
  604. cellGcmResetFlipStatus();
  605. // queue Flip command
  606. GCM_FUNC( cellGcmSetFlipWithWaitLabel, m_display.surfaceFlipIdx, GCM_LABEL_FLIP_CONTROL, LABEL_FLIP_CONTROL_READY);
  607. m_display.Flip();
  608. GCM_FUNC( cellGcmSetWriteCommandLabel, GCM_LABEL_FLIP_CONTROL, LABEL_FLIP_CONTROL_WAIT);
  609. GCM_FUNC( cellGcmSetWaitFlip );
  610. GCM_FUNC( cellGcmFlush );
  611. extern void Ps3gcmLocalMemoryAllocator_Reclaim();
  612. Ps3gcmLocalMemoryAllocator_Reclaim();
  613. //--------------------------------------------------------------------------------------------------
  614. // Start a new frame
  615. //--------------------------------------------------------------------------------------------------
  616. newframe:
  617. m_frameNo ++;
  618. // Insert start of gpu timestamp
  619. idx = m_frameNo&1;
  620. startIdx = GCM_REPORT_TIMESTAMP_FRAME_FIRST + (idx*2);
  621. GCM_FUNC( cellGcmSetTimeStamp, startIdx );
  622. // Put RSX into known state for start of frame
  623. gpGcmDrawState->ResetRsxState();
  624. // Moved from DX present()
  625. GCM_FUNC( cellGcmSetInvalidateVertexCache );
  626. }
  627. //--------------------------------------------------------------------------------------------------
  628. // Buffer management
  629. //--------------------------------------------------------------------------------------------------
  630. CPs3gcmBuffer * CPs3gcmBuffer::New( uint32 uiSize, CPs3gcmAllocationType_t uType )
  631. {
  632. CPs3gcmBuffer * p = new CPs3gcmBuffer;
  633. p->m_lmBlock.Alloc( uType, uiSize );
  634. return p;
  635. }
  636. void CPs3gcmBuffer::Release()
  637. {
  638. // Wait for RSX to finish using the buffer memory
  639. // and free it later
  640. m_lmBlock.Free();
  641. delete this;
  642. }