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

//================ Copyright (c) Valve Corporation. All Rights Reserved. ===========================
//
// Gcm renderer state and util functions
//
//==================================================================================================
#ifndef SPU
#define CELL_GCM_MEMCPY memcpy // PPU SNC has no such intrinsic
#endif
#include "sys/memory.h"
#include "sysutil/sysutil_sysparam.h"
#include "cell/sysmodule.h"
#include "tier0/platform.h"
#include "tier0/dbg.h"
#include "tier1/utlbuffer.h"
#include "cell/gcm.h"
#include "gcmconfig.h"
#include "ps3gcmmemory.h"
#include "gcmstate.h"
#include "gcmlabels.h"
#include "gcmdrawstate.h"
#include "ps3/ps3_helpers.h"
#include <cell/gem.h> // PS3 move controller lib
#include "inputsystem/iinputsystem.h"
#include "memdbgon.h"
//--------------------------------------------------------------------------------------------------
// Golobals, GCM context, flip control init proto
//--------------------------------------------------------------------------------------------------
ALIGN128 CPs3gcmGlobalState g_ps3gcmGlobalState ALIGN128_POST;
ALIGN16 CellGcmContextData gGcmContext ALIGN16_POST;
CellGcmContextData* gpGcmContext;
CellGcmContextData gCallContext;
CellGcmContextData* gpCallContext = &gCallContext;
static void Gcm_InitFlipControl(void);
static volatile uint32_t *s_label_call_cmd_ring_seg; // pointer to the call cmd label
volatile uint32_t *g_label_fppatch_ring_seg; // Fp pacth label
//--------------------------------------------------------------------------------------------------
// Empty Ps
//--------------------------------------------------------------------------------------------------
uint8 g_dataShaderPsEmpty[] = {
0x00, 0x00, 0x1B, 0x5C, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0xB0, 0x00, 0x00, 0x00, 0x01
, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x80
, 0x00, 0x00, 0x04, 0x18, 0x00, 0x00, 0x0A, 0xC5, 0x00, 0x00, 0x10, 0x05, 0xFF, 0xFF, 0xFF, 0xFF
, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50
, 0x00, 0x00, 0x10, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00
, 0x43, 0x4F, 0x4C, 0x4F, 0x52, 0x00, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF
, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
, 0x1E, 0x7E, 0x7E, 0x00, 0xC8, 0x00, 0x1C, 0x9D, 0xC8, 0x00, 0x00, 0x01, 0xC8, 0x00, 0x00, 0x01
, 0x1E, 0x01, 0x01, 0x00, 0x28, 0x02, 0x1C, 0x9C, 0xC8, 0x00, 0x00, 0x01, 0xC8, 0x00, 0x00, 0x01
, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
//--------------------------------------------------------------------------------------------------
// Global GCM state class
//
// Global state, command buffers, RSX draw display buffers etc etc
//--------------------------------------------------------------------------------------------------
int32 CPs3gcmGlobalState::Init()
{
MEM_ALLOC_CREDIT_( "GCM INIT" );
Msg(">>>> Sizeof(CGcmDrawStateDma) %d \n", DRAWSTATE_SIZEOFDMA);
Msg(">>>> Sizeof(CGcmDrawState) %d \n", sizeof(CGcmDrawState));
// Create Raw SPU task for renderer acceleration
gSpuMgr.Init(1);
gSpuMgr.CreateSpuTask("rawspu_gcmdraw_spu.self", &m_spuHandle);
// Default to 60Hz
m_flipMode = 30;
// Video : display res, video buffer, gamma, RGB colour range
if( int nError= InitVideo() )
return nError;
// Alloc IO memory, Set address, size of main memory pool for RSX
CreateIoBuffers();
// Init GCM : Map IO memory, Create command buffers
if( int nError = InitGcm() )
return nError;
// Retrieve RSX local memory config
CellGcmConfig rsxConfig;
cellGcmGetConfiguration( &rsxConfig );
m_pLocalBaseAddress = rsxConfig.localAddress;
m_nLocalSize = rsxConfig.localSize;
cellGcmAddressToOffset( m_pLocalBaseAddress, &m_nLocalBaseOffset );
Assert( m_nLocalBaseOffset == 0 );
// Init local memory mgr
Ps3gcmLocalMemoryAllocator_Init();
// Create display buffers etc..
CreateRsxBuffers();
// Create Empty PS
m_pShaderPsEmpty = reinterpret_cast< CgBinaryProgram * >( g_dataShaderPsEmpty );
m_pShaderPsEmptyBuffer.Alloc( kAllocPs3GcmShader, m_pShaderPsEmpty->ucodeSize );
V_memcpy( m_pShaderPsEmptyBuffer.DataInLocalMemory(), ( (char*)m_pShaderPsEmpty ) + m_pShaderPsEmpty->ucode, m_pShaderPsEmpty->ucodeSize );
CgBinaryFragmentProgram *pCgFragmentProgram = ( CgBinaryFragmentProgram * )( uintp( m_pShaderPsEmpty ) + m_pShaderPsEmpty->program );
m_nPsEmptyAttributeInputMask = pCgFragmentProgram->attributeInputMask;
uint registerCount = pCgFragmentProgram->registerCount;
// NOTE: actual register count can be modified by specifying an artificial e.g. PS3REGCOUNT48 static combo to force it to 48
Assert( registerCount <= 48 );
if (registerCount < 2)
{
// register count must be [2, 48]
registerCount = 2;
}
uint8_t controlTxp = CELL_GCM_FALSE;
uint32 shCtrl0 = ( CELL_GCM_COMMAND_CAST( controlTxp ) << CELL_GCM_SHIFT_SET_SHADER_CONTROL_CONTROL_TXP )
& CELL_GCM_MASK_SET_SHADER_CONTROL_CONTROL_TXP;
shCtrl0 |= ( 1<<10 ) | ( registerCount << 24 );
shCtrl0 |= pCgFragmentProgram->depthReplace ? 0xE : 0x0;
shCtrl0 |= pCgFragmentProgram->outputFromH0 ? 0x00 : 0x40;
shCtrl0 |= pCgFragmentProgram->pixelKill ? 0x80 : 0x00;
m_nPsEmptyShaderControl0 = shCtrl0;
// Init glip control
m_fastFlip = 0;
Gcm_InitFlipControl();
// Address of draw states
m_eaDrawStates = uintp(gGcmDrawState);
// Give SPU program this class
gSpuMgr.WriteMailbox(&m_spuHandle, uintp(this));
return CELL_OK;
}
void CPs3gcmGlobalState::CreateIoBuffers()
{
m_nIoSize = GCM_IOSIZE;
if ((m_nIoSize & 0xFFFFF) != 0) // MB aligned
{
Error("No MB alignment %x\n\n", m_nIoSize);
}
// Try to allocate main memory that will be mapped to IO address space
// Actually mapped in in GcmInit, once gcm is going
sys_addr_t pIoAddress = NULL;
int nError = sys_memory_allocate( m_nIoSize, SYS_MEMORY_PAGE_SIZE_1M, &pIoAddress );
if ( CELL_OK != nError )
{
Error( "sys_memory_allocate failed to allocate %d bytes (err: %d)\n", m_nIoSize, nError );
}
m_pIoAddress = (void *)pIoAddress;
Msg( "======== GCM IO memory allocated @0x%p size = %d MB ========\n", m_pIoAddress, m_nIoSize / 1024 / 1024 );
// Call command buffer
m_pCallCmdBuffer = (void*)(uintp(pIoAddress) + GCM_DEFCMDBUFFSIZE);
// RSX main memory pool buffer
m_nRsxMainMemoryPoolBufferSize = GCM_MAINPOOLSIZE;
m_pRsxMainMemoryPoolBuffer = (void*)(uintp(pIoAddress) + GCM_DEFCMDBUFFSIZE + GCM_CALLCMDBUFFSIZE);
// Patch buffers
m_pPatchBuff = (uint8*)m_pRsxMainMemoryPoolBuffer + GCM_MAINPOOLSIZE;
}
int CPs3gcmGlobalState::InitGcm()
{
int32 result = cellGcmInit( GCM_DEFCMDBUFFSIZE, m_nIoSize, m_pIoAddress );
if ( result < CELL_OK )
return result;
gGcmContext = *gCellGcmCurrentContext;
gpGcmContext = &gGcmContext;
gpGcmContext->callback = CmdBufferFull;
// Set the flip mode etc...
// Get the offset delta
cellGcmAddressToOffset( m_pIoAddress, &m_nIoOffsetDelta );
m_nIoOffsetDelta -= uintp( m_pIoAddress );
// Setup call cmd buffer
m_nCallCmdBufferoffset = uintp(m_pCallCmdBuffer) + m_nIoOffsetDelta;
m_nCallWritePos = 0;
m_nCallReadSegment = 0;
s_label_call_cmd_ring_seg = cellGcmGetLabelAddress(GCM_LABEL_CALL_CMD_RING_SEG);
*s_label_call_cmd_ring_seg = 0;
// Setup Patch Buffers
m_nPatchIdx = 0;
m_nPatchReadSeg = 0;
g_label_fppatch_ring_seg = cellGcmGetLabelAddress(GCM_LABEL_FPPATCH_RING_SEG);
*g_label_fppatch_ring_seg = 0;
return CELL_OK;
}
int CPs3gcmGlobalState::InitVideo()
{
//////////////////////////////////////////////////////////////////////////
//
// Initialize m_display
//
CellVideoOutState videoOutState;
int result = cellVideoOutGetState( CELL_VIDEO_OUT_PRIMARY, 0, &videoOutState);
if ( result < CELL_OK )
return result;
CellVideoOutResolution resolution;
result = cellVideoOutGetResolution( videoOutState.displayMode.resolutionId, &resolution );
if ( result < CELL_OK )
return result;
// Always output scanout in system m_display resolution
m_nRenderSize[0] = resolution.width;
m_nRenderSize[1] = resolution.height;
// Handle special case: 1080p will be upsampled from 720p
if ( resolution.height >= 720 && CommandLine()->FindParm( "-480p" ) )
{
m_nRenderSize[0] = 640;
m_nRenderSize[1] = 480;
videoOutState.displayMode.resolutionId = CELL_VIDEO_OUT_RESOLUTION_480;
}
else if ( resolution.height >= 1080 && !CommandLine()->FindParm( "-1080p" ) )
{
m_nRenderSize[0] = 1280;
m_nRenderSize[1] = 720;
videoOutState.displayMode.resolutionId = CELL_VIDEO_OUT_RESOLUTION_720;
}
//////////////////////////////////////////////////////////////////////////
//
// Set video output
//
CellVideoOutConfiguration videocfg;
memset( &videocfg, 0, sizeof(videocfg) );
videocfg.resolutionId = videoOutState.displayMode.resolutionId;
videocfg.format = CELL_VIDEO_OUT_BUFFER_COLOR_FORMAT_X8R8G8B8;
videocfg.pitch = cellGcmGetTiledPitchSize( m_nRenderSize[0] * 4 );
m_nSurfaceRenderPitch = videocfg.pitch;
// Configure video output
result = cellVideoOutConfigure( CELL_VIDEO_OUT_PRIMARY, &videocfg, NULL, 0 );
if ( result < CELL_OK )
return result;
// Get the new video output
result = cellVideoOutGetState( CELL_VIDEO_OUT_PRIMARY, 0, &videoOutState );
if ( result < CELL_OK )
return result;
m_flRenderAspect = ( videoOutState.displayMode.aspect == CELL_VIDEO_OUT_ASPECT_4_3 ) ? ( 4.0f/3.0f ) : ( 16.0f / 9.0f );
// Set the gamma to deal with TV's having a darker gamma than computer monitors
result = cellSysmoduleLoadModule( CELL_SYSMODULE_AVCONF_EXT );
if ( result == CELL_OK )
{
cellVideoOutSetGamma( CELL_VIDEO_OUT_PRIMARY, 2.2f / 2.5f );
}
else
{
Warning( "***** ERROR calling cellSysmoduleLoadModule( CELL_SYSMODULE_AVCONF_EXT )! Gamma not set!\n" );
return result;
}
// Output video color settings
CellVideoOutDeviceInfo info;
cellVideoOutGetDeviceInfo( CELL_VIDEO_OUT_PRIMARY, 0, &info );
if ( info.rgbOutputRange == CELL_VIDEO_OUT_RGB_OUTPUT_RANGE_LIMITED )
{
DevMsg( "***** Video Out - Limited Range (16-235) - Gamma=%d *****\n", info.colorInfo.gamma );
}
else
{
DevMsg( "***** Video Out - Full Range (0-255) - Gamma=%d *****\n", info.colorInfo.gamma );
}
return CELL_OK;
}
void CPs3gcmGlobalState::CreateRsxBuffers()
{
//////////////////////////////////////////////////////////////////////////
//
// Create automatic display objects
//
if( m_nSurfaceRenderPitch != cellGcmGetTiledPitchSize( m_nRenderSize[0] * 4 ) )
{
Error("Pre-computed surface render pitch %u != %u = cellGcmGetTiledPitchSize( %u * 4 ) ", m_nSurfaceRenderPitch, cellGcmGetTiledPitchSize( m_nRenderSize[0] * 4 ), m_nRenderSize[0] );
}
m_display.surfaceFlipIdx = 0;
// Color buffers
for ( int k = 0; k < ARRAYSIZE( m_display.surfaceColor ); ++ k )
{
uint32 nRenderSize32bpp = GetRenderSurfaceBytes(); // 32-line vertical alignment required in local memory
m_display.surfaceColor[k].Alloc( kAllocPs3gcmColorBufferFB, nRenderSize32bpp );
cellGcmSetDisplayBuffer( k, m_display.surfaceColor[k].Offset(), m_nSurfaceRenderPitch, m_nRenderSize[0], m_nRenderSize[1] );
}
// Depth buffer
{
uint32 zcullSize[2] = { AlignValue( m_nRenderSize[0], 64 ), AlignValue( m_nRenderSize[1], 64 ) };
uint32 nDepthPitch = cellGcmGetTiledPitchSize( zcullSize[0] * 4 );
uint32 uDepthBufferSize32bpp = nDepthPitch * zcullSize[1];
uDepthBufferSize32bpp = AlignValue( uDepthBufferSize32bpp, PS3GCMALLOCATIONALIGN( kAllocPs3gcmDepthBuffer ) );
m_display.surfaceDepth.Alloc( kAllocPs3gcmDepthBuffer, uDepthBufferSize32bpp );
uint32 uiZcullIndex = m_display.surfaceDepth.ZcullMemoryIndex();
cellGcmBindZcull( uiZcullIndex,
m_display.surfaceDepth.Offset(),
zcullSize[0], zcullSize[1],
m_display.surfaceDepth.ZcullMemoryStart(),
CELL_GCM_ZCULL_Z24S8,
CELL_GCM_SURFACE_CENTER_1,
CELL_GCM_ZCULL_LESS,
CELL_GCM_ZCULL_LONES,
CELL_GCM_SCULL_SFUNC_ALWAYS,
0, 0 // sRef, sMask
);
uint32 uiTileIndex = m_display.surfaceDepth.TiledMemoryIndex();
cellGcmSetTileInfo( uiTileIndex, CELL_GCM_LOCATION_LOCAL, m_display.surfaceDepth.Offset(),
uDepthBufferSize32bpp, m_nSurfaceRenderPitch, CELL_GCM_COMPMODE_Z32_SEPSTENCIL_REGULAR,
m_display.surfaceDepth.TiledMemoryTagAreaBase(), // The area base + size/0x10000 will be allocated as the tag area.
3 ); // Default depth buffer on bank 3
cellGcmBindTile( uiTileIndex );
}
}
void CPs3gcmGlobalState::Shutdown()
{
gpGcmDrawState->EndFrame();
gpGcmDrawState->CmdBufferFinish();
cellGcmSetFlipHandler(NULL);
cellGcmSetVBlankHandler(NULL);
cellSysmoduleUnloadModule( CELL_SYSMODULE_AVCONF_EXT );
}
//--------------------------------------------------------------------------------------------------
// DawPrimUp code...
//--------------------------------------------------------------------------------------------------
uint32 CPs3gcmGlobalState::DrawPrimitiveUP(D3DPRIMITIVETYPE nPrimitiveType,UINT nPrimitiveCount,
CONST void *pVertexStreamZeroData, UINT nVertexStreamZeroStride )
{
// First Determine size required for this call
uint32 size = 0;
uint32 nIndexCount = GetGcmCount( nPrimitiveType, nPrimitiveCount );
uint32 nDataWords = ( nVertexStreamZeroStride * nIndexCount + 3 ) / sizeof( uint32 );
size = cellGcmSetWriteTextureLabelMeasureSize(size, GCM_LABEL_CALL_CMD_RING_SEG, 0 );
size = cellGcmSetInvalidateVertexCacheMeasureSize(size);
size = cellGcmSetDrawInlineArrayMeasureSize(size, GetGcmMode( nPrimitiveType ), nDataWords, pVertexStreamZeroData );
size = cellGcmSetReturnCommandMeasureSize(size);
size *=4;
// Check there is no space in the current segment
uint32 endPos, nextSeg, readSeg, writeSeg;
endPos = m_nCallWritePos + size;
writeSeg = m_nCallWritePos/GCM_CALLCMDSEGSIZE;
if ((endPos/GCM_CALLCMDSEGSIZE) != writeSeg)
{
// Move to the next segment
uint32 nextSeg = (writeSeg + 1) % (GCM_CALLCMDBUFFSIZE / GCM_CALLCMDSEGSIZE);
// Wait for RSX to not be in this segment
readSeg = m_nCallReadSegment;
if(nextSeg == readSeg) readSeg = *s_label_call_cmd_ring_seg;
gpGcmDrawState->CmdBufferFlush();
uint32 spins = 0;
while(nextSeg == readSeg)
{
spins++;
sys_timer_usleep(60);
readSeg = *s_label_call_cmd_ring_seg;
}
//if (spins > 1) Msg("Spins %d\n", spins);
// Move to next segmend abnd record new readSeg
m_nCallWritePos = (nextSeg * GCM_CALLCMDSEGSIZE);
writeSeg = nextSeg;
m_nCallReadSegment = readSeg;
// Msg("new Segment 0x%x\n", m_nCallWritePos);
}
uint32 ret = m_nCallWritePos + uintp(m_pCallCmdBuffer);
// Write Data
// Setup a context to do so
CellGcmContextData context;
context.begin = (uint32*)m_pCallCmdBuffer;
context.current = (uint32*)((uint8*)m_pCallCmdBuffer + m_nCallWritePos);
context.end = (uint32*)((uint8*)m_pCallCmdBuffer + GCM_CALLCMDBUFFSIZE);
context.callback = 0;
cellGcmSetWriteTextureLabelUnsafeInline(&context, GCM_LABEL_CALL_CMD_RING_SEG, writeSeg );
cellGcmSetInvalidateVertexCacheUnsafeInline(&context);
cellGcmSetDrawInlineArrayUnsafeInline(&context, GetGcmMode( nPrimitiveType ), nDataWords, pVertexStreamZeroData );
cellGcmSetReturnCommandUnsafeInline(&context);
// Update pointers
m_nCallWritePos += size;
return ret;
}
//--------------------------------------------------------------------------------------------------
// Command Buffer callback
//--------------------------------------------------------------------------------------------------
#define SEGSIZE 0x40000
#define SEGMASK 0x3FFFF
int32 CPs3gcmGlobalState::CmdBufferFull(struct CellGcmContextData * pGcmContext, uint32_t size)
{
// move to next SEGSIZE, and then wrap to start
// Determine where the next buffer will be
uint32 nIoAddress = (uint32)g_ps3gcmGlobalState.m_pIoAddress;
uint32 nextBufferStart = ((uint32)pGcmContext->begin + SEGSIZE) & (~SEGMASK);
nextBufferStart -= nIoAddress;
nextBufferStart &= (GCM_DEFCMDBUFFSIZE-1);
nextBufferStart = nextBufferStart ? (nextBufferStart + nIoAddress) : (SEGSIZE + nIoAddress);
// Flush RSX to this point
cellGcmFlushUnsafeInline(pGcmContext);
// put jump command to beginning of next buffer
uint32 nextBufferOffset = nextBufferStart - nIoAddress;
uint32 nextBufferEndOffset = ((nextBufferOffset + SEGSIZE) & (~SEGMASK)) - 4;
cellGcmSetJumpCommandUnsafeInline(pGcmContext, nextBufferStart - nIoAddress );
// get put/get/ref register address
volatile CellGcmControl* control = cellGcmGetControlRegister();
int count = 500000;
// wait for RSX to finish all commands in next buffer (it's a ring buffer)
volatile uint32_t get = (volatile uint32_t)control->get;
while( (get < 0x1000 ) || ( (get >= nextBufferOffset) && (get < nextBufferEndOffset) ) )
{
sys_timer_usleep( 30 );
get = (volatile uint32_t)control->get;
// count--;
// if (count < 1)
// {
// Msg("\n*****>>>> CmdBufferFull : get 0x%x : nextBufferOffset 0x%x : nextBufferEndOffset 0x%x\n", get, nextBufferOffset, nextBufferEndOffset );
// count = 1;
// }
}
// Set Command buffer context struct
pGcmContext->begin = (uint32*)nextBufferStart;
pGcmContext->end = (uint32*)(nextBufferEndOffset + nIoAddress);
pGcmContext->current = (uint32*)nextBufferStart;
return CELL_OK;
}
//--------------------------------------------------------------------------------------------------
// Flip Control
//
// Summary :
//
// Label used to cap the framerate. ie label to ensure flips no faster than 1 (60hz) or 2 (30Hz) vblanks.
// PPU blocks if previous flip not complete, so can't run too far ahead
// vblanks and flips noted by callbacks
//--------------------------------------------------------------------------------------------------
enum {
LABEL_FLIP_CONTROL_READY=1, // when label-before-flip is released
LABEL_FLIP_CONTROL_WAIT, // when label-before-flip is not released
/*
label_flip_control:
LABEL_FLIP_CONTROL_WAIT
=> (when releasing flip by ppu) => LABEL_FLIP_CONTROL_READY,
=> (when flip is finished by rsx) => LABEL_FLIP_CONTROL_WAIT,
*/
FLIP_STATE_V1=1,
FLIP_STATE_FLIP_RELEASED,
FLIP_STATE_FLIPPED,
/*
flip_status sequence (30fps or slower):
FLIP_STATE_FLIPPED
(at vblank callback) => FLIP_STATE_V1
(at vblank callback) =<release flip>=> FLIP_STATE_FLIP_RELEASED
(at flip callback) => FLIP_STATE_FLIPPED
*/
/*
flip_status sequence (60fps or slower):
FLIP_STATE_FLIPPED
(at vblank callback) =<release flip>=> FLIP_STATE_FLIP_RELEASED
(at flip callback) => FLIP_STATE_FLIPPED
*/
};
static volatile uint32_t *s_label_flip_control; // pointer to the flip control label
static int s_flip_status=FLIP_STATE_FLIPPED; // status variable to control flip
//--------------------------------------------------------------------------------------------------
static bool Gcm_ReleaseFlip(void)
{
if (*s_label_flip_control==LABEL_FLIP_CONTROL_READY) {
/* just in case rsx is running very slow somehow */
/* and flip_control label is not updated even after the real flip */
return false;
}
*s_label_flip_control=LABEL_FLIP_CONTROL_READY;
return true;
}
void updateCursorPosition(const int pixelX, const int pixelY)
{
cellGcmSetCursorPosition(pixelX, pixelY);
int32_t result = cellGcmUpdateCursor();
if( result == CELL_GCM_ERROR_FAILURE)
{
// [dkorus] this case happens until we initialize the cursor
//Msg(" hardware cursor error: cellGcmInitCursor() has not been called\n");
}
else if( result == CELL_GCM_ERROR_INVALID_VALUE )
{
Msg(" hardware cursor error: cursor bitmap is not correctly set\n");
}
}
void enableCursor()
{
if (cellGcmSetCursorEnable() != CELL_OK )
{
Msg( "Hardware Cursor Error: trouble with enable\n" );
}
if ( cellGcmUpdateCursor() != CELL_OK )
{
Msg( "Hardware Cursor Error: trouble with update\n" );
}
}
static void Gcm_VblankCallbackFunction(const uint32_t head)
{
// unused arg
(void)head;
int pixelX, pixelY;
if ( g_pInputSystem )
{
bool cursorEnabled = g_pInputSystem->GetPS3CursorPos( pixelX, pixelY );
if( cursorEnabled )
{
updateCursorPosition(pixelX,pixelY);
}
}
switch (s_flip_status){
case FLIP_STATE_FLIPPED:
if (g_ps3gcmGlobalState.m_flipMode == 30){
s_flip_status=FLIP_STATE_V1;
} else if (g_ps3gcmGlobalState.m_flipMode == 60){
if (Gcm_ReleaseFlip()){
s_flip_status=FLIP_STATE_FLIP_RELEASED;
}
}
break;
case FLIP_STATE_V1:
if (Gcm_ReleaseFlip()){
s_flip_status=FLIP_STATE_FLIP_RELEASED;
}
break;
case FLIP_STATE_FLIP_RELEASED:
break;
default:
assert(0);
}
}
static void Gcm_FlipCallbackFunction(const uint32_t head)
{
(void)head;
switch (s_flip_status){
case FLIP_STATE_FLIP_RELEASED:
s_flip_status=FLIP_STATE_FLIPPED;
break;
default:
break;
}
}
// initialize flip control state machine
static void Gcm_InitFlipControl(void)
{
cellGcmSetFlipMode( CELL_GCM_DISPLAY_HSYNC );
g_ps3gcmGlobalState.m_frameNo = 0;
g_ps3gcmGlobalState.m_finishIdx = 0;
s_label_flip_control=cellGcmGetLabelAddress(GCM_LABEL_FLIP_CONTROL);
*s_label_flip_control=LABEL_FLIP_CONTROL_WAIT;
cellGcmSetFlipHandler(Gcm_FlipCallbackFunction);
cellGcmSetVBlankHandler(Gcm_VblankCallbackFunction);
}
//--------------------------------------------------------------------------------------------------
// Beginscene, endscene and flip
//--------------------------------------------------------------------------------------------------
uint32 gCmdBufferHighWater = 0;
uint32 gCmdBufferStart = 0;
void CPs3gcmGlobalState::BeginScene()
{
gCmdBufferStart = (uint32)gpGcmContext->current;
gpGcmDrawState->BeginScene();
}
void CPs3gcmGlobalState::EndScene()
{
if ( (uint32)gpGcmContext->current > gCmdBufferStart )
{
uint32 bytes = (uint32)gpGcmContext->current - gCmdBufferStart;
if (bytes > gCmdBufferHighWater ) gCmdBufferHighWater = bytes;
}
gpGcmDrawState->EndScene();
}
float g_fliptime = 0;
void CPs3gcmGlobalState::SetFastFlip(bool onoff)
{
m_fastFlip = onoff;
g_fliptime = Plat_FloatTime();
}
extern void OnFrameTimestampAvailableRsx( float ms );
void CPs3gcmGlobalState::Flip()
{
cellSysutilCheckCallback();
if(m_fastFlip)
{
Gcm_ReleaseFlip();
float time = Plat_FloatTime();
if ( (time - g_fliptime) > 0.05) goto fullflip;
// Just end the frame, no point in flipping here...
gpGcmDrawState->EndFrame();
GCM_FUNC( cellGcmFlush );
goto newframe;
}
fullflip:
int idx, startIdx, endIdx;
//--------------------------------------------------------------------------------------------------
// Ensure any buffered state, copies etc... goes to GPU
//--------------------------------------------------------------------------------------------------
gpGcmDrawState->EndFrame();
//--------------------------------------------------------------------------------------------------
// Wait for previous frame Flip
//--------------------------------------------------------------------------------------------------
while (cellGcmGetFlipStatus()!=0){
g_pGcmSharedData->CheckForAudioRequest();
g_pGcmSharedData->CheckForServerRequest();
sys_timer_usleep(300);
}
// Insert end of gpu timestamp
idx = m_frameNo&1;
endIdx = GCM_REPORT_TIMESTAMP_FRAME_FIRST + (idx*2) + 1;
GCM_FUNC( cellGcmSetTimeStamp, endIdx );
//--------------------------------------------------------------------------------------------------
// If requested, lets defrag VRAM
//--------------------------------------------------------------------------------------------------
if (g_pGcmSharedData->m_bDeFrag)
{
g_pGcmSharedData->m_bDeFrag = 0;
extern void Ps3gcmLocalMemoryAllocator_CompactWithReason( char const *szReason );
Ps3gcmLocalMemoryAllocator_CompactWithReason( "End of Round" );
}
//--------------------------------------------------------------------------------------------------
// Get Timestamps
//--------------------------------------------------------------------------------------------------
if (m_frameNo)
{
idx = ((m_frameNo-1) & 1);
startIdx = GCM_REPORT_TIMESTAMP_FRAME_FIRST + (idx*2);
endIdx = startIdx+1;
uint64 uiStartTimestamp = cellGcmGetTimeStamp( startIdx );
uint64 uiEndTimestamp = cellGcmGetTimeStamp( endIdx );
uint64 uiRsxTimeInNanoSeconds = uiEndTimestamp - uiStartTimestamp;
OnFrameTimestampAvailableRsx( uiRsxTimeInNanoSeconds / 1000000.0f );
}
//--------------------------------------------------------------------------------------------------
// Insert new flip command and flush gpu
//--------------------------------------------------------------------------------------------------
// reset FlipStatus = 1
cellGcmResetFlipStatus();
// queue Flip command
GCM_FUNC( cellGcmSetFlipWithWaitLabel, m_display.surfaceFlipIdx, GCM_LABEL_FLIP_CONTROL, LABEL_FLIP_CONTROL_READY);
m_display.Flip();
GCM_FUNC( cellGcmSetWriteCommandLabel, GCM_LABEL_FLIP_CONTROL, LABEL_FLIP_CONTROL_WAIT);
GCM_FUNC( cellGcmSetWaitFlip );
GCM_FUNC( cellGcmFlush );
extern void Ps3gcmLocalMemoryAllocator_Reclaim();
Ps3gcmLocalMemoryAllocator_Reclaim();
//--------------------------------------------------------------------------------------------------
// Start a new frame
//--------------------------------------------------------------------------------------------------
newframe:
m_frameNo ++;
// Insert start of gpu timestamp
idx = m_frameNo&1;
startIdx = GCM_REPORT_TIMESTAMP_FRAME_FIRST + (idx*2);
GCM_FUNC( cellGcmSetTimeStamp, startIdx );
// Put RSX into known state for start of frame
gpGcmDrawState->ResetRsxState();
// Moved from DX present()
GCM_FUNC( cellGcmSetInvalidateVertexCache );
}
//--------------------------------------------------------------------------------------------------
// Buffer management
//--------------------------------------------------------------------------------------------------
CPs3gcmBuffer * CPs3gcmBuffer::New( uint32 uiSize, CPs3gcmAllocationType_t uType )
{
CPs3gcmBuffer * p = new CPs3gcmBuffer;
p->m_lmBlock.Alloc( uType, uiSize );
return p;
}
void CPs3gcmBuffer::Release()
{
// Wait for RSX to finish using the buffer memory
// and free it later
m_lmBlock.Free();
delete this;
}