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.

1116 lines
37 KiB

  1. //========== Copyright � 2010, Valve Corporation, All rights reserved. ========
  2. #include "dxabstract.h"
  3. #include "ps3gcmstate.h"
  4. #include "utlmap.h"
  5. #include "ps3/ps3gcmlabels.h"
  6. #include "spugcm.h"
  7. #include "memdbgon.h"
  8. #include <sysutil/sysutil_sysparam.h>
  9. #include "ps3/ps3_helpers.h"
  10. //////////////////////////////////////////////////////////////////////////
  11. #define MB (1024*1024)
  12. // the safety margin, in bytes, for the command buffer
  13. // we may use the 16 bytes beyond the buffer to write jump-back commands
  14. const uint s_nCmdSizeSafetyMargin = 32;
  15. CPs3gcmGlobalState g_ps3gcmGlobalState;
  16. uint8 g_dataShaderPsEmpty[] = {
  17. #include "shader_ps_empty.h"
  18. };
  19. int32_t GcmContextPermCallbackError(struct CellGcmContextData *pCtx, uint32_t nAlloc )
  20. {
  21. Error( "Unexpected error while filling permanent cmd buffer: %d Kb filled up, choked on allocating %d words. RefCount=%d. Permanent cmd buffer size is not enough, or there's a leak.\n", uintp(pCtx->current)-uintp(pCtx->begin), nAlloc, g_ps3gcmGlobalState.m_nCmdBufferRefCount );
  22. return EINVAL; // it's not CELL_OK
  23. }
  24. #if GCM_CTX_UNSAFE_MODE
  25. static int32_t Ps3gcmGlobalCommandBufferReserveCallback( struct CellGcmContextData *context, uint32_t nCount )
  26. {
  27. nCount;
  28. g_ps3gcmGlobalState.CmdBufferReservationCallback( context );
  29. return CELL_OK;
  30. }
  31. #undef cellGcmFlush // we need it to implement our command buffer flush
  32. uint32 CPs3gcmGlobalState::GetRsxControlNextReferenceValue()
  33. {
  34. static uint32 s_uiReferenceValue;
  35. return ++ s_uiReferenceValue;
  36. }
  37. #endif
  38. static inline uint32 Ps3gcmGlobalCommandBufferUsageSegmentBytes( uint32 nCmdSize )
  39. {
  40. #if GCM_CTX_UNSAFE_MODE
  41. // Triple buffer in unsafe mode
  42. return ( nCmdSize / 3 ) & ~127;
  43. #else
  44. // Default 32 Kb buffers in safe mode
  45. return 32768;
  46. #endif
  47. }
  48. static inline uint32 Ps3gcmGlobalCommandBufferUsageCookie( struct CellGcmContextData *context, void *pIoAddress, uint32 nCmdSize )
  49. {
  50. // Note only which portion is in use by RSX when switching to the next segment:
  51. uint32 const offBegin = ( ( char * ) context->begin ) - ( ( char * ) pIoAddress );
  52. uint32 const numSegmentBytes = Ps3gcmGlobalCommandBufferUsageSegmentBytes( nCmdSize );
  53. return ( offBegin / numSegmentBytes );
  54. }
  55. uint32 CalculateMemorySizeFromCmdLineParam( char const *pCmdParamName, uint32 nDefaultValue, uint32 nMinValue )
  56. {
  57. uint nCmdSize = 0;
  58. if ( const char *p = CommandLine()->ParmValue( pCmdParamName, (const char *)NULL ) )
  59. {
  60. for(; isdigit( *p ) ; ++p )
  61. {
  62. nCmdSize = nCmdSize * 10 + (*p-'0');
  63. }
  64. switch( *p )
  65. {
  66. case '\0':
  67. case 'm':
  68. case 'M':
  69. nCmdSize *= 1024 * 1024;
  70. break;
  71. case 'k':
  72. case 'K':
  73. nCmdSize *= 1024;
  74. break;
  75. case 'b':
  76. case 'B':
  77. break;
  78. default:
  79. nCmdSize = 0;
  80. break;
  81. }
  82. }
  83. else
  84. {
  85. return nDefaultValue;
  86. }
  87. return MAX( nCmdSize, nMinValue );
  88. }
  89. int32 CPs3gcmGlobalState::Init()
  90. {
  91. MEM_ALLOC_CREDIT_( "GCM INIT" );
  92. m_nIoLocalOffsetEmptyFragmentProgramSetupRoutine = 0;
  93. ///////////////////////////////////////////////////////////////////////////////////
  94. // Negotiate video output resolution, setup display gamma, surface pitch and so on
  95. //
  96. if( int nError= InitVideo() )
  97. return nError;
  98. //////////////////////////////////////////////////////////////////////////
  99. //
  100. // Allocate GCM IO & CMD buffers
  101. //
  102. // Default sizes for IO and CMD buffers
  103. #if GCM_CTX_UNSAFE_MODE
  104. m_nCmdSize = 3*MB;
  105. #else
  106. m_nCmdSize = 512 * 1024; // TEST: 256Kb or less is for testing only; production should be at least 512Kb; NOTE: TEST WITH < 128k !!
  107. #endif
  108. m_nCmdSize = CalculateMemorySizeFromCmdLineParam( "-gcmSizeCMD", m_nCmdSize, m_nCmdSize );
  109. const uint nMaxIoMappedMemorySize = 256*MB;
  110. // start with nothing preallocated
  111. m_nIoSize = m_nIoSizeNotPreallocated = nMaxIoMappedMemorySize;
  112. m_pIoAddress = NULL;
  113. CreateIoBuffers(); // let the buffers creation routine calculate the required buffers size
  114. uint32 nMinIoMemoryRequired = nMaxIoMappedMemorySize - ( m_nIoSizeNotPreallocated - m_nCmdSize );
  115. uint32 nIoMemoryAllocated = AlignValue( nMinIoMemoryRequired, MB ); // the size should not change here in release!
  116. m_nIoSize = m_nIoSizeNotPreallocated = nIoMemoryAllocated;
  117. // Try to allocate main memory that will be mapped to IO address space
  118. Msg( "======== GCM IO memory allocated @0x%p size = %d MB ========\n", m_pIoAddress, m_nIoSize / 1024 / 1024 );
  119. sys_addr_t pIoAddress = NULL;
  120. int nError = sys_memory_allocate( m_nIoSize, SYS_MEMORY_PAGE_SIZE_1M, &pIoAddress );
  121. if ( CELL_OK != nError )
  122. {
  123. Msg( "sys_memory_allocate failed to allocate %d bytes (err: %d)\n", m_nIoSize, nError );
  124. return nError;
  125. }
  126. m_pIoAddress = (void *)pIoAddress;
  127. CreateIoBuffers(); // Create the IO buffers for real now
  128. // Determine how much memory has been used:
  129. uint nCmdSizeSlackInitial = ( m_nIoSizeNotPreallocated - m_nCmdSize ); // we can use this much more for anyting, and the rest for cmd buffer (which is not preallocated in CreateIOBuffers())
  130. Assert( nCmdSizeSlackInitial < MB );
  131. g_spuGcm.UseIoBufferSlack( nCmdSizeSlackInitial );
  132. Assert( m_nIoSizeNotPreallocated >= m_nCmdSize ); // we should have enough space for cmd buffer, even thought we may use up some slack
  133. uint nCmdSizeSlackRemaining = ( m_nIoSizeNotPreallocated - m_nCmdSize ) & ( MB - 1 ); // we need this much for cmd buffer (not preallocated in CreateIOBuffers())
  134. Msg( "IO Buffer slack: was %u kB, used %u kB, reusing remaining %u kB for cmd buffer\n", nCmdSizeSlackInitial / 1024, ( nCmdSizeSlackInitial - nCmdSizeSlackRemaining ) / 1024, nCmdSizeSlackRemaining / 1024 );
  135. // leave space for all buffers, and use the rest of the space for cmd buffer
  136. // we need the cmd buffer to be 16-byte aligned and have 16 byte slack in the end . Let's make it 32 for good measure
  137. m_nCmdSize = ( m_nIoSizeNotPreallocated - s_nCmdSizeSafetyMargin ) & -16;
  138. m_nCmdBufferRefCount = 0;
  139. if( int nError = InitGcm() )
  140. return nError;
  141. // Retrieve RSX local memory config
  142. CellGcmConfig rsxConfig;
  143. cellGcmGetConfiguration( &rsxConfig );
  144. m_pLocalBaseAddress = rsxConfig.localAddress;
  145. m_nLocalSize = rsxConfig.localSize;
  146. cellGcmAddressToOffset( m_pLocalBaseAddress, &m_nLocalBaseOffset );
  147. Assert( m_nLocalBaseOffset == 0 );
  148. // Initialize allocator/tracker
  149. extern void Ps3gcmLocalMemoryAllocator_Init();
  150. Ps3gcmLocalMemoryAllocator_Init();
  151. CreateRsxBuffers();
  152. CreateEmptyPixelShader();
  153. CreateDebugStripeTextureBuffer();
  154. g_spuGcm.OnGcmInit();
  155. return CELL_OK;
  156. }
  157. void CPs3gcmGlobalState::CreateRsxBuffers()
  158. {
  159. //////////////////////////////////////////////////////////////////////////
  160. //
  161. // Create automatic display objects
  162. //
  163. if( m_nSurfaceRenderPitch != cellGcmGetTiledPitchSize( m_nRenderSize[0] * 4 ) )
  164. {
  165. Error("Pre-computed surface render pitch %u != %u = cellGcmGetTiledPitchSize( %u * 4 ) ", m_nSurfaceRenderPitch, cellGcmGetTiledPitchSize( m_nRenderSize[0] * 4 ), m_nRenderSize[0] );
  166. }
  167. // Color buffers
  168. for ( int k = 0; k < ARRAYSIZE( m_display.surfaceColor ); ++ k )
  169. {
  170. uint32 nRenderSize32bpp = GetRenderSurfaceBytes(); // 32-line vertical alignment required in local memory
  171. m_display.surfaceColor[k].Alloc( kAllocPs3gcmColorBufferFB, nRenderSize32bpp );
  172. cellGcmSetDisplayBuffer( k, m_display.surfaceColor[k].Offset(), m_nSurfaceRenderPitch, m_nRenderSize[0], m_nRenderSize[1] );
  173. }
  174. // Depth buffer
  175. {
  176. uint32 zcullSize[2] = { AlignValue( m_nRenderSize[0], 64 ), AlignValue( m_nRenderSize[1], 64 ) };
  177. uint32 nDepthPitch = cellGcmGetTiledPitchSize( zcullSize[0] * 4 );
  178. uint32 uDepthBufferSize32bpp = nDepthPitch * zcullSize[1];
  179. uDepthBufferSize32bpp = AlignValue( uDepthBufferSize32bpp, PS3GCMALLOCATIONALIGN( kAllocPs3gcmDepthBuffer ) );
  180. m_display.surfaceDepth.Alloc( kAllocPs3gcmDepthBuffer, uDepthBufferSize32bpp );
  181. uint32 uiZcullIndex = m_display.surfaceDepth.ZcullMemoryIndex();
  182. cellGcmBindZcull( uiZcullIndex,
  183. m_display.surfaceDepth.Offset(),
  184. zcullSize[0], zcullSize[1],
  185. m_display.surfaceDepth.ZcullMemoryStart(),
  186. CELL_GCM_ZCULL_Z24S8,
  187. CELL_GCM_SURFACE_CENTER_1,
  188. CELL_GCM_ZCULL_LESS,
  189. CELL_GCM_ZCULL_LONES,
  190. CELL_GCM_SCULL_SFUNC_ALWAYS,
  191. 0, 0 // sRef, sMask
  192. );
  193. uint32 uiTileIndex = m_display.surfaceDepth.TiledMemoryIndex();
  194. cellGcmSetTileInfo( uiTileIndex, CELL_GCM_LOCATION_LOCAL, m_display.surfaceDepth.Offset(),
  195. uDepthBufferSize32bpp, m_nSurfaceRenderPitch, CELL_GCM_COMPMODE_Z32_SEPSTENCIL_REGULAR,
  196. m_display.surfaceDepth.TiledMemoryTagAreaBase(), // The area base + size/0x10000 will be allocated as the tag area.
  197. 3 ); // Default depth buffer on bank 3
  198. cellGcmBindTile( uiTileIndex );
  199. }
  200. g_spuGcm.CreateRsxBuffers();
  201. }
  202. void CPs3gcmGlobalState::DrawDebugStripe( uint nScreenX, uint nScreenY, uint nStripeY, uint nStripeWidth, uint nStripeHeight, int nNext )
  203. {
  204. if( nScreenX < m_nRenderSize[0] )
  205. {
  206. uint nDstOffset = m_display.surfaceColor[ m_display.NextSurfaceIndex( nNext + CPs3gcmDisplay::SURFACE_COUNT ) ].Offset();
  207. uint nSrcOffset = m_debugStripeImageBuffer.Offset();
  208. uint nRenderStripeWidth = MIN( ( uint )( m_nRenderSize[0] - nScreenX - 4 ), nStripeWidth );
  209. Assert( nScreenX + nRenderStripeWidth < ( uint )m_nRenderSize[0] );
  210. //static int x0 = 128, y0 = 64,x1 = 0,y1 = 0, w1 = 128, h1 = 1;
  211. Assert( nStripeY + nStripeHeight <= 4 );
  212. GCM_FUNC( cellGcmSetTransferImage, CELL_GCM_TRANSFER_LOCAL_TO_LOCAL,
  213. nDstOffset,
  214. m_nSurfaceRenderPitch,
  215. /*x0,y0,*/nScreenX, nScreenY,
  216. nSrcOffset,
  217. m_nRenderSize[0] * 4,
  218. /*x1,y1*/0, nStripeY, nRenderStripeWidth, nStripeHeight,
  219. 4 );
  220. }
  221. }
  222. void CPs3gcmGlobalState::CreateDebugStripeTextureBuffer()
  223. {
  224. const int s_nDebugScanlineColor[] = { 0xFFFFFFFF, 0xFFFF80FF, 0xFF00FF00, 0xFFFFFF00 };
  225. m_debugStripeImageBuffer.Alloc( kAllocPs3gcmTextureData, m_nRenderSize[0] * 4 * ARRAYSIZE( s_nDebugScanlineColor ) );
  226. uint32 * pEaLocalDebugScanline = ( uint32* ) m_debugStripeImageBuffer.DataInLocalMemory();
  227. for( uint y = 0; y < ARRAYSIZE( s_nDebugScanlineColor ); ++y )
  228. {
  229. for( uint nX = 0; nX < m_nRenderSize[0]; ++nX )
  230. {
  231. uint nColor = s_nDebugScanlineColor[y];
  232. switch( nX % 100 )
  233. {
  234. case 98:case 99: case 1:case 2: nColor = 0x80808080; break;//
  235. case 0: nColor = 0; break;//
  236. case 50: nColor = 0xFF800000; break; //
  237. default:
  238. switch( nX % 10 )
  239. {
  240. case 8: case 9: case 1: case 2: nColor = 0xFFFFFF80; break;// grey;
  241. case 0: nColor = 0xFF40C0FF; break;//
  242. }
  243. break;
  244. }
  245. pEaLocalDebugScanline[nX + m_nRenderSize[0] * y] = nColor;
  246. }
  247. }
  248. }
  249. void CPs3gcmGlobalState::CreateEmptyPixelShader()
  250. {
  251. //////////////////////////////////////////////////////////////////////////
  252. //
  253. // Create an empty pixel shader, upload ucode to local memory
  254. //
  255. m_pShaderPsEmpty = reinterpret_cast< CgBinaryProgram * >( g_dataShaderPsEmpty );
  256. m_pShaderPsEmptyBuffer.Alloc( kAllocPs3GcmShader, m_pShaderPsEmpty->ucodeSize );
  257. V_memcpy( m_pShaderPsEmptyBuffer.DataInLocalMemory(), ( (char*)m_pShaderPsEmpty ) + m_pShaderPsEmpty->ucode, m_pShaderPsEmpty->ucodeSize );
  258. CellGcmContextData * permBufferContext = CmdBufferAlloc( );
  259. uint32 * pBeginPermCmdBuffer = permBufferContext->current;
  260. m_nIoLocalOffsetEmptyFragmentProgramSetupRoutine = CmdBufferToIoOffset( pBeginPermCmdBuffer );
  261. cellGcmSetFragmentProgramInline( permBufferContext, ( CGprogram ) m_pShaderPsEmpty, m_pShaderPsEmptyBuffer.Offset() );
  262. cellGcmSetReturnCommand( permBufferContext );
  263. }
  264. void CPs3gcmGlobalState::CreateIoBuffers()
  265. {
  266. //////////////////////////////////////////////////////////////////////////////
  267. //
  268. // Preallocate IO memory buffers, compute the max memory available to the command buffer
  269. // THe memory is allocated from the end towards the beginning (where the cmd buffer is)
  270. // and the cmd buffer occupies all the extra memory at the start
  271. //
  272. uint nPermanentCmdBufferSize = 16 * 1024; // reduce by padding in the end, to keep nice alignment
  273. g_spuGcm.CreateIoBuffers();
  274. // NOTE: the buffer MUST have 1KB padding in the end to prevent overfetch RSX crash!
  275. m_cmdBufferPermContext.begin = m_cmdBufferPermContext.current = ( uint32* ) IoMemoryPrealloc( 128, nPermanentCmdBufferSize );
  276. m_cmdBufferPermContext.end = ( uint32* )( uintp( m_cmdBufferPermContext.begin ) + nPermanentCmdBufferSize );
  277. m_cmdBufferPermContext.callback = GcmContextPermCallbackError;
  278. // RSX data transfer buffer
  279. m_nRsxDataTransferBufferSize = 0*MB;
  280. m_nRsxDataTransferBufferSize = CalculateMemorySizeFromCmdLineParam( "-gcmSizeTransfer", m_nRsxDataTransferBufferSize );
  281. m_pRsxDataTransferBuffer = IoMemoryPrealloc( 1, m_nRsxDataTransferBufferSize );
  282. // RSX main memory pool buffer
  283. m_nRsxMainMemoryPoolBufferSize = PS3GCM_VBIB_IN_IO_MEMORY ? 60 * MB : 0 * MB;
  284. m_pRsxMainMemoryPoolBuffer = m_nRsxMainMemoryPoolBufferSize ? IoMemoryPrealloc( 128, m_nRsxMainMemoryPoolBufferSize ) : NULL;
  285. }
  286. int CPs3gcmGlobalState::InitVideo()
  287. {
  288. //////////////////////////////////////////////////////////////////////////
  289. //
  290. // Initialize m_display
  291. //
  292. CellVideoOutState videoOutState;
  293. int result = cellVideoOutGetState( CELL_VIDEO_OUT_PRIMARY, 0, &videoOutState);
  294. if ( result < CELL_OK )
  295. return result;
  296. CellVideoOutResolution resolution;
  297. result = cellVideoOutGetResolution( videoOutState.displayMode.resolutionId, &resolution );
  298. if ( result < CELL_OK )
  299. return result;
  300. // Always output scanout in system m_display resolution
  301. m_nRenderSize[0] = resolution.width;
  302. m_nRenderSize[1] = resolution.height;
  303. // Handle special case: 1080p will be upsampled from 720p
  304. if ( resolution.height >= 720 && CommandLine()->FindParm( "-480p" ) )
  305. {
  306. m_nRenderSize[0] = 640;
  307. m_nRenderSize[1] = 480;
  308. videoOutState.displayMode.resolutionId = CELL_VIDEO_OUT_RESOLUTION_480;
  309. }
  310. else if ( resolution.height >= 1080 && !CommandLine()->FindParm( "-1080p" ) )
  311. {
  312. m_nRenderSize[0] = 1280;
  313. m_nRenderSize[1] = 720;
  314. videoOutState.displayMode.resolutionId = CELL_VIDEO_OUT_RESOLUTION_720;
  315. }
  316. //////////////////////////////////////////////////////////////////////////
  317. //
  318. // Set video output
  319. //
  320. CellVideoOutConfiguration videocfg;
  321. memset( &videocfg, 0, sizeof(videocfg) );
  322. videocfg.resolutionId = videoOutState.displayMode.resolutionId;
  323. videocfg.format = CELL_VIDEO_OUT_BUFFER_COLOR_FORMAT_X8R8G8B8;
  324. videocfg.pitch = cellGcmGetTiledPitchSize( m_nRenderSize[0] * 4 );
  325. m_nSurfaceRenderPitch = videocfg.pitch;
  326. // Configure video output
  327. result = cellVideoOutConfigure( CELL_VIDEO_OUT_PRIMARY, &videocfg, NULL, 0 );
  328. if ( result < CELL_OK )
  329. return result;
  330. // Get the new video output
  331. result = cellVideoOutGetState( CELL_VIDEO_OUT_PRIMARY, 0, &videoOutState );
  332. if ( result < CELL_OK )
  333. return result;
  334. m_flRenderAspect = ( videoOutState.displayMode.aspect == CELL_VIDEO_OUT_ASPECT_4_3 ) ? ( 4.0f/3.0f ) : ( 16.0f / 9.0f );
  335. // Set the gamma to deal with TV's having a darker gamma than computer monitors
  336. result = cellSysmoduleLoadModule( CELL_SYSMODULE_AVCONF_EXT );
  337. if ( result == CELL_OK )
  338. {
  339. cellVideoOutSetGamma( CELL_VIDEO_OUT_PRIMARY, 2.2f / 2.5f );
  340. }
  341. else
  342. {
  343. Warning( "***** ERROR calling cellSysmoduleLoadModule( CELL_SYSMODULE_AVCONF_EXT )! Gamma not set!\n" );
  344. return result;
  345. }
  346. // Output video color settings
  347. CellVideoOutDeviceInfo info;
  348. cellVideoOutGetDeviceInfo( CELL_VIDEO_OUT_PRIMARY, 0, &info );
  349. if ( info.rgbOutputRange == CELL_VIDEO_OUT_RGB_OUTPUT_RANGE_LIMITED )
  350. {
  351. DevMsg( "***** Video Out - Limited Range (16-235) - Gamma=%d *****\n", info.colorInfo.gamma );
  352. }
  353. else
  354. {
  355. DevMsg( "***** Video Out - Full Range (0-255) - Gamma=%d *****\n", info.colorInfo.gamma );
  356. }
  357. return CELL_OK;
  358. }
  359. //////////////////////////////////////////////////////////////////////////
  360. //
  361. // Init GCM
  362. //
  363. int CPs3gcmGlobalState::InitGcm()
  364. {
  365. m_nFlushCounter = 0;
  366. int32 result = cellGcmInit( m_nCmdSize, m_nIoSize, m_pIoAddress );
  367. if ( result < CELL_OK )
  368. return result;
  369. g_pGcmSharedData->m_nIoMemorySize = m_nIoSize;
  370. g_pGcmSharedData->m_pIoMemory = m_pIoAddress;
  371. // Set the flip mode
  372. cellGcmSetFlipMode( CELL_GCM_DISPLAY_HSYNC );
  373. cellGcmAddressToOffset( m_pIoAddress, &m_nIoOffsetDelta );
  374. m_nIoOffsetDelta -= uintp( m_pIoAddress );
  375. if( CmdBufferToIoOffset( gCellGcmCurrentContext->begin ) != SYSTEM_CMD_BUFFER_RESERVED_AREA )
  376. {
  377. Warning(
  378. "********************************************************************************\n"
  379. "**********Unexpected GCM system command buffer begin 0x%08x*****************\n"
  380. "********************************************************************************\n",
  381. CmdBufferToIoOffset( gCellGcmCurrentContext->begin )
  382. );
  383. }
  384. #if GCM_CTX_UNSAFE_MODE
  385. // Set custom callback function
  386. GCM_CTX->callback = Ps3gcmGlobalCommandBufferReserveCallback;
  387. m_pCurrentCmdBufferSegmentRSX = ( uint32_t const volatile * ) cellGcmGetLabelAddress( GCM_LABEL_GLOBAL_CMD_BUFFER_BEGIN );
  388. *const_cast< uint32_t * >( m_pCurrentCmdBufferSegmentRSX ) = Ps3gcmGlobalCommandBufferUsageCookie( GCM_CTX, m_pIoAddress, m_nCmdSize );
  389. // In unsafe mode split command buffer into segments
  390. GCM_CTX->end = ( uint32 * )( Ps3gcmGlobalCommandBufferUsageSegmentBytes( m_nCmdSize ) + ( ( char * ) m_pIoAddress ) ) - 4;
  391. m_pCurrentCmdBufferUnflushedBeginRSX = GCM_CTX->begin;
  392. #endif
  393. return CELL_OK;
  394. }
  395. void CPs3gcmGlobalState::Shutdown()
  396. {
  397. // Let RSX wait for final flip
  398. GCM_FUNC( cellGcmSetWaitFlip );
  399. #if GCM_CTX_UNSAFE_MODE
  400. // Let PPU wait for all commands done (include waitFlip)
  401. uint32 rsxref = GetRsxControlNextReferenceValue();
  402. GCM_FUNC( cellGcmFinish, rsxref );
  403. #else
  404. g_spuGcm.Shutdown();
  405. #endif
  406. cellSysmoduleUnloadModule( CELL_SYSMODULE_AVCONF_EXT );
  407. }
  408. void CPs3gcmGlobalState::CmdBufferFlush( CmdBufferFlushType_t eFlushType )
  409. {
  410. Assert( !g_spuGcm.IsDeferredDrawQueue() );
  411. g_spuGcm.CmdBufferFlush();
  412. m_nFlushCounter++;
  413. if ( eFlushType == kFlushEndFrame )
  414. {
  415. extern void Ps3gcmLocalMemoryAllocator_Reclaim();
  416. Ps3gcmLocalMemoryAllocator_Reclaim();
  417. }
  418. }
  419. void CPs3gcmGlobalState::CmdBufferFinish()
  420. {
  421. #if GCM_CTX_UNSAFE_MODE
  422. CmdBufferFlush( CPs3gcmGlobalState::kFlushForcefully );
  423. uint32 rsxref = g_ps3gcmGlobalState.GetRsxControlNextReferenceValue();
  424. GCM_FUNC( cellGcmFinish, rsxref );
  425. #else
  426. g_spuGcm.CmdBufferFinish();
  427. #endif
  428. }
  429. #if GCM_CTX_UNSAFE_MODE
  430. void CPs3gcmGlobalState::CmdBufferReservationCallback( struct CellGcmContextData *context )
  431. {
  432. enum CmdBufferSize_t
  433. {
  434. kJumpCmdSize = 1 * sizeof(uint32),
  435. kSegmentReservedSize = kJumpCmdSize,
  436. };
  437. uint32 const uiOldRsxCookie = Ps3gcmGlobalCommandBufferUsageCookie( context, m_pIoAddress, m_nCmdSize );
  438. uint32 const uiSegmentSize = Ps3gcmGlobalCommandBufferUsageSegmentBytes( m_nCmdSize );
  439. uint32 uiNewBegin = ( ( char * ) context->end ) - ( ( char * ) m_pIoAddress ) + kSegmentReservedSize;
  440. uint32 uiNewEnd = uiNewBegin + uiSegmentSize - kSegmentReservedSize;
  441. if ( uiNewBegin >= m_nCmdSize )
  442. {
  443. uiNewBegin = SYSTEM_CMD_BUFFER_RESERVED_AREA;
  444. uiNewEnd = uiSegmentSize - kSegmentReservedSize;
  445. }
  446. // Let RSX go ahead and grab the currently full segment
  447. cellGcmFlush( context );
  448. // Insert the jump command to jump into the new segment
  449. cellGcmSetJumpCommandUnsafeInline( context, uiNewBegin );
  450. // Prepare the settings for the new segment
  451. context->begin = reinterpret_cast< uint32_t * >( ( ( char * ) m_pIoAddress ) + uiNewBegin );
  452. context->end = reinterpret_cast< uint32_t * >( ( ( char * ) m_pIoAddress ) + uiNewEnd );
  453. context->current = context->begin;
  454. // Make sure that RSX is not using the new context segment
  455. uint32 const uiNewRsxCookie = Ps3gcmGlobalCommandBufferUsageCookie( context, m_pIoAddress, m_nCmdSize );
  456. if ( uiNewRsxCookie != uiOldRsxCookie )
  457. {
  458. while ( uiNewRsxCookie == *m_pCurrentCmdBufferSegmentRSX )
  459. sys_timer_usleep( 30 ); // RSX is still using the segments with the new cookie
  460. // The first word in the new segment will be to have RSX set label marking the segment
  461. // as being used by RSX
  462. cellGcmSetWriteCommandLabelUnsafeInline( context, GCM_LABEL_GLOBAL_CMD_BUFFER_BEGIN, uiNewRsxCookie );
  463. }
  464. #if GCM_CTX_UNSAFE_MODE
  465. m_pCurrentCmdBufferUnflushedBeginRSX = context->current;
  466. #endif
  467. }
  468. #endif
  469. //////////////////////////////////////////////////////////////////////////
  470. void * CPs3gcmGlobalState::IoMemoryPrealloc( uint nAlign, uint nSize )
  471. {
  472. Assert( !( nAlign & ( nAlign - 1 ) ) );
  473. // we never need to allocate with alignment greater than the base of IO address;
  474. // hence we can align the not-preallocated size only
  475. Assert( !( ( nAlign - 1 ) & uintp( m_pIoAddress ) ) );
  476. m_nIoSizeNotPreallocated = ( m_nIoSizeNotPreallocated - nSize ) & ~( nAlign - 1 );
  477. uintp eaIoAddress = uintp( m_pIoAddress ) + m_nIoSizeNotPreallocated;
  478. Assert( !( eaIoAddress & ( nAlign - 1 ) ) );
  479. return m_pIoAddress ? ( void* )eaIoAddress : NULL;
  480. }
  481. void * CPs3gcmGlobalState::IoSlackAlloc( uint nAlign, uint nSize )
  482. {
  483. Assert( m_pIoAddress ); // don't call this in the first pass of CreateIoBuffers() !
  484. Assert( !( nAlign & ( nAlign - 1 ) ) ); // alignment must be sane!
  485. // we never need to allocate with alignment greater than the base of IO address;
  486. // hence we can align the not-preallocated size only
  487. Assert( !( ( nAlign - 1 ) & uintp( m_pIoAddress ) ) );
  488. // preview what the new free io size will be ( may be negative if nSize is too big )
  489. signed int nNewIoSizeNotPreallocated = ( m_nIoSizeNotPreallocated - nSize ) & ~( nAlign - 1 );
  490. if( nNewIoSizeNotPreallocated > signed( m_nCmdSize + s_nCmdSizeSafetyMargin ) )
  491. {
  492. // we still have enough room left for command buffer, so we can allocate this memory and it'll be in IO slack
  493. Msg( "Saving %d kB, using IO memory slack\n", nSize / 1024 );
  494. m_nIoSizeNotPreallocated = nNewIoSizeNotPreallocated;
  495. uintp eaIoAddress = uintp( m_pIoAddress ) + m_nIoSizeNotPreallocated;
  496. Assert( !( eaIoAddress & ( nAlign - 1 ) ) );
  497. return ( void* )eaIoAddress;
  498. }
  499. else
  500. {
  501. return MemAlloc_AllocAligned( nSize, nAlign );
  502. }
  503. }
  504. void CPs3gcmGlobalState::IoSlackFree( void * eaMemory )
  505. {
  506. if( eaMemory && !IsIoMemory( eaMemory ) )
  507. {
  508. MemAlloc_FreeAligned( eaMemory );
  509. }
  510. }
  511. //////////////////////////////////////////////////////////////////////////
  512. //
  513. // Texture layouts
  514. //
  515. //===============================================================================
  516. #ifdef _CERT
  517. #define GLMTEX_FMT_DESC( x )
  518. #else
  519. #define GLMTEX_FMT_DESC( x ) x ,
  520. #endif
  521. #define CELL_GCM_REMAP_MODE_OIO(order, inputARGB, outputARGB) \
  522. (((order)<<16)|((inputARGB))|((outputARGB)<<8))
  523. #define REMAPO( x ) CELL_GCM_TEXTURE_REMAP_ORDER_X##x##XY
  524. #define REMAP4(a,r,g,b) (((a)<<0)|((r)<<2)|((g)<<4)|((b)<<6))
  525. #define REMAP_ARGB REMAP4( CELL_GCM_TEXTURE_REMAP_FROM_A, CELL_GCM_TEXTURE_REMAP_FROM_R, CELL_GCM_TEXTURE_REMAP_FROM_G, CELL_GCM_TEXTURE_REMAP_FROM_B )
  526. #define REMAP_4 REMAP4( CELL_GCM_TEXTURE_REMAP_REMAP, CELL_GCM_TEXTURE_REMAP_REMAP, CELL_GCM_TEXTURE_REMAP_REMAP, CELL_GCM_TEXTURE_REMAP_REMAP )
  527. #define REMAP_13 REMAP4( CELL_GCM_TEXTURE_REMAP_ONE, CELL_GCM_TEXTURE_REMAP_REMAP, CELL_GCM_TEXTURE_REMAP_REMAP, CELL_GCM_TEXTURE_REMAP_REMAP )
  528. #define REMAP_4X(x) REMAP4( x, x, x, x )
  529. #define REMAP_13X(y, x) REMAP4( y, x, x, x )
  530. #define REMAP_ALL_DEFAULT CELL_GCM_REMAP_MODE_OIO( REMAPO(Y), REMAP_ARGB, REMAP_4 )
  531. #define REMAP_ALL_DEFAULT_X CELL_GCM_REMAP_MODE_OIO( REMAPO(X), REMAP_ARGB, REMAP_4 )
  532. #define CAP( x ) CPs3gcmTextureLayout::Format_t::kCap##x
  533. CPs3gcmTextureLayout::Format_t g_ps3texFormats[PS3_TEX_MAX_FORMAT_COUNT] =
  534. {
  535. // summ-name d3d-format
  536. // gcmRemap
  537. // gcmFormat
  538. // gcmPitchPer4X gcmFlags
  539. { GLMTEX_FMT_DESC("_D16") D3DFMT_D16,
  540. REMAP_ALL_DEFAULT,
  541. 8,
  542. CELL_GCM_TEXTURE_DEPTH16,
  543. 0 },
  544. { GLMTEX_FMT_DESC("_D24X8") D3DFMT_D24X8,
  545. REMAP_ALL_DEFAULT,
  546. 16,
  547. CELL_GCM_TEXTURE_DEPTH24_D8,
  548. 0 },
  549. { GLMTEX_FMT_DESC("_D24S8") D3DFMT_D24S8,
  550. REMAP_ALL_DEFAULT,
  551. 16,
  552. CELL_GCM_TEXTURE_DEPTH24_D8,
  553. 0 },
  554. { GLMTEX_FMT_DESC("_A8R8G8B8") D3DFMT_A8R8G8B8,
  555. REMAP_ALL_DEFAULT,
  556. 16,
  557. CELL_GCM_TEXTURE_A8R8G8B8,
  558. CAP(SRGB) },
  559. { GLMTEX_FMT_DESC("_X8R8G8B8") D3DFMT_X8R8G8B8,
  560. REMAP_ALL_DEFAULT,
  561. 16,
  562. CELL_GCM_TEXTURE_A8R8G8B8,
  563. CAP(SRGB) },
  564. { GLMTEX_FMT_DESC("_X1R5G5B5") D3DFMT_X1R5G5B5,
  565. CELL_GCM_REMAP_MODE_OIO( REMAPO(X), REMAP_ARGB, REMAP_13 ),
  566. 8,
  567. CELL_GCM_TEXTURE_R5G6B5,
  568. 0 },
  569. { GLMTEX_FMT_DESC("_A1R5G5B5") D3DFMT_A1R5G5B5,
  570. REMAP_ALL_DEFAULT_X,
  571. 8,
  572. CELL_GCM_TEXTURE_A1R5G5B5,
  573. 0 },
  574. { GLMTEX_FMT_DESC("_L8") D3DFMT_L8,
  575. CELL_GCM_REMAP_MODE_OIO( REMAPO(Y), REMAP_4X(CELL_GCM_TEXTURE_REMAP_FROM_B), REMAP_13 ),
  576. 4,
  577. CELL_GCM_TEXTURE_B8,
  578. 0 },
  579. { GLMTEX_FMT_DESC("_A8L8") D3DFMT_A8L8,
  580. CELL_GCM_REMAP_MODE_OIO( REMAPO(Y), REMAP_13X( CELL_GCM_TEXTURE_REMAP_FROM_G, CELL_GCM_TEXTURE_REMAP_FROM_B), REMAP_4 ),
  581. 8,
  582. CELL_GCM_TEXTURE_G8B8,
  583. 0 },
  584. { GLMTEX_FMT_DESC("_DXT1") D3DFMT_DXT1,
  585. CELL_GCM_REMAP_MODE_OIO( REMAPO(Y), REMAP_ARGB, REMAP_13 ),
  586. 8,
  587. CELL_GCM_TEXTURE_COMPRESSED_DXT1,
  588. CAP(SRGB) | CAP(4xBlocks) },
  589. { GLMTEX_FMT_DESC("_DXT3") D3DFMT_DXT3,
  590. REMAP_ALL_DEFAULT,
  591. 16,
  592. CELL_GCM_TEXTURE_COMPRESSED_DXT23,
  593. CAP(SRGB) | CAP(4xBlocks) },
  594. { GLMTEX_FMT_DESC("_DXT5") D3DFMT_DXT5,
  595. REMAP_ALL_DEFAULT,
  596. 16,
  597. CELL_GCM_TEXTURE_COMPRESSED_DXT45,
  598. CAP(SRGB) | CAP(4xBlocks) },
  599. { GLMTEX_FMT_DESC("_A16B16G16R16F") D3DFMT_A16B16G16R16F,
  600. REMAP_ALL_DEFAULT_X,
  601. 32,
  602. CELL_GCM_TEXTURE_W16_Z16_Y16_X16_FLOAT,
  603. 0 },
  604. { GLMTEX_FMT_DESC("_A16B16G16R16") D3DFMT_A16B16G16R16,
  605. REMAP_ALL_DEFAULT_X,
  606. 64,
  607. CELL_GCM_TEXTURE_W32_Z32_Y32_X32_FLOAT,
  608. 0 },
  609. { GLMTEX_FMT_DESC("_A32B32G32R32F") D3DFMT_A32B32G32R32F,
  610. REMAP_ALL_DEFAULT_X,
  611. 64,
  612. CELL_GCM_TEXTURE_W32_Z32_Y32_X32_FLOAT,
  613. 0 },
  614. { GLMTEX_FMT_DESC("_R8G8B8") D3DFMT_R8G8B8,
  615. CELL_GCM_REMAP_MODE_OIO( REMAPO(Y),
  616. REMAP4( CELL_GCM_TEXTURE_REMAP_FROM_B, CELL_GCM_TEXTURE_REMAP_FROM_A, CELL_GCM_TEXTURE_REMAP_FROM_R, CELL_GCM_TEXTURE_REMAP_FROM_G ),
  617. REMAP_13 ),
  618. 16,
  619. CELL_GCM_TEXTURE_A8R8G8B8,
  620. CAP(SRGB) },
  621. { GLMTEX_FMT_DESC("_A8") D3DFMT_A8,
  622. CELL_GCM_REMAP_MODE_OIO( REMAPO(Y),
  623. REMAP4( CELL_GCM_TEXTURE_REMAP_FROM_B, CELL_GCM_TEXTURE_REMAP_FROM_R, CELL_GCM_TEXTURE_REMAP_FROM_B, CELL_GCM_TEXTURE_REMAP_FROM_B ),
  624. REMAP_13X( CELL_GCM_TEXTURE_REMAP_REMAP, CELL_GCM_TEXTURE_REMAP_ZERO ) ),
  625. 4,
  626. CELL_GCM_TEXTURE_B8,
  627. 0 },
  628. { GLMTEX_FMT_DESC("_R5G6B5") D3DFMT_R5G6B5,
  629. CELL_GCM_REMAP_MODE_OIO( REMAPO(Y),
  630. REMAP4( CELL_GCM_TEXTURE_REMAP_FROM_B, CELL_GCM_TEXTURE_REMAP_FROM_A, CELL_GCM_TEXTURE_REMAP_FROM_R, CELL_GCM_TEXTURE_REMAP_FROM_G ),
  631. REMAP_13 ),
  632. 16,
  633. CELL_GCM_TEXTURE_A8R8G8B8,
  634. CAP(SRGB) },
  635. { GLMTEX_FMT_DESC("_Q8W8V8U8") D3DFMT_Q8W8V8U8,
  636. REMAP_ALL_DEFAULT,
  637. 16,
  638. CELL_GCM_TEXTURE_A8R8G8B8,
  639. CAP(SRGB) },
  640. };
  641. uint g_nPs3texFormatCount = PS3_TEX_CANONICAL_FORMAT_COUNT;
  642. #undef CAP
  643. #undef GLMTEX_FMT_DESC
  644. static bool Ps3texLayoutLessFunc( CPs3gcmTextureLayout::Key_t const &a, CPs3gcmTextureLayout::Key_t const &b )
  645. {
  646. return ( memcmp( &a, &b, sizeof( CPs3gcmTextureLayout::Key_t ) ) < 0 );
  647. }
  648. static CUtlMap< CPs3gcmTextureLayout::Key_t, CPs3gcmTextureLayout const * > s_ps3texLayouts( Ps3texLayoutLessFunc );
  649. CPs3gcmTextureLayout const * CPs3gcmTextureLayout::New( Key_t const &k )
  650. {
  651. // SPUGCM shared area must be initialized BEFORE anyone calls this function
  652. Assert( g_spuGcmShared.m_eaPs3texFormats == g_ps3texFormats );
  653. // look up 'key' in the map and see if it's a hit, if so, bump the refcount and return
  654. // if not, generate a completed layout based on the key, add to map, set refcount to 1, return that
  655. unsigned short index = s_ps3texLayouts.Find( k );
  656. if ( index != s_ps3texLayouts.InvalidIndex() )
  657. {
  658. CPs3gcmTextureLayout const *layout = s_ps3texLayouts[ index ];
  659. ++ layout->m_refCount;
  660. return layout;
  661. }
  662. // Need to generate complete information about the texture layout
  663. uint8 nMips = ( k.m_texFlags & kfMip ) ? k.m_nActualMipCount : 1;
  664. uint8 nFaces = ( k.m_texFlags & kfTypeCubeMap ) ? 6 : 1;
  665. uint32 nSlices = nMips * nFaces;
  666. // Allocate layout memory
  667. size_t numLayoutBytes = sizeof( CPs3gcmTextureLayout ) + nSlices * sizeof( Slice_t );
  668. CPs3gcmTextureLayout *layout = ( CPs3gcmTextureLayout * ) MemAlloc_AllocAligned( numLayoutBytes, 16 );
  669. memset( layout, 0, numLayoutBytes );
  670. memcpy( &layout->m_key, &k, sizeof( Key_t ) );
  671. layout->m_refCount = 1;
  672. // Find the format descriptor
  673. for ( int j = 0; j < PS3_TEX_CANONICAL_FORMAT_COUNT; ++ j )
  674. {
  675. if ( g_ps3texFormats[j].m_d3dFormat == k.m_texFormat )
  676. {
  677. layout->m_nFormat = j;
  678. break;
  679. }
  680. Assert( j != PS3_TEX_CANONICAL_FORMAT_COUNT - 1 );
  681. }
  682. layout->m_mipCount = nMips;
  683. //
  684. // Slices
  685. //
  686. bool bSwizzled = layout->IsSwizzled();
  687. size_t fmtPitch = layout->GetFormatPtr()->m_gcmPitchPer4X;
  688. size_t fmtPitchBlock = ( layout->GetFormatPtr()->m_gcmCaps & CPs3gcmTextureLayout::Format_t::kCap4xBlocks ) ? 16 : 4;
  689. size_t numDataBytes = 0;
  690. Slice_t *pSlice = &layout->m_slices[0];
  691. for ( int face = 0; face < nFaces; ++ face )
  692. {
  693. // For cubemaps every next face in swizzled addressing
  694. // must be aligned on 128-byte boundary
  695. if ( bSwizzled )
  696. {
  697. numDataBytes = ( numDataBytes + 127 ) & ~127;
  698. }
  699. for ( int mip = 0; mip < nMips; ++ mip, ++ pSlice )
  700. {
  701. for ( int j = 0; j < ARRAYSIZE( k.m_size ); ++ j )
  702. {
  703. pSlice->m_size[j] = k.m_size[j] >> mip;
  704. pSlice->m_size[j] = MAX( pSlice->m_size[j], 1 );
  705. }
  706. pSlice->m_storageOffset = numDataBytes;
  707. size_t numTexels;
  708. // For linear layout textures every mip row must be padded to the
  709. // width of the original highest level mip so that the pitch was
  710. // the same for every mip
  711. if ( bSwizzled )
  712. numTexels = ( pSlice->m_size[0] * pSlice->m_size[1] * pSlice->m_size[2] );
  713. else
  714. numTexels = ( k.m_size[0] * pSlice->m_size[1] * pSlice->m_size[2] );
  715. size_t numBytes = ( numTexels * fmtPitch ) / fmtPitchBlock;
  716. if ( layout->GetFormatPtr()->m_gcmCaps & CPs3gcmTextureLayout::Format_t::kCap4xBlocks )
  717. {
  718. // Ensure the size of the smallest mipmap levels of DXT1/3/5 textures (the 1x1 and 2x2 mips) is accurately computed.
  719. numBytes = MAX( numBytes, fmtPitch );
  720. }
  721. pSlice->m_storageSize = MAX( numBytes, 1 );
  722. numDataBytes += pSlice->m_storageSize;
  723. }
  724. }
  725. // Make the total size 128-byte aligned
  726. // Realistically it is required only for depth textures
  727. numDataBytes = ( numDataBytes + 127 ) & ~127;
  728. //
  729. // Tiled and ZCull memory adjustments
  730. //
  731. layout->m_gcmAllocType = kAllocPs3gcmTextureData;
  732. if ( layout->IsTiledMemory() )
  733. {
  734. if( g_nPs3texFormatCount >= PS3_TEX_MAX_FORMAT_COUNT )
  735. {
  736. Error("Modified ps3 format array overflow. Increase PS3_TEX_MAX_FORMAT_COUNT appropriately and recompile\n");
  737. }
  738. Format_t *pModifiedFormat = &g_ps3texFormats[g_nPs3texFormatCount];
  739. V_memcpy( pModifiedFormat, layout->GetFormatPtr(), sizeof( Format_t ) );
  740. layout->m_nFormat = g_nPs3texFormatCount;
  741. g_nPs3texFormatCount ++;
  742. if ( k.m_texFlags & kfTypeDepthStencil )
  743. {
  744. //
  745. // Tiled Zcull Surface
  746. //
  747. uint32 zcullSize[2] = { AlignValue( k.m_size[0], 64 ), AlignValue( k.m_size[1], 64 ) };
  748. uint32 nDepthPitch = cellGcmGetTiledPitchSize( zcullSize[0] * 4 );
  749. pModifiedFormat->m_gcmPitchPer4X = nDepthPitch;
  750. uint32 uDepthBufferSize32bpp = nDepthPitch * zcullSize[1];
  751. uDepthBufferSize32bpp = AlignValue( uDepthBufferSize32bpp, PS3GCMALLOCATIONALIGN( kAllocPs3gcmDepthBuffer ) );
  752. Assert( uDepthBufferSize32bpp >= numDataBytes );
  753. numDataBytes = uDepthBufferSize32bpp;
  754. layout->m_gcmAllocType = kAllocPs3gcmDepthBuffer;
  755. }
  756. else
  757. {
  758. //
  759. // Tiled Color Surface
  760. //
  761. uint32 nTiledPitch = cellGcmGetTiledPitchSize( k.m_size[0] * layout->GetFormatPtr()->m_gcmPitchPer4X / 4 );
  762. pModifiedFormat->m_gcmPitchPer4X = nTiledPitch;
  763. if ( k.m_size[0] == 512 && k.m_size[1] == 512 && k.m_size[2] == 1 )
  764. layout->m_gcmAllocType = kAllocPs3gcmColorBuffer512;
  765. else if ( k.m_size[0] == g_ps3gcmGlobalState.m_nRenderSize[0] && k.m_size[1] == g_ps3gcmGlobalState.m_nRenderSize[1] && k.m_size[2] == 1 )
  766. layout->m_gcmAllocType = kAllocPs3gcmColorBufferFB;
  767. else if ( k.m_size[0] == g_ps3gcmGlobalState.m_nRenderSize[0]/4 && k.m_size[1] == g_ps3gcmGlobalState.m_nRenderSize[1]/4 && k.m_size[2] == 1 )
  768. layout->m_gcmAllocType = kAllocPs3gcmColorBufferFBQ;
  769. else
  770. layout->m_gcmAllocType = kAllocPs3gcmColorBufferMisc;
  771. uint32 uRenderSize = nTiledPitch * AlignValue( k.m_size[1], 32 ); // 32-line vertical alignment required in local memory
  772. if ( layout->m_gcmAllocType == kAllocPs3gcmColorBufferMisc )
  773. uRenderSize = AlignValue( uRenderSize, PS3GCMALLOCATIONALIGN( kAllocPs3gcmColorBufferMisc ) );
  774. Assert( uRenderSize >= numDataBytes );
  775. numDataBytes = uRenderSize;
  776. }
  777. }
  778. layout->m_storageTotalSize = numDataBytes;
  779. //
  780. // Finished creating the layout information
  781. //
  782. #ifndef _CERT
  783. // generate summary
  784. // "target, format, +/- mips, base size"
  785. char scratch[1024];
  786. char *targetname = targetname = "2D ";
  787. if ( layout->IsVolumeTex() )
  788. targetname = "3D ";
  789. if ( layout->IsCubeMap() )
  790. targetname = "CUBE";
  791. sprintf( scratch, "[%s %s %dx%dx%d mips=%d slices=%d flags=%02X%s]",
  792. targetname,
  793. layout->GetFormatPtr()->m_formatSummary,
  794. layout->m_key.m_size[0], layout->m_key.m_size[1], layout->m_key.m_size[2],
  795. nMips,
  796. nSlices,
  797. layout->m_key.m_texFlags,
  798. (layout->m_key.m_texFlags & kfSrgbEnabled) ? " SRGB" : ""
  799. );
  800. layout->m_layoutSummary = strdup( scratch );
  801. #endif
  802. // then insert into map. disregard returned index.
  803. s_ps3texLayouts.Insert( k, layout );
  804. return layout;
  805. }
  806. void CPs3gcmTextureLayout::Release() const
  807. {
  808. -- m_refCount;
  809. // keep the layout in the map for easy access
  810. Assert( m_refCount >= 0 );
  811. }
  812. //////////////////////////////////////////////////////////////////////////
  813. //
  814. // Texture management
  815. //
  816. CPs3gcmTexture * CPs3gcmTexture::New( CPs3gcmTextureLayout::Key_t const &key )
  817. {
  818. //
  819. // Allocate a new layout for the texture
  820. //
  821. CPs3gcmTextureLayout const *pLayout = CPs3gcmTextureLayout::New( key );
  822. if ( !pLayout )
  823. {
  824. Debugger();
  825. return NULL;
  826. }
  827. CPs3gcmTexture *tex = (CPs3gcmTexture *)MemAlloc_AllocAligned( sizeof( CPs3gcmTexture ), 16 );
  828. memset( tex, 0, sizeof( CPs3gcmTexture ) ); // NOTE: This clears the CPs3gcmLocalMemoryBlock
  829. tex->m_layout = pLayout;
  830. CPs3gcmAllocationType_t uAllocationType = pLayout->m_gcmAllocType;
  831. if ( key.m_texFlags & CPs3gcmTextureLayout::kfNoD3DMemory )
  832. {
  833. if ( ( uAllocationType == kAllocPs3gcmDepthBuffer ) || ( uAllocationType == kAllocPs3gcmColorBufferMisc ) )
  834. {
  835. Assert( 0 );
  836. Warning( "ERROR: (CPs3gcmTexture::New) depth/colour buffers should not be marked with kfNoD3DMemory!\n" );
  837. }
  838. else
  839. {
  840. // Early-out, storage will be allocated later (via IDirect3DDevice9::AllocateTextureStorage)
  841. return tex;
  842. }
  843. }
  844. tex->Allocate();
  845. return tex;
  846. }
  847. void CPs3gcmTexture::Release()
  848. {
  849. // Wait for RSX to finish using the texture memory
  850. // and free it later
  851. if ( m_lmBlock.Size() )
  852. {
  853. m_lmBlock.Free();
  854. }
  855. m_layout->Release();
  856. MemAlloc_FreeAligned( this );
  857. }
  858. bool CPs3gcmTexture::Allocate()
  859. {
  860. if ( m_lmBlock.Size() )
  861. {
  862. // Already allocated!
  863. Assert( 0 );
  864. Warning( "ERROR: CPs3gcmTexture::Allocate called twice!\n" );
  865. return true;
  866. }
  867. CPs3gcmAllocationType_t uAllocationType = m_layout->m_gcmAllocType;
  868. const CPs3gcmTextureLayout::Key_t & key = m_layout->m_key;
  869. m_lmBlock.Alloc( uAllocationType, m_layout->m_storageTotalSize );
  870. if ( m_layout->IsTiledMemory() )
  871. {
  872. if ( uAllocationType == kAllocPs3gcmDepthBuffer )
  873. {
  874. bool bIs16BitDepth = ( m_layout->GetFormatPtr()->m_gcmFormat == CELL_GCM_TEXTURE_DEPTH16 ) || ( m_layout->m_nFormat == CELL_GCM_TEXTURE_DEPTH16_FLOAT );
  875. uint32 zcullSize[2] = { AlignValue( key.m_size[0], 64 ), AlignValue( key.m_size[1], 64 ) };
  876. uint32 uiZcullIndex = m_lmBlock.ZcullMemoryIndex();
  877. cellGcmBindZcull( uiZcullIndex,
  878. m_lmBlock.Offset(),
  879. zcullSize[0], zcullSize[1],
  880. m_lmBlock.ZcullMemoryStart(),
  881. bIs16BitDepth ? CELL_GCM_ZCULL_Z16 : CELL_GCM_ZCULL_Z24S8,
  882. CELL_GCM_SURFACE_CENTER_1,
  883. CELL_GCM_ZCULL_LESS,
  884. CELL_GCM_ZCULL_LONES,
  885. CELL_GCM_SCULL_SFUNC_ALWAYS,
  886. 0, 0 // sRef, sMask
  887. );
  888. uint32 uiTileIndex = m_lmBlock.TiledMemoryIndex();
  889. cellGcmSetTileInfo( uiTileIndex, CELL_GCM_LOCATION_LOCAL, m_lmBlock.Offset(),
  890. m_layout->m_storageTotalSize, m_layout->DefaultPitch(), bIs16BitDepth ? CELL_GCM_COMPMODE_DISABLED : CELL_GCM_COMPMODE_Z32_SEPSTENCIL_REGULAR,
  891. m_lmBlock.TiledMemoryTagAreaBase(), // The area base + size/0x10000 will be allocated as the tag area.
  892. 1 ); // Misc depth buffers on bank 1
  893. cellGcmBindTile( uiTileIndex );
  894. }
  895. else if ( uAllocationType == kAllocPs3gcmColorBufferMisc )
  896. {
  897. uint32 uiTileIndex = m_lmBlock.TiledMemoryIndex();
  898. cellGcmSetTileInfo( uiTileIndex, CELL_GCM_LOCATION_LOCAL, m_lmBlock.Offset(),
  899. m_layout->m_storageTotalSize, m_layout->DefaultPitch(), CELL_GCM_COMPMODE_DISABLED,
  900. m_lmBlock.TiledMemoryTagAreaBase(), // The area base + size/0x10000 will be allocated as the tag area.
  901. 1 ); // Tile misc color buffers on bank 1
  902. cellGcmBindTile( uiTileIndex );
  903. }
  904. }
  905. #ifdef _DEBUG
  906. memset( Data(), 0, m_layout->m_storageTotalSize ); // initialize texture data to BLACK in DEBUG
  907. #endif
  908. return true;
  909. }
  910. //////////////////////////////////////////////////////////////////////////
  911. //
  912. // Buffer management
  913. //
  914. CPs3gcmBuffer * CPs3gcmBuffer::New( uint32 uiSize, CPs3gcmAllocationType_t uType )
  915. {
  916. CPs3gcmBuffer * p = new CPs3gcmBuffer;
  917. p->m_lmBlock.Alloc( uType, uiSize );
  918. return p;
  919. }
  920. void CPs3gcmBuffer::Release()
  921. {
  922. // Wait for RSX to finish using the buffer memory
  923. // and free it later
  924. m_lmBlock.Free();
  925. delete this;
  926. }