|
|
//================ 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; }
|