initial
This commit is contained in:
18
common/ps3/job_notify.h
Normal file
18
common/ps3/job_notify.h
Normal file
@@ -0,0 +1,18 @@
|
||||
//========== Copyright © Valve Corporation, All rights reserved. ========
|
||||
#ifndef JOB_NOTIFY_HDR
|
||||
#define JOB_NOTIFY_HDR
|
||||
|
||||
#include "ps3/spu_job_shared.h"
|
||||
|
||||
namespace job_notify
|
||||
{
|
||||
struct ALIGN16 NotifyArea_t
|
||||
{
|
||||
uint32 m_nCopyTo;
|
||||
uint32 m_nCopyFrom;
|
||||
uint32 m_nSpuId;
|
||||
}ALIGN16_POST;
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
10
common/ps3/prx.cpp
Normal file
10
common/ps3/prx.cpp
Normal file
@@ -0,0 +1,10 @@
|
||||
#include "dbg.h"
|
||||
#include "tier1/interface.h"
|
||||
#include "ps3/ps3_helpers.h"
|
||||
|
||||
#ifndef DLLNAME
|
||||
#error DLLNAME is not defined
|
||||
#define DLLNAME unknownprxmodule
|
||||
#endif
|
||||
|
||||
PS3_PRX_APPSYSTEM_MODULE( DLLNAME )
|
||||
11
common/ps3/ps3_assert.h
Normal file
11
common/ps3/ps3_assert.h
Normal file
@@ -0,0 +1,11 @@
|
||||
// PS3 Assert : As of SDK 084, the PS3 assert found in assert.h will simply break execution
|
||||
// by calling __abort: this will exit the application instead of breaking
|
||||
// execution in the debugger.
|
||||
|
||||
#if defined(_PS3) && defined(_DEBUG)
|
||||
#ifdef assert
|
||||
#undef assert
|
||||
#endif
|
||||
#define assert(v)
|
||||
//if(!(v)) { *(int*)0x1 = 0; }
|
||||
#endif
|
||||
17
common/ps3/ps3_changelistver.h
Normal file
17
common/ps3/ps3_changelistver.h
Normal file
@@ -0,0 +1,17 @@
|
||||
// IMAGEBUILDER SHOULD MAKE A LINE LIKE THIS WITH THE CHANGELIST NUMBER #DEFINED IN:
|
||||
// IT'S OKAY IF IT BLOWS AWAY THE REST OF THIS FILE
|
||||
// ONLY THIS ONE #define IS NECESSARY:
|
||||
|
||||
// #define APPCHANGELISTVERSION 936857
|
||||
|
||||
|
||||
|
||||
|
||||
// IMAGEBUILDER SHOULD NOT EMIT THE FOLLOWING LINES
|
||||
// THEY INDICATE THAT THIS IS *NOT* AN AUTOBUILT IMAGE
|
||||
// AND SHOULD BE ABSENT FROM THE AUTOBUILDER'S LOCAL
|
||||
// VERSION OF THIS .H
|
||||
|
||||
|
||||
#define PS3CLVERMAJOR 0
|
||||
#define PS3CLVERMINOR 1
|
||||
116
common/ps3/ps3_console.h
Normal file
116
common/ps3/ps3_console.h
Normal file
@@ -0,0 +1,116 @@
|
||||
#ifndef PS3_CONSOLE_H
|
||||
#define PS3_CONSOLE_H
|
||||
|
||||
#include <cell/cell_fs.h>
|
||||
#include "ps3_platform.h"
|
||||
#include <sysutil/sysutil_sysconf.h>
|
||||
#include "ps3/ps3_vxconsole.h"
|
||||
#include "ps3/ps3_core.h"
|
||||
#include "tier0/dbg.h"
|
||||
|
||||
#if 0
|
||||
//-- The following, subject to being moved somewhere more sensible - DL
|
||||
#define PS3_SYSUTIL_CALLBACK_SLOT 0
|
||||
#define SOUND_SYSUTIL_CALLBACK_SLOT 1
|
||||
|
||||
bool PS3_RegisterSysUtilCallback( void );
|
||||
bool PS3_RegisterDiscChangeCallback( void );
|
||||
void PS3_UnRegisterSysUtilCallback( void );
|
||||
void PS3_UnRegisterDiscChangeCallback( void );
|
||||
void PS3_CheckSysUtilCallback( void );
|
||||
|
||||
int PS3_OpenSystemConfigurationDialog(CellSysconfType iConfType,CellSysconfCallback pCallBack, void * pUserData );
|
||||
void PS3_CloseSystemConfigurationDialog();
|
||||
void PS3_CleanSystemConfigurationDialog();
|
||||
|
||||
//--
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
//void PS3_SendRemoteCommand( const char* dbgCommand, bool bAsync );
|
||||
bool PS3_DebugString( unsigned int color, const char* format, ... );
|
||||
bool PS3_IsConsoleConnected();
|
||||
void PS3_InitConsoleMonitor( bool bWaitForConnect = false );
|
||||
int XBX_rAddCommands(int numCommands, const char* commands[], const char* help[]);
|
||||
|
||||
//updates the status of the console connection and handles new messages
|
||||
void PS3_UpdateConsoleMonitor();
|
||||
|
||||
|
||||
//language settings
|
||||
const char* PS3_GetLanguageString( void );
|
||||
bool PS3_IsLocalized( void );
|
||||
*/
|
||||
|
||||
// for integration with vxconsole profile bars:
|
||||
#define XBX_MAX_PROFILE_COUNTERS 64
|
||||
#define XMAKECOLOR( r, g, b ) ((unsigned int)(((unsigned char)(r)|((unsigned int)((unsigned char)(g))<<8))|(((unsigned int)(unsigned char)(b))<<16)))
|
||||
|
||||
|
||||
|
||||
class IPS3Console
|
||||
{
|
||||
public:
|
||||
// // // X360 console interface
|
||||
virtual void SendRemoteCommand( const char *dbgCommand, bool bAsync ) = 0;
|
||||
virtual void SendPrefixedDECIMessage( const char *prefix, const char *message, bool async ) = 0;
|
||||
virtual void DebugString( unsigned int color, const char *format, ... ) = 0;
|
||||
virtual bool IsConsoleConnected() = 0;
|
||||
virtual void InitConsoleMonitor( bool bWaitForConnect = false ) = 0;
|
||||
virtual void DisconnectConsoleMonitor() = 0;
|
||||
virtual void FlushDebugOutput() = 0;
|
||||
virtual bool GetXboxName( char *, unsigned * ) = 0;
|
||||
virtual void CrashDump( bool ) = 0;
|
||||
virtual void CrashDumpFullHeap( bool ) = 0;
|
||||
virtual void DumpDllInfo( const char *pBasePath ) = 0;
|
||||
// virtual void OutputDebugString( const char * ) = 0;
|
||||
virtual bool IsDebuggerPresent() = 0;
|
||||
|
||||
virtual int SetProfileAttributes( const char *pProfileName, int numCounters, const char *names[], COLORREF colors[] ) = 0;
|
||||
virtual void SetProfileData( const char *pProfileName, int numCounters, unsigned int *counters ) = 0;
|
||||
virtual int MemDump( const char *pDumpFileName ) = 0;
|
||||
virtual int TimeStampLog( float time, const char *pString ) = 0;
|
||||
virtual int MaterialList( int nMaterials, const xMaterialList_t *pXMaterialList ) = 0;
|
||||
virtual int TextureList( int nTextures, const xTextureList_t *pXTextureList ) = 0;
|
||||
virtual int SoundList( int nSounds, const xSoundList_t *pXSoundList ) = 0;
|
||||
virtual int MapInfo( const xMapInfo_t *pXMapInfo ) = 0;
|
||||
virtual int AddCommands( int numCommands, const char *commands[], const char* help[] ) = 0;
|
||||
virtual int ModelList( int nModels, const xModelList_t *pList ) = 0;
|
||||
virtual int DataCacheList( int nItems, const xDataCacheItem_t* pItems ) = 0;
|
||||
virtual int VProfNodeList( int nItems, const xVProfNodeItem_t *pItems ) = 0;
|
||||
virtual int TraceComplete( void ) = 0;
|
||||
virtual int BugReporter( void ) = 0;
|
||||
virtual bool SendBinaryData( const void *pData, int iDataSize, bool bAsync = true, DWORD dwSyncTimout = 15000 ) = 0; //returns false if sync call timed out or not connected. Otherwise true
|
||||
virtual int SyncDvdDevCache() = 0;
|
||||
virtual int SyncShaderCache() = 0;
|
||||
virtual int Version( int nVersion ) = 0;
|
||||
|
||||
// // // PS3 specific
|
||||
|
||||
// manually send a frame buffer across the DECI wire because the VRAM capture comes with all
|
||||
// sorts of untenable encumberances
|
||||
virtual void TransmitScreenshot( char *pFrameBuffer, uint32 uWidth, uint32 uHeight, uint32 uPitch, uint32 uColorFmt ) = 0;
|
||||
|
||||
// send an arbitrary blob of data of a given length. You have to supply the prefix yourself (avoids an unnecessary additional copy).
|
||||
virtual int SendBinaryDECI( const uint8 *dbgCommand, uint length, bool bHaltOnError = true ) = 0;
|
||||
|
||||
// a function that receives fake xbox messages
|
||||
typedef void (*fRemoteCommandSink_t)(const char *pRemoteCommandBuffer);
|
||||
// synchronous message pumping, could make an async thread in the future if necessary
|
||||
virtual void PumpMessage( fRemoteCommandSink_t ) = 0; // pump up to ONE remote command message synchronously
|
||||
|
||||
// Add delegates that are called when the console is connected/disconnected to VXConsole
|
||||
typedef void (*fOnConnectDelegate_t)( void );
|
||||
typedef void (*fOnDisconnectDelegate_t)( void );
|
||||
virtual void AddOnConnectDelegate( fOnConnectDelegate_t pOnConnectDelegate ) = 0;
|
||||
virtual void AddOnDisconnectDelegate( fOnDisconnectDelegate_t pOnDisconnectDelegate ) = 0;
|
||||
};
|
||||
|
||||
|
||||
PLATFORM_INTERFACE IPS3Console *g_pValvePS3Console;
|
||||
PLATFORM_INTERFACE void ValvePS3ConsoleInit();
|
||||
PLATFORM_INTERFACE void ValvePS3ConsoleShutdown();
|
||||
|
||||
#endif //PS3_CONSOLE_H
|
||||
|
||||
522
common/ps3/ps3_core.h
Normal file
522
common/ps3/ps3_core.h
Normal file
@@ -0,0 +1,522 @@
|
||||
//========= Copyright © 1996-2004, Valve LLC, All rights reserved. ============
|
||||
//
|
||||
// Purpose: XBox HAL - Game to hardware abstraction
|
||||
//
|
||||
//=============================================================================
|
||||
#pragma once
|
||||
|
||||
#define XBX_BREAK(x) if (x) {DebugBreak();}
|
||||
|
||||
//#define XBX_MAX_DPORTS 4
|
||||
// PS3 supports up to 7 controllers!
|
||||
#define XUSER_MAX_COUNT 7
|
||||
#define XBX_MAX_EVENTS 32
|
||||
#define XBX_MAX_BUTTONSAMPLE 32768
|
||||
#define XBX_MAX_ANALOGSAMPLE 255
|
||||
#define XBX_MAX_MESSAGE 1024
|
||||
#define XBX_MAX_PATH MAX_PATH
|
||||
#define XBX_MAX_RCMDLENGTH 256
|
||||
#define XBX_MAX_RCMDNAMELEN 32
|
||||
#define XBX_HDD_CLUSTERSIZE 16384
|
||||
|
||||
#define XBX_INVALID_STORAGE_ID ((DWORD)(-1))
|
||||
#define XBX_STORAGE_DECLINED ((DWORD)(-2))
|
||||
#define XBX_INVALID_USER_ID ((DWORD)(-1))
|
||||
|
||||
#define XBX_USER_SETTINGS_CONTAINER_DRIVE "CFG"
|
||||
#define XBX_USER_SAVES_CONTAINER_DRIVE "SAV"
|
||||
|
||||
typedef uint64_t XUID;
|
||||
#define IsEqualXUID( a, b ) ( ( a ) == ( b ) )
|
||||
|
||||
typedef struct {
|
||||
BYTE ab[8]; // xbox to xbox key identifier
|
||||
} XNKID;
|
||||
|
||||
typedef struct {
|
||||
BYTE ab[16]; // xbox to xbox key exchange key
|
||||
} XNKEY;
|
||||
|
||||
#define XCONTENT_MAX_DISPLAYNAME_LENGTH 128
|
||||
#define XCONTENT_MAX_FILENAME_LENGTH 42
|
||||
#define XCONTENTDEVICE_MAX_NAME_LENGTH 27
|
||||
typedef DWORD XCONTENTDEVICEID, *PXCONTENTDEVICEID;
|
||||
typedef struct _XCONTENT_DATA
|
||||
{
|
||||
XCONTENTDEVICEID DeviceID;
|
||||
DWORD dwContentType;
|
||||
wchar_t szDisplayName[XCONTENT_MAX_DISPLAYNAME_LENGTH];
|
||||
char szFileName[XCONTENT_MAX_FILENAME_LENGTH];
|
||||
} XCONTENT_DATA, *PXCONTENT_DATA;
|
||||
|
||||
// could be dvd or hdd, actual device depends on source of xbe launch
|
||||
#define XBX_DVD_DRIVE "D:\\"
|
||||
#define XBX_BOOT_DRIVE "D:\\"
|
||||
#define XBX_SWAP_DIRECTORY "T:\\HL2\\HL2X\\SWAP\\"
|
||||
#define XBX_PERSISTENT_DIR "T:\\HL2\\"
|
||||
#define XBX_HDD_SAVE_DIRECTORY "U:\\"
|
||||
|
||||
#define XBX_IOTHREAD_STACKSIZE 32768
|
||||
#define XBX_IOTHREAD_PRIORITY THREAD_PRIORITY_HIGHEST
|
||||
|
||||
#define XBX_SCREEN_WIDTH 640
|
||||
#define XBX_SCREEN_HEIGHT 480
|
||||
#define XBOX_MINBORDERSAFE 0.04f
|
||||
#define XBOX_MAXBORDERSAFE 0.04f
|
||||
|
||||
#ifndef GPU_RESOLVE_ALIGNMENT
|
||||
#define GPU_RESOLVE_ALIGNMENT 8
|
||||
#endif
|
||||
|
||||
#define XBX_CALCSIG_TYPE XCALCSIG_FLAG_NON_ROAMABLE
|
||||
|
||||
#define XBX_VIRTUAL_BASEDIR "r:\\hl2"
|
||||
#define XBX_GAMEDIR "hl2x"
|
||||
|
||||
#if defined( _DEBUG )
|
||||
#define XBX_XBE_BASE_FILENAME "hl2d_xbox.xbe"
|
||||
#elif defined( _RELEASE )
|
||||
#define XBX_XBE_BASE_FILENAME "hl2r_xbox.xbe"
|
||||
#else
|
||||
#define XBX_XBE_BASE_FILENAME "hl2_xbox.xbe"
|
||||
#endif
|
||||
|
||||
// Path to our running executable
|
||||
#define XBX_XBE_PATH XBX_BOOT_DRIVE XBX_XBE_BASE_FILENAME
|
||||
|
||||
#define CLR_DEFAULT 0xFF000000
|
||||
#define CLR_WARNING 0x0000FFFF
|
||||
#define CLR_ERROR 0x000000FF
|
||||
|
||||
#define XBX_ALIGN(x,y) (((x)+((y)-1))&~((y)-1))
|
||||
|
||||
// disk space requirements
|
||||
#define HL2_SAVEIMAGE_BYTES ( 1024 * 70 )
|
||||
#define HL2_SAVEGAME_BYTES ( 1024 * 1024 * 10 )
|
||||
#define HL2_CONFIGFILE_BYTES XBX_HDD_CLUSTERSIZE
|
||||
|
||||
#define HL2_PERSISTENT_BYTES_NEEDED ( HL2_CONFIGFILE_BYTES + HL2_SAVEGAME_BYTES * 2 )
|
||||
#define HL2_USERSAVE_BYTES_NEEDED ( HL2_SAVEGAME_BYTES + HL2_SAVEIMAGE_BYTES + XBX_GetSaveGameOverhead() )
|
||||
|
||||
#define FILE_BEGIN 0
|
||||
#define FILE_CURRENT 1
|
||||
#define FILE_END 2
|
||||
|
||||
typedef enum
|
||||
{
|
||||
XC_NULL,
|
||||
XC_NORMAL,
|
||||
XC_IBEAM,
|
||||
XC_WAIT,
|
||||
XC_CROSS,
|
||||
XC_UP,
|
||||
XC_SIZENWSE,
|
||||
XC_SIZENESW,
|
||||
XC_SIZEWE,
|
||||
XC_SIZENS,
|
||||
XC_SIZEALL,
|
||||
XC_NO,
|
||||
XC_HAND,
|
||||
XC_MAXCURSORS,
|
||||
} xCursor_e;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
XK_NULL,
|
||||
XK_BUTTON_UP,
|
||||
XK_BUTTON_DOWN,
|
||||
XK_BUTTON_LEFT,
|
||||
XK_BUTTON_RIGHT,
|
||||
XK_BUTTON_START,
|
||||
XK_BUTTON_BACK,
|
||||
XK_BUTTON_STICK1,
|
||||
XK_BUTTON_STICK2,
|
||||
XK_BUTTON_A,
|
||||
XK_BUTTON_B,
|
||||
XK_BUTTON_X,
|
||||
XK_BUTTON_Y,
|
||||
XK_BUTTON_LEFT_SHOULDER,
|
||||
XK_BUTTON_RIGHT_SHOULDER,
|
||||
XK_BUTTON_LTRIGGER,
|
||||
XK_BUTTON_RTRIGGER,
|
||||
XK_STICK1_UP,
|
||||
XK_STICK1_DOWN,
|
||||
XK_STICK1_LEFT,
|
||||
XK_STICK1_RIGHT,
|
||||
XK_STICK2_UP,
|
||||
XK_STICK2_DOWN,
|
||||
XK_STICK2_LEFT,
|
||||
XK_STICK2_RIGHT,
|
||||
XK_BUTTON_INACTIVE_START, // Special key that is passed through on disabled controllers
|
||||
XK_BUTTON_FIREMODE_SELECTOR_1,
|
||||
XK_BUTTON_FIREMODE_SELECTOR_2,
|
||||
XK_BUTTON_FIREMODE_SELECTOR_3,
|
||||
XK_BUTTON_RELOAD,
|
||||
XK_BUTTON_TRIGGER,
|
||||
XK_BUTTON_PUMP_ACTION,
|
||||
XK_XBUTTON_ROLL_RIGHT,
|
||||
XK_XBUTTON_ROLL_LEFT,
|
||||
XK_MAX_KEYS,
|
||||
} xKey_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
XVRB_NONE, // off
|
||||
XVRB_ERROR, // fatal error
|
||||
XVRB_ALWAYS, // no matter what
|
||||
XVRB_WARNING, // non-fatal warnings
|
||||
XVRB_STATUS, // status reports
|
||||
XVRB_ALL,
|
||||
} xverbose_e;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
XOF_READ = 0x01, // read access
|
||||
XOF_WRITE = 0x02, // write access
|
||||
XOF_CREATE = 0x04, // create if not exist
|
||||
} xopenfile_e;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
XSF_SET = FILE_BEGIN,
|
||||
XSF_CUR = FILE_CURRENT,
|
||||
XSF_END = FILE_END,
|
||||
} xseekfile_e;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
XFA_LOCALONLY,
|
||||
XFA_REMOTEONLY,
|
||||
XFA_LOCALFIRST,
|
||||
} xFileAccess_e;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
XEV_NULL,
|
||||
XEV_KEY,
|
||||
XEV_REMOTECMD,
|
||||
XEV_LISTENER_NOTIFICATION,
|
||||
XEV_QUIT,
|
||||
XEV_GAMEPAD_UNPLUGGED,
|
||||
XEV_GAMEPAD_INSERTED,
|
||||
} xevent_e;
|
||||
|
||||
typedef struct xevent_s
|
||||
{
|
||||
xevent_e event;
|
||||
int arg1;
|
||||
int arg2;
|
||||
int arg3;
|
||||
uint64 sysutil_status;
|
||||
uint64 sysutil_param;
|
||||
} xevent_t;
|
||||
|
||||
typedef struct xevent_SYS_SIGNINCHANGED_s
|
||||
{
|
||||
XUID xuid[ XUSER_MAX_COUNT ];
|
||||
int state[ XUSER_MAX_COUNT ];
|
||||
DWORD dwParam;
|
||||
} xevent_SYS_SIGNINCHANGED_t;
|
||||
|
||||
typedef struct ps3syscbckeventhdlr_s
|
||||
{
|
||||
int (*pfnHandler)( xevent_t const &ev );
|
||||
} ps3syscbckeventhdlr_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
MDIR_NULL = 0x00,
|
||||
MDIR_UP = 0x01,
|
||||
MDIR_DOWN = 0x02,
|
||||
MDIR_LEFT = 0x04,
|
||||
MDIR_RIGHT = 0x08,
|
||||
} xMouseDir_e;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char *pName;
|
||||
const char *pGroupName;
|
||||
const char *pFormatName;
|
||||
int size;
|
||||
int width;
|
||||
int height;
|
||||
int depth;
|
||||
int numLevels;
|
||||
int binds;
|
||||
int refCount;
|
||||
int sRGB;
|
||||
int edram;
|
||||
int procedural;
|
||||
int cacheableState;
|
||||
int cacheableSize;
|
||||
int final;
|
||||
int failed;
|
||||
int pwl;
|
||||
int reduced;
|
||||
} xTextureList_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char *pName;
|
||||
const char *pShaderName;
|
||||
int refCount;
|
||||
} xMaterialList_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char name[MAX_PATH];
|
||||
char formatName[32];
|
||||
int rate;
|
||||
int bits;
|
||||
int channels;
|
||||
int looped;
|
||||
int dataSize;
|
||||
int numSamples;
|
||||
int streamed;
|
||||
int quality;
|
||||
} xSoundList_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float position[3];
|
||||
float angle[3];
|
||||
char mapPath[256];
|
||||
char savePath[256];
|
||||
int build;
|
||||
int skill;
|
||||
char details[1024];
|
||||
} xMapInfo_t;
|
||||
|
||||
/******************************************************************************
|
||||
XBX_CONSOLE.CPP
|
||||
******************************************************************************/
|
||||
extern int XBX_rAddCommands(int numCommands, const char* commands[], const char* help[]);
|
||||
extern int XBX_rTextureList(int nTextures, const xTextureList_t* pXTextureList);
|
||||
extern int XBX_rTimeStampLog(float time, const char *pString);
|
||||
#define XBX_rMaterialList if ( !g_pValvePS3Console ); else g_pValvePS3Console->MaterialList //(int nMaterials, const xMaterialList_t* pXMaterialList);
|
||||
// inline int XBX_rSoundList(int nSounds, const xSoundList_t* pXSoundList) { return g_pValvePS3Console ? g_pValvePS3Console->SoundList( nSounds, pXSoundList ) : -1 ; }
|
||||
#define XBX_rSoundList if ( !g_pValvePS3Console ); else g_pValvePS3Console->SoundList
|
||||
extern int XBX_rMemDump( int nStatsID );
|
||||
#define XBX_rMapInfo if ( !g_pValvePS3Console ) ; else g_pValvePS3Console->MapInfo //( xMapInfo_t *pMapInfo ) { return g_pValvePS3Console ? g_pValvePS3Console->MapInfo( pMapInfo ) : -1 ; }
|
||||
|
||||
/******************************************************************************
|
||||
XBX_DEBUG.CPP
|
||||
******************************************************************************/
|
||||
// extern void XBX_SendRemoteCommand(const char* dbgCommand, bool async);
|
||||
#define XBX_SendRemoteCommand if ( !g_pValvePS3Console ) ; else g_pValvePS3Console->SendRemoteCommand
|
||||
#define XBX_SendPrefixedMsg if ( !g_pValvePS3Console ) ; else g_pValvePS3Console->SendPrefixedDECIMessage
|
||||
// extern void XBX_DebugString(xverbose_e verbose, COLORREF color, const char* format, ...);
|
||||
#define XBX_DebugString if ( !g_pValvePS3Console ) ; else g_pValvePS3Console->DebugString
|
||||
extern void XBX_SetVerbose(xverbose_e verbose);
|
||||
extern void XBX_InitDebug(void);
|
||||
extern void XBX_Log( const char *pString );
|
||||
extern bool g_xbx_bNoVXConsole;
|
||||
|
||||
/******************************************************************************
|
||||
XBX_DEVICES.CPP
|
||||
******************************************************************************/
|
||||
extern void XBX_InitDevices(void);
|
||||
extern void XBX_SampleDevices(void);
|
||||
extern void XBX_SetRumble( float fLeftMotor, float fRightMotor );
|
||||
extern void XBX_StopRumble( void );
|
||||
extern void XBX_SetActiveController( int port );
|
||||
extern int XBX_GetActiveController();
|
||||
extern bool XBX_IsControllerValid( int port );
|
||||
|
||||
/******************************************************************************
|
||||
XBX_DISPLAY.CPP
|
||||
******************************************************************************/
|
||||
extern u32_t XBX_GetDisplayTime(void);
|
||||
extern void XBX_CreateDisplay(void);
|
||||
extern void XBX_BeginFrame(void);
|
||||
extern void XBX_EndFrame(void);
|
||||
//EAPS3extern void XBX_HookD3DDevice(IDirect3DDevice8* pD3DDevice);
|
||||
//EAPS3extern IDirect3DDevice8 *g_xbx_pD3DDevice;
|
||||
extern u32_t g_xbx_numVBlanks;
|
||||
extern u32_t g_xbx_frameTime;
|
||||
extern int g_xbx_numFrames;
|
||||
|
||||
/******************************************************************************
|
||||
XBX_FILEIO.CPP
|
||||
******************************************************************************/
|
||||
enum xFileDevice_e
|
||||
{
|
||||
XFD_NULL,
|
||||
XFD_LOCALHDD,
|
||||
XFD_REMOTEHDD,
|
||||
XFD_DVDROM,
|
||||
XFD_TITLE_PERSISTENT_HDD,
|
||||
};
|
||||
|
||||
enum XFileMode_t
|
||||
{
|
||||
XFM_BINARY,
|
||||
XFM_TEXT
|
||||
};
|
||||
|
||||
//EAPS3 : XBox structure
|
||||
struct WIN32_FIND_DATA
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
//EAPS3 : XBox structure
|
||||
struct XGAME_FIND_DATA
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
extern void XBX_FixupFilename(const char* input, char* output, xFileDevice_e& outFileDevice, bool bWarnInvalid = true);
|
||||
extern void XBX_SetRemotePath(const char* remotePath);
|
||||
extern void XBX_SetLocalPath(const char* localPath);
|
||||
extern const char *XBX_GetLocalPath();
|
||||
extern FILE* XBX_fopen(const char* filename, const char* options);
|
||||
extern int XBX_setvbuf( FILE *fp, char *,int mode, size_t size );
|
||||
extern int XBX_fclose(FILE* fp);
|
||||
extern int XBX_fseek(FILE *fp, long pos, int seekType);
|
||||
extern long XBX_ftell(FILE *fp);
|
||||
extern int XBX_feof(FILE *fp);
|
||||
extern size_t XBX_fread(void *dest, size_t size, size_t count, FILE *fp);
|
||||
extern size_t XBX_fwrite(const void *src, size_t size, size_t count, FILE *fp);
|
||||
extern bool XBX_setmode( FILE *fp, int mode );
|
||||
extern size_t XBX_vfprintf(FILE *fp, const char *fmt, va_list list);
|
||||
extern int XBX_ferror(FILE *fp);
|
||||
extern int XBX_fflush(FILE *fp);
|
||||
extern char* XBX_fgets(char *dest, int destSize, FILE *fp);
|
||||
extern int XBX_stat(const char *path, struct _stat *buf);
|
||||
//extern int XBX_unlink(const char* filename);
|
||||
extern int XBX_rename(const char* pszFrom, const char* pszTo);
|
||||
extern HANDLE XBX_FindFirstFile(const char *findname, WIN32_FIND_DATA *dat);
|
||||
extern BOOL XBX_FindNextFile(HANDLE handle, WIN32_FIND_DATA *dat);
|
||||
extern BOOL XBX_FindClose(HANDLE handle);
|
||||
extern void XBX_SetFileAccess(xFileAccess_e mode);
|
||||
extern void XBX_EnableFileSync(bool bSync);
|
||||
//extern int XBX_mkdir( const char * );
|
||||
extern void XBX_rFileSync(const char *pFileName);
|
||||
extern DWORD XBX_GetSigSize( DWORD sigType );
|
||||
extern void XBX_CalculateSignature( BYTE *buff, void *pSig, DWORD buffSize, DWORD sigType );
|
||||
extern bool XBX_ValidateSignature( BYTE *pBuffer, DWORD size, DWORD sigType );
|
||||
extern bool g_xbx_bFileSync;
|
||||
extern DWORD XBX_GetSigSize( DWORD sigType );
|
||||
extern void XBX_CalculateSignature( BYTE *buff, void *pSig, DWORD buffSize, DWORD sigType );
|
||||
extern bool XBX_ValidateSignature( BYTE *pBuffer, DWORD size, DWORD sigType );
|
||||
extern bool XBX_SaveFileExists( const wchar_t *pName, XGAME_FIND_DATA *fileData );
|
||||
extern bool XBX_SaveNumberExists( const int number, XGAME_FIND_DATA *fileData );
|
||||
|
||||
/******************************************************************************
|
||||
XBX_MEMORY.CPP
|
||||
******************************************************************************/
|
||||
extern void XBX_InitMemory(void);
|
||||
extern void XBX_EnableMemoryTrace(bool enable);
|
||||
extern unsigned int g_xbx_memoryD3DCost;
|
||||
|
||||
/******************************************************************************
|
||||
XBX_PROFILE.CPP
|
||||
******************************************************************************/
|
||||
class xVProfNodeItem_t;
|
||||
extern int XBX_rSetProfileAttributes(const char *pProfileName, int numCounters, const char *names[], COLORREF colors[]);
|
||||
extern void XBX_rSetProfileData( const char *pProfileName, int numCounters, unsigned int *counters );
|
||||
extern void XBX_rVProfNodeList( int nItems, const xVProfNodeItem_t *pItems );
|
||||
|
||||
/******************************************************************************
|
||||
XBX_SYSTEM.CPP
|
||||
******************************************************************************/
|
||||
extern void XBX_StringCopyToWide( WCHAR *pDst, const char *pSrc );
|
||||
extern u32_t XBX_GetSystemTime(void);
|
||||
ULARGE_INTEGER XBX_GetFreeBytes( const char *drive );
|
||||
extern unsigned int XBX_GetBlocksNeeded( const char *drive, DWORD bytesRequested );
|
||||
extern DWORD XBX_GetSaveGameOverhead( void );
|
||||
extern void XBX_Error(const char* format, ...);
|
||||
extern void XBX_Init();
|
||||
extern bool XBX_IsRetailMode();
|
||||
extern void XBX_RelaunchHL2( unsigned int contextCode = 0, const char *pszArgs = "", void *pRelaunchData = NULL, unsigned nBytesRelaunchData = 0 );
|
||||
extern bool XBX_GetRelaunchContext( unsigned int *pContextCode, __int64 *pStartTime );
|
||||
extern bool XBX_GetRelaunchData( void *pRelaunchData, unsigned maxBytes );
|
||||
extern void XBX_LaunchInstaller( unsigned int contextCode );
|
||||
extern void XBX_LaunchDashboard( char chDrive, int spaceNeeded );
|
||||
extern LPSTR g_xbx_pCmdLine;
|
||||
extern const char* g_xbx_version;
|
||||
extern bool XBX_NoXBDM();
|
||||
|
||||
typedef HRESULT (STDCALL *DmSendNotificationStringFunc_t)(LPCSTR sz);
|
||||
typedef HRESULT (STDCALL *DmRegisterCommandProcessorFunc_t)(LPCSTR szProcessor, PVOID /*HACK:/needsport/ WAS:PDM_CMDPROC /Vitaliy/ */ pfn);
|
||||
typedef HRESULT (STDCALL *DmCaptureStackBackTraceFunc_t)(ULONG FramesToCapture, PVOID *BackTrace);
|
||||
typedef BOOL (STDCALL *DmIsDebuggerPresentFunc_t)(void);
|
||||
|
||||
extern DmSendNotificationStringFunc_t CallDmSendNotificationString;
|
||||
extern DmRegisterCommandProcessorFunc_t CallDmRegisterCommandProcessor;
|
||||
extern DmCaptureStackBackTraceFunc_t CallDmCaptureStackBackTrace;
|
||||
extern DmIsDebuggerPresentFunc_t CallDmIsDebuggerPresent;
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
XBX_EVENTS.CPP
|
||||
******************************************************************************/
|
||||
|
||||
// Event handling
|
||||
PLATFORM_INTERFACE bool XBX_NotifyCreateListener( uint64_t categories );
|
||||
PLATFORM_INTERFACE void XBX_QueueEvent( xevent_e event, int arg1, int arg2, int arg3 );
|
||||
PLATFORM_INTERFACE void XBX_ProcessEvents( void );
|
||||
PLATFORM_INTERFACE void XBX_DispatchEventsQueue( void );
|
||||
|
||||
// Accessors
|
||||
PLATFORM_INTERFACE const char* XBX_GetLanguageString( void );
|
||||
PLATFORM_INTERFACE bool XBX_IsLocalized( void );
|
||||
PLATFORM_INTERFACE bool XBX_IsAudioLocalized( void );
|
||||
PLATFORM_INTERFACE const char *XBX_GetNextSupportedLanguage( const char *pLanguage, bool *pbHasAudio );
|
||||
PLATFORM_INTERFACE bool XBX_IsRestrictiveLanguage( void );
|
||||
PLATFORM_INTERFACE u32_t XBX_GetImageChangelist( void );
|
||||
|
||||
//
|
||||
// Storage devices management
|
||||
//
|
||||
PLATFORM_INTERFACE void XBX_ResetStorageDeviceInfo();
|
||||
PLATFORM_INTERFACE DWORD XBX_DescribeStorageDevice( DWORD nStorageID );
|
||||
PLATFORM_INTERFACE char const *XBX_MakeStorageContainerRoot( int iController, char const *szRootName, char *pBuffer, int numBufferBytes );
|
||||
|
||||
PLATFORM_INTERFACE DWORD XBX_GetStorageDeviceId( int iController );
|
||||
PLATFORM_INTERFACE void XBX_SetStorageDeviceId( int iController, DWORD id );
|
||||
|
||||
//
|
||||
// Information about game primary user
|
||||
//
|
||||
PLATFORM_INTERFACE DWORD XBX_GetPrimaryUserId( void );
|
||||
PLATFORM_INTERFACE void XBX_SetPrimaryUserId( DWORD id );
|
||||
|
||||
PLATFORM_INTERFACE DWORD XBX_GetPrimaryUserIsGuest( void );
|
||||
PLATFORM_INTERFACE void XBX_SetPrimaryUserIsGuest( DWORD bPrimaryUserIsGuest );
|
||||
|
||||
//
|
||||
// Disabling and enabling input from controllers
|
||||
//
|
||||
PLATFORM_INTERFACE void XBX_ResetUserIdSlots();
|
||||
PLATFORM_INTERFACE void XBX_ClearUserIdSlots();
|
||||
|
||||
//
|
||||
// Mapping between game slots and controllers
|
||||
//
|
||||
PLATFORM_INTERFACE int XBX_GetUserId( int nSlot );
|
||||
PLATFORM_INTERFACE int XBX_GetSlotByUserId( int idx );
|
||||
PLATFORM_INTERFACE void XBX_SetUserId( int nSlot, int idx );
|
||||
PLATFORM_INTERFACE void XBX_ClearSlot( int nSlot );
|
||||
PLATFORM_INTERFACE void XBX_ClearUserId( int idx );
|
||||
|
||||
PLATFORM_INTERFACE DWORD XBX_GetUserIsGuest( int nSlot );
|
||||
PLATFORM_INTERFACE void XBX_SetUserIsGuest( int nSlot, DWORD dwUserIsGuest );
|
||||
|
||||
//
|
||||
// Number of game users
|
||||
//
|
||||
PLATFORM_INTERFACE DWORD XBX_GetNumGameUsers( void );
|
||||
PLATFORM_INTERFACE void XBX_SetNumGameUsers( DWORD numGameUsers );
|
||||
|
||||
//
|
||||
// Invite related functions
|
||||
//
|
||||
PLATFORM_INTERFACE XNKID XBX_GetInviteSessionId( void );
|
||||
PLATFORM_INTERFACE void XBX_SetInviteSessionId( XNKID nSessionId );
|
||||
PLATFORM_INTERFACE XUID XBX_GetInvitedUserXuid( void );
|
||||
PLATFORM_INTERFACE void XBX_SetInvitedUserXuid( XUID xuid );
|
||||
PLATFORM_INTERFACE DWORD XBX_GetInvitedUserId( void );
|
||||
PLATFORM_INTERFACE void XBX_SetInvitedUserId( DWORD nUserId );
|
||||
|
||||
45
common/ps3/ps3_d3dstubs.h
Normal file
45
common/ps3/ps3_d3dstubs.h
Normal file
@@ -0,0 +1,45 @@
|
||||
//========= Copyright © 1996-2004, Valve LLC, All rights reserved. ============
|
||||
//
|
||||
// Purpose: XBox win32 stubs
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================
|
||||
#pragma once
|
||||
|
||||
typedef void* IDirect3D9;
|
||||
typedef void* IDirect3DDevice9;
|
||||
typedef void* IDirect3DVertexShader9;
|
||||
typedef void* IDirect3DPixelShader9;
|
||||
typedef void* IDirect3DVertexDeclaration9;
|
||||
typedef void* IDirect3DTexture9;
|
||||
typedef void* IDirect3DBaseTexture9;
|
||||
typedef void* IDirect3DCubeTexture9;
|
||||
typedef void* IDirect3DSurface9;
|
||||
typedef void* IDirect3DIndexBuffer9;
|
||||
typedef void* IDirect3DVertexBuffer9;
|
||||
typedef void* IDirect3DVolumeTexture9;
|
||||
typedef void ID3DXFont;
|
||||
typedef void* D3DADAPTER_IDENTIFIER9;
|
||||
typedef void* D3DCAPS9;
|
||||
typedef void* D3DMATERIAL9;
|
||||
typedef void* D3DVIEWPORT9;
|
||||
typedef void* D3DLIGHT9;
|
||||
typedef void* D3DVERTEXELEMENT9;
|
||||
|
||||
// not sure what behavior to emulate yet
|
||||
#define D3DLOCK_NOSYSLOCK 0
|
||||
#define D3DLOCK_DISCARD 0
|
||||
|
||||
#define D3DENUM_WHQL_LEVEL 0
|
||||
|
||||
// collapse sampler state back into texture state
|
||||
typedef enum
|
||||
{
|
||||
D3DSAMP_ADDRESSU = D3DTSS_ADDRESSU,
|
||||
D3DSAMP_ADDRESSV = D3DTSS_ADDRESSV,
|
||||
D3DSAMP_ADDRESSW = D3DTSS_ADDRESSW,
|
||||
D3DSAMP_MINFILTER = D3DTSS_MINFILTER,
|
||||
D3DSAMP_MAGFILTER = D3DTSS_MAGFILTER,
|
||||
D3DSAMP_MIPFILTER = D3DTSS_MIPFILTER,
|
||||
D3DSAMP_MAXANISOTROPY = D3DTSS_MAXANISOTROPY,
|
||||
} D3DSAMPLERSTATETYPE;
|
||||
447
common/ps3/ps3_helpers.h
Normal file
447
common/ps3/ps3_helpers.h
Normal file
@@ -0,0 +1,447 @@
|
||||
#ifndef __PS3_HELPERS__
|
||||
#define __PS3_HELPERS__
|
||||
|
||||
#ifndef SN_TARGET_PS3
|
||||
#error
|
||||
#endif
|
||||
|
||||
|
||||
#include <cellstatus.h>
|
||||
#include <sys/paths.h>
|
||||
#include <sys/prx.h>
|
||||
#include <sys/synchronization.h>
|
||||
#include <sys/ppu_thread.h>
|
||||
#include <sys/timer.h>
|
||||
#include "ppu_intrinsics.h"
|
||||
#include <np.h>
|
||||
#include <np/drm.h>
|
||||
|
||||
// Forward declarations
|
||||
|
||||
#ifndef _CERT
|
||||
#define PS3PRXLOADDIAGNOSTIC printf
|
||||
#else
|
||||
#define PS3PRXLOADDIAGNOSTIC( ... ) ((void)0)
|
||||
#endif
|
||||
|
||||
struct TLSGlobals;
|
||||
|
||||
// PS3 PRX load parameters structures
|
||||
|
||||
struct PS3_PrxLoadParametersBase_t
|
||||
{
|
||||
int32_t cbSize;
|
||||
sys_prx_id_t sysPrxId;
|
||||
uint64_t uiFlags;
|
||||
uint64_t reserved[7];
|
||||
};
|
||||
|
||||
struct PS3_PrxModuleEntry_t
|
||||
{
|
||||
PS3_PrxModuleEntry_t *pNextModule;
|
||||
char chName[256];
|
||||
uint32_t uiRefCount;
|
||||
PS3_PrxLoadParametersBase_t prxParams[0];
|
||||
};
|
||||
extern "C" PS3_PrxModuleEntry_t ** PS3_PrxGetModulesList();
|
||||
|
||||
|
||||
struct PS3_GcmSharedData;
|
||||
|
||||
// exported from tier0
|
||||
extern "C" PS3_GcmSharedData *g_pGcmSharedData;
|
||||
|
||||
|
||||
struct PS3_GcmSharedData
|
||||
{
|
||||
void *m_pIoMemory;
|
||||
uint32_t m_nIoMemorySize;
|
||||
|
||||
PS3_GcmSharedData()
|
||||
{
|
||||
memset(this, 0, sizeof(PS3_GcmSharedData));
|
||||
}
|
||||
|
||||
// Thread for the QMS and Server (when host_thread_mode)
|
||||
// Thread wakes up on a semaphore and when it does so it checks for
|
||||
// sv_runflag and then qms runFlag and does the right thing
|
||||
// This is hand coded because the PS3 scheduler sometimes (regardless of priorities)
|
||||
// pushes out the main thread to run the server if the server is it's own job.
|
||||
// So we create a single thread, one which we have the ability to explicitly
|
||||
// run the server and the qms
|
||||
// The semaphore is there so that we can sleep instead of exiting the job
|
||||
// Otherwise the run flags actually control if we run locklessly
|
||||
// CheckForServerRequest() is called eregularly on the QMS and so allows the
|
||||
// server to interrupt the QMS and run pretty much where we need to to.
|
||||
//
|
||||
|
||||
sys_ppu_thread_t m_thread;
|
||||
sys_semaphore_t m_semaphore;
|
||||
|
||||
// Server
|
||||
|
||||
volatile int m_svRunFlag;
|
||||
volatile int m_svDoneFlag;
|
||||
volatile int m_numTicks;
|
||||
void (*m_pfnAsyncServer)(int numTicks);
|
||||
|
||||
// QMS
|
||||
|
||||
volatile int m_qmsRunFlag;
|
||||
volatile int m_qmsDoneFlag;
|
||||
volatile void* m_cmat;
|
||||
volatile void* m_ptr;
|
||||
void (*m_func)(void*, void*);
|
||||
|
||||
// Audio
|
||||
|
||||
volatile int m_audioRunFlag;
|
||||
volatile int m_audioDoneFlag;
|
||||
void (*m_AudioFunc)(void);
|
||||
|
||||
// Endframe Defrag
|
||||
|
||||
volatile int m_bDeFrag;
|
||||
|
||||
// Create semaphore & thread
|
||||
|
||||
void Init()
|
||||
{
|
||||
// Create Semaphore
|
||||
sys_semaphore_attribute_t attr;
|
||||
|
||||
sys_semaphore_attribute_initialize(attr);
|
||||
int ret = sys_semaphore_create(&m_semaphore, &attr, 0, 2); // No point in allowing > 2 posts
|
||||
if(ret != CELL_OK)
|
||||
{
|
||||
printf("Unable to create QMS sem\n");
|
||||
}
|
||||
}
|
||||
|
||||
void RunServer(void (*pfn)(int), int numticks)
|
||||
{
|
||||
|
||||
// Set global data
|
||||
|
||||
m_pfnAsyncServer = pfn;
|
||||
m_numTicks = numticks;
|
||||
|
||||
__lwsync();
|
||||
|
||||
m_svRunFlag = 1;
|
||||
|
||||
// Post semaphore incase trhead sleeps
|
||||
|
||||
sys_semaphore_post(m_semaphore, 1);
|
||||
|
||||
}
|
||||
|
||||
void RunQMS(void (*func)(void* cmat, void* ptr), void* cmat, void* ptr )
|
||||
{
|
||||
m_func = func;
|
||||
m_cmat = cmat;
|
||||
m_ptr = ptr;
|
||||
|
||||
__lwsync();
|
||||
|
||||
m_qmsRunFlag = 1;
|
||||
|
||||
// Post semaphore incase trhead sleeps
|
||||
|
||||
sys_semaphore_post(m_semaphore, 1);
|
||||
}
|
||||
|
||||
void WaitForServer()
|
||||
{
|
||||
while (!m_svDoneFlag) sys_timer_usleep(60);
|
||||
m_svDoneFlag = 0;
|
||||
|
||||
}
|
||||
|
||||
void WaitForQMS()
|
||||
{
|
||||
while (!m_qmsDoneFlag) sys_timer_usleep(60);
|
||||
m_qmsDoneFlag = 0;
|
||||
|
||||
}
|
||||
|
||||
void CheckForServerRequest()
|
||||
{
|
||||
if (m_svRunFlag)
|
||||
{
|
||||
m_svRunFlag = 0;
|
||||
m_pfnAsyncServer(m_numTicks);
|
||||
m_svDoneFlag = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Audio
|
||||
|
||||
|
||||
void RunAudio(void (*pfn)(void))
|
||||
{
|
||||
|
||||
// Set global data
|
||||
|
||||
m_AudioFunc = pfn;
|
||||
|
||||
__lwsync();
|
||||
|
||||
m_audioRunFlag = 1;
|
||||
|
||||
// Post semaphore incase trhead sleeps
|
||||
|
||||
sys_semaphore_post(m_semaphore, 1);
|
||||
|
||||
}
|
||||
|
||||
void WaitForAudio()
|
||||
{
|
||||
while (!m_audioDoneFlag) sys_timer_usleep(60);
|
||||
m_audioDoneFlag = 0;
|
||||
}
|
||||
|
||||
void CheckForAudioRequest()
|
||||
{
|
||||
if (g_pGcmSharedData->m_audioRunFlag)
|
||||
{
|
||||
g_pGcmSharedData->m_audioRunFlag = 0;
|
||||
g_pGcmSharedData->m_AudioFunc();
|
||||
g_pGcmSharedData->m_audioDoneFlag = 1;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
class CPs3ContentPathInfo;
|
||||
struct PS3_LoadTier0_Parameters_t : public PS3_PrxLoadParametersBase_t
|
||||
{
|
||||
typedef TLSGlobals * ( *PFNGETTLSGLOBALS )();
|
||||
PFNGETTLSGLOBALS pfnGetTlsGlobals; // [IN] [ from launcher_main to tier0 ]
|
||||
|
||||
PS3_PrxModuleEntry_t **ppPrxModulesList; // [IN] [ from launcher_main: head of the list of loaded PRX modules ]
|
||||
|
||||
CPs3ContentPathInfo *pPS3PathInfo; // [IN] [ from launcher_main to tier0 ]
|
||||
|
||||
uint64_t fiosLaunchTime; // [IN] [ from launcher_main: the time when the launcher was launched, the baseline time ]
|
||||
|
||||
uint32_t nCLNumber; // [IN] [ from launcher_main to tier0: the changelist number for this image (0 if unknown) ]
|
||||
|
||||
void(*pfnPushMarker)( const char * pName );
|
||||
void(*pfnPopMarker)();
|
||||
void(*pfnSwapBufferMarker)();
|
||||
|
||||
// Raw SPU libSN functions
|
||||
|
||||
void (*snRawSPULockHandler) (void);
|
||||
void (*snRawSPUUnlockHandler) (void);
|
||||
void (*snRawSPUNotifyCreation) (unsigned int uID);
|
||||
void (*snRawSPUNotifyDestruction) (unsigned int uID);
|
||||
void (*snRawSPUNotifyElfLoad) (unsigned int uID, unsigned int uEntry, const char *pFileName);
|
||||
void (*snRawSPUNotifyElfLoadNoWait) (unsigned int uID, unsigned int uEntry, const char *pFileName);
|
||||
void (*snRawSPUNotifyElfLoadAbs) (unsigned int uID, unsigned int uEntry, const char *pFileName);
|
||||
void (*snRawSPUNotifyElfLoadAbsNoWait) (unsigned int uID, unsigned int uEntry, const char *pFileName);
|
||||
void (*snRawSPUNotifySPUStopped) (unsigned int uID);
|
||||
void (*snRawSPUNotifySPUStarted) (unsigned int uID);
|
||||
|
||||
struct PS3_GcmSharedData *m_pGcmSharedData;
|
||||
|
||||
typedef void ( *PFNSHUTDOWN )();
|
||||
PFNSHUTDOWN pfnTier0Shutdown; // [OUT] [ tier0 shutdown procedure to be invoked ]
|
||||
};
|
||||
|
||||
struct PS3_LoadLauncher_Parameters_t : public PS3_PrxLoadParametersBase_t
|
||||
{
|
||||
typedef int ( *PFNLAUNCHERMAIN )( int argc, char **argv );
|
||||
PFNLAUNCHERMAIN pfnLauncherMain; // [OUT] [ launcher entry point ]
|
||||
|
||||
typedef void ( *PFNSHUTDOWN )();
|
||||
PFNSHUTDOWN pfnLauncherShutdown; // [OUT] [ launcher shutdown procedure to be invoked ]
|
||||
};
|
||||
|
||||
struct PS3_LoadAppSystemInterface_Parameters_t : public PS3_PrxLoadParametersBase_t
|
||||
{
|
||||
typedef void* ( *PFNCREATEINTERFACE )( const char *pName, int *pReturnCode );
|
||||
|
||||
PFNCREATEINTERFACE pfnCreateInterface; // [OUT] [ app system module create interface entry point ]
|
||||
uint64_t reserved[8];
|
||||
};
|
||||
|
||||
inline int PS3_PrxLoad( const char *path, PS3_PrxLoadParametersBase_t *params )
|
||||
{
|
||||
#define NP_POOL_SIZE (128*1024)
|
||||
static uint8_t np_pool[NP_POOL_SIZE];
|
||||
|
||||
int res;
|
||||
int modres;
|
||||
sys_prx_id_t id;
|
||||
|
||||
if ( !params )
|
||||
return -1;
|
||||
|
||||
PS3_PrxModuleEntry_t ** ppPrxModulesList = PS3_PrxGetModulesList();
|
||||
|
||||
//
|
||||
// Walk the loaded list
|
||||
//
|
||||
|
||||
for ( PS3_PrxModuleEntry_t *pEntry = *ppPrxModulesList; pEntry; pEntry = pEntry->pNextModule )
|
||||
{
|
||||
if ( strcmp( pEntry->chName, path ) )
|
||||
continue;
|
||||
|
||||
++ pEntry->uiRefCount;
|
||||
memcpy( params, pEntry->prxParams, ( pEntry->prxParams->cbSize <= params->cbSize ) ? pEntry->prxParams->cbSize : params->cbSize );
|
||||
PS3PRXLOADDIAGNOSTIC("PRX MODULE ADDREF: %s [0x%08X] (refs=%u)\n", path, params->sysPrxId, pEntry->uiRefCount);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
// Load a new instance of PRX
|
||||
//
|
||||
|
||||
|
||||
params->sysPrxId = -1;
|
||||
|
||||
// If sceNp wasn't already initalised then we need to un-init it after we're done here. If Steam is loaded
|
||||
// after this and it finds NP is already intialised it won't like it
|
||||
int npInit = sceNpInit( NP_POOL_SIZE, np_pool );
|
||||
SceNpDrmKey key = { 0x2B, 0x8E, 0xD3, 0xE4, 0xDF, 0xF1, 0x43, 0xA2, 0xA5, 0xD7, 0x4D, 0x8D, 0x89, 0x29, 0xC5, 0xF4 };
|
||||
sceNpDrmIsAvailable( &key, path );
|
||||
|
||||
id = sys_prx_load_module(path, 0, NULL);
|
||||
if (id < CELL_OK)
|
||||
{
|
||||
PS3PRXLOADDIAGNOSTIC("sys_prx_load_module failed: %s [0x%08x]\n", path, id);
|
||||
return id;
|
||||
}
|
||||
PS3PRXLOADDIAGNOSTIC("PRX MODULE LOADED: %s [0x%08X]\n", path, id);
|
||||
|
||||
if ( npInit != SCE_NP_ERROR_ALREADY_INITIALIZED )
|
||||
{
|
||||
sceNpTerm();
|
||||
}
|
||||
|
||||
params->sysPrxId = id;
|
||||
res = sys_prx_start_module(id, params->cbSize, params, &modres, 0, NULL);
|
||||
if (res < CELL_OK)
|
||||
{
|
||||
PS3PRXLOADDIAGNOSTIC("sys_prx_start_module failed: %s [0x%08x]\n", path, res);
|
||||
return res;
|
||||
}
|
||||
PS3PRXLOADDIAGNOSTIC("PRX MODULE STARTED: %s [0x%08X 0x%08X]\n", path, id, res);
|
||||
|
||||
//
|
||||
// Add to the loaded list
|
||||
//
|
||||
|
||||
if ( void *pvEntry = malloc( sizeof( PS3_PrxModuleEntry_t ) + params->cbSize ) )
|
||||
{
|
||||
PS3_PrxModuleEntry_t *pPrxEntry = ( PS3_PrxModuleEntry_t * ) pvEntry;
|
||||
pPrxEntry->pNextModule = *ppPrxModulesList;
|
||||
*ppPrxModulesList = pPrxEntry;
|
||||
strncpy( pPrxEntry->chName, path, sizeof( pPrxEntry->chName ) );
|
||||
pPrxEntry->uiRefCount = 1;
|
||||
memcpy( pPrxEntry->prxParams, params, params->cbSize );
|
||||
}
|
||||
|
||||
return modres;
|
||||
}
|
||||
|
||||
inline int PS3_PrxUnload( sys_prx_id_t id )
|
||||
{
|
||||
PS3_PrxModuleEntry_t ** ppPrxModulesList = PS3_PrxGetModulesList();
|
||||
|
||||
//
|
||||
// Walk the loaded list
|
||||
//
|
||||
|
||||
for ( PS3_PrxModuleEntry_t *pEntry = *ppPrxModulesList, **ppFromPrevEntry = ppPrxModulesList;
|
||||
pEntry; ppFromPrevEntry = &pEntry->pNextModule, pEntry = pEntry->pNextModule )
|
||||
{
|
||||
if ( pEntry->prxParams->sysPrxId != id )
|
||||
continue;
|
||||
|
||||
if ( -- pEntry->uiRefCount )
|
||||
{
|
||||
PS3PRXLOADDIAGNOSTIC("PRX MODULE RELREF: %s [0x%08X] (refs=%u)\n", pEntry->chName, pEntry->prxParams->sysPrxId, pEntry->uiRefCount);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
PS3PRXLOADDIAGNOSTIC("PRX MODULE UNLOAD: %s [0x%08X]\n", pEntry->chName, pEntry->prxParams->sysPrxId, pEntry->uiRefCount);
|
||||
*ppFromPrevEntry = pEntry->pNextModule;
|
||||
free( pEntry );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Perform the system unload process
|
||||
//
|
||||
|
||||
int modres;
|
||||
int res;
|
||||
|
||||
res = sys_prx_stop_module(id, 0, NULL, &modres, 0, NULL);
|
||||
if (res < CELL_OK)
|
||||
{
|
||||
PS3PRXLOADDIAGNOSTIC("sys_prx_stop_module failed: id=0x%08x, 0x%08x\n", id, res);
|
||||
return res;
|
||||
}
|
||||
PS3PRXLOADDIAGNOSTIC("PRX MODULE STOPPED: id=0x%08x, 0x%08x\n", id, res);
|
||||
|
||||
res = sys_prx_unload_module(id, 0, NULL);
|
||||
if (res < CELL_OK)
|
||||
{
|
||||
PS3PRXLOADDIAGNOSTIC("sys_prx_unload_module failed: id=0x%08X, 0x%08x\n", id, res);
|
||||
return res;
|
||||
}
|
||||
PS3PRXLOADDIAGNOSTIC("PRX MODULE UNLOADED: id=0x%08x, 0x%08x\n", id, res);
|
||||
|
||||
return modres;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// DEFINITION OF BASIC APPSYSTEM PRX IMPLEMENTATION
|
||||
//
|
||||
//
|
||||
#include "ps3_changelistver.h"
|
||||
#ifndef PS3CLVERMAJOR
|
||||
#define PS3CLVERMAJOR ((APPCHANGELISTVERSION / 256) % 256)
|
||||
#define PS3CLVERMINOR (APPCHANGELISTVERSION % 256)
|
||||
#endif
|
||||
|
||||
#ifdef _DEBUG
|
||||
#define PS3_PRX_SYS_MODULE_INFO_FULLMACROREPLACEMENTHELPER(ps3modulename) SYS_MODULE_INFO( ps3modulename##_dbg, 0, PS3CLVERMAJOR, PS3CLVERMINOR)
|
||||
#else
|
||||
#define PS3_PRX_SYS_MODULE_INFO_FULLMACROREPLACEMENTHELPER(ps3modulename) SYS_MODULE_INFO( ps3modulename##_rel, 0, PS3CLVERMAJOR, PS3CLVERMINOR)
|
||||
#endif
|
||||
|
||||
#define PS3_PRX_SYS_MODULE_START_NAME_FULLMACROREPLACEMENTHELPER(ps3modulename) _##ps3modulename##_ps3_prx_entry
|
||||
|
||||
#define PS3_PRX_APPSYSTEM_MODULE( ps3modulename ) \
|
||||
\
|
||||
PS3_PRX_SYS_MODULE_INFO_FULLMACROREPLACEMENTHELPER( ps3modulename ); \
|
||||
SYS_MODULE_START( PS3_PRX_SYS_MODULE_START_NAME_FULLMACROREPLACEMENTHELPER( ps3modulename ) ); \
|
||||
\
|
||||
extern "C" int PS3_PRX_SYS_MODULE_START_NAME_FULLMACROREPLACEMENTHELPER( ps3modulename )( unsigned int args, void *pArg ) \
|
||||
{ \
|
||||
Assert( args >= sizeof( PS3_LoadAppSystemInterface_Parameters_t ) ); \
|
||||
PS3_LoadAppSystemInterface_Parameters_t *pParams = reinterpret_cast< PS3_LoadAppSystemInterface_Parameters_t * >( pArg ); \
|
||||
Assert( pParams->cbSize >= sizeof( PS3_LoadAppSystemInterface_Parameters_t ) ); \
|
||||
pParams->pfnCreateInterface = CreateInterface; \
|
||||
return SYS_PRX_RESIDENT; \
|
||||
} \
|
||||
|
||||
//
|
||||
//
|
||||
// END DEFINITION OF BASIC APPSYSTEM PRX IMPLEMENTATION
|
||||
//
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#endif // __PS3_HELPERS__
|
||||
43
common/ps3/ps3_launch.h
Normal file
43
common/ps3/ps3_launch.h
Normal file
@@ -0,0 +1,43 @@
|
||||
//========= Copyright © 1996-2005, Valve LLC, All rights reserved. ============
|
||||
//
|
||||
// Purpose: Common XBox Launch data passed between apps
|
||||
//
|
||||
//=============================================================================
|
||||
#include "ps3_platform.h"
|
||||
|
||||
#define RELAUNCH_MAGIC_NUMBER 0xbd122969
|
||||
|
||||
// used to hold persistent states across restart
|
||||
struct RelaunchHeader_t
|
||||
{
|
||||
unsigned int magicNumber;
|
||||
unsigned int contextCode; // the context code that was used
|
||||
unsigned int nBytesRelaunchData;
|
||||
unsigned int activeDevice; // which controller was active
|
||||
__int64 startTime; // used to track duration of relaunch
|
||||
bool bRetail; // running as retail mode
|
||||
bool bInDebugger; // in debug session
|
||||
};
|
||||
|
||||
#pragma pack()
|
||||
|
||||
#define GetRelaunchHeader( x ) (((RelaunchHeader_t *)(((unsigned int)(x)) + MAX_LAUNCH_DATA_SIZE / 2)) - 1)
|
||||
|
||||
// a context code is passed to installer or dashboard
|
||||
// the dashboard passes the context code to the installer
|
||||
// installer exits and launches HL2 with RelaunchHeader
|
||||
#define CONTEXTCODE_HL2MAGIC 0x9E000000
|
||||
#define CONTEXTCODE_MAGICMASK 0xFF000000
|
||||
// xbe image type
|
||||
#define CONTEXTCODE_DEBUG_XBE 0x00000001 // running the debug xbe
|
||||
#define CONTEXTCODE_RELEASE_XBE 0x00000002 // running the release xbe
|
||||
#define CONTEXTCODE_RETAIL_XBE 0x00000004 // running the retail xbe
|
||||
// mode options
|
||||
#define CONTEXTCODE_RETAIL_MODE 0x00000010 // running the desired xbe in retail mode
|
||||
#define CONTEXTCODE_INDEBUGGER 0x00000020 // running during a debugger session
|
||||
#define CONTEXTCODE_NO_XBDM 0x00000040 // No XBDM calls
|
||||
// operation commands
|
||||
#define CONTEXTCODE_DASHBOARD 0x00010000 // pass through immediately to hl2
|
||||
#define CONTEXTCODE_ATTRACT 0x00020000 // run the attract mode
|
||||
#define CONTEXTCODE_LOADMAP 0x00040000 // restart directly to load a map
|
||||
#define CONTEXTCODE_QUIT 0x00080000 // quit game, go directly to main menu
|
||||
202
common/ps3/ps3_platform.h
Normal file
202
common/ps3/ps3_platform.h
Normal file
@@ -0,0 +1,202 @@
|
||||
//========= Copyright © 1996-2004, Valve LLC, All rights reserved. ============
|
||||
//
|
||||
// Purpose: PS/3 Platform include
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================
|
||||
|
||||
#ifndef _PS3_PLATFORM_H
|
||||
#define _PS3_PLATFORM_H
|
||||
|
||||
//EAPS3 #undef Verify // can't use verify, because there's a Verify member of struct D3DPushBuffer
|
||||
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <wchar.h>
|
||||
#include <string.h> // needed for memset
|
||||
|
||||
//EAPS3: Defines of win32 types used in Visual Studio.
|
||||
typedef void VOID;
|
||||
typedef const void * LPCVOID;
|
||||
typedef unsigned long DWORD;
|
||||
typedef DWORD * LPDWORD;
|
||||
typedef int BOOL;
|
||||
typedef int * LPBOOL;
|
||||
typedef unsigned short WORD;
|
||||
typedef float FLOAT;
|
||||
typedef short SHORT;
|
||||
typedef long LONG;
|
||||
typedef char CHAR;
|
||||
typedef unsigned int UINT;
|
||||
typedef unsigned long ULONG;
|
||||
typedef unsigned char BYTE;
|
||||
typedef BYTE* LPBYTE;
|
||||
typedef long long DWORDLONG;
|
||||
|
||||
typedef void* PVOID;
|
||||
typedef int DWORD_PTR;
|
||||
typedef int ULONG_PTR;
|
||||
typedef long* LONG_PTR;
|
||||
typedef unsigned int* UINT_PTR;
|
||||
typedef WORD* LPWORD;
|
||||
typedef ULONG_PTR * PDWORD_PTR;
|
||||
typedef ULONG_PTR SIZE_T;
|
||||
typedef ULONG_PTR * PSIZE_T;
|
||||
|
||||
typedef wchar_t WCHAR;
|
||||
typedef CHAR TCHAR;
|
||||
|
||||
typedef const char* LPCSTR;
|
||||
typedef char* LPSTR;
|
||||
typedef LPSTR LPTSTR;
|
||||
typedef const char* LPCTSTR;
|
||||
typedef const wchar_t* LPCWSTR;
|
||||
typedef WCHAR * LPWSTR;
|
||||
typedef WCHAR * PWSTR;
|
||||
|
||||
typedef void* HICON;
|
||||
typedef void* HCURSOR;
|
||||
typedef void* HBRUSH;
|
||||
typedef void* HMENU;
|
||||
typedef void* HFONT;
|
||||
typedef void* HBITMAP;
|
||||
|
||||
typedef DWORD COLORREF;
|
||||
typedef void* HINSTANCE;
|
||||
typedef UINT MMRESULT;
|
||||
typedef long HRESULT;
|
||||
typedef long LRESULT;
|
||||
typedef void* HANDLE;
|
||||
//typedef void* HWND;
|
||||
typedef void* LPVOID;
|
||||
typedef unsigned int WPARAM;
|
||||
typedef int LPARAM;
|
||||
typedef void* HDC;
|
||||
typedef void* HHOOK;
|
||||
typedef void* HMODULE;
|
||||
typedef void* HKL;
|
||||
typedef void* HKEY;
|
||||
typedef HKEY* PHKEY;
|
||||
typedef void* HGDIOBJ;
|
||||
typedef WORD ATOM;
|
||||
typedef HANDLE HGLOBAL;
|
||||
//typedef WORD WAVEFORMATEX;
|
||||
|
||||
typedef long long __int64;
|
||||
|
||||
typedef float vec3_t[3];
|
||||
typedef signed long long s64_t;
|
||||
typedef unsigned long long u64_t;
|
||||
typedef signed int s32_t;
|
||||
typedef unsigned int u32_t;
|
||||
typedef signed short s16_t;
|
||||
typedef unsigned short u16_t;
|
||||
typedef signed char s8_t;
|
||||
typedef unsigned char u8_t;
|
||||
typedef unsigned char byte_t;
|
||||
typedef unsigned int rgba_t;
|
||||
|
||||
typedef long long ULARGE_INTEGER;
|
||||
|
||||
typedef u64_t ULONGLONG;
|
||||
|
||||
typedef struct _POINTL /* ptl */
|
||||
{
|
||||
LONG x;
|
||||
LONG y;
|
||||
} POINT, POINTL, *PPOINTL, *LPPOINT;
|
||||
|
||||
typedef struct _GUID
|
||||
{
|
||||
unsigned long Data1;
|
||||
unsigned short Data2;
|
||||
unsigned short Data3;
|
||||
unsigned char Data4[8];
|
||||
} GUID;
|
||||
|
||||
typedef struct tagRECT
|
||||
{
|
||||
LONG left;
|
||||
LONG top;
|
||||
LONG right;
|
||||
LONG bottom;
|
||||
} RECT, *PRECT, *NPRECT, *LPRECT;
|
||||
|
||||
typedef struct _FILETIME {
|
||||
DWORD dwLowDateTime;
|
||||
DWORD dwHighDateTime;
|
||||
} FILETIME, *PFILETIME, *LPFILETIME;
|
||||
|
||||
typedef struct _SECURITY_ATTRIBUTES
|
||||
{
|
||||
DWORD nLength;
|
||||
/* [size_is] */ LPVOID lpSecurityDescriptor;
|
||||
BOOL bInheritHandle;
|
||||
} SECURITY_ATTRIBUTES;
|
||||
|
||||
typedef struct _SECURITY_ATTRIBUTES *LPSECURITY_ATTRIBUTES;
|
||||
|
||||
// Function call convention
|
||||
#define _cdecl
|
||||
#define __cdecl
|
||||
#define __declspec(x)
|
||||
|
||||
#define WINAPI
|
||||
#define FAR
|
||||
#define NEAR
|
||||
#define CONST const
|
||||
#define CALLBACK
|
||||
#define IN
|
||||
#define OPTIONAL
|
||||
|
||||
struct PDM_CMDCONT
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
#ifndef __stdcall
|
||||
#define __stdcall
|
||||
#endif
|
||||
//typedef HRESULT (__stdcall *PDM_CMDPROC)(LPCSTR szCommand, LPSTR szResponse, DWORD cchResponse, PDM_CMDCONT pdmcc);
|
||||
#undef __stdcall
|
||||
|
||||
typedef int (*PROC)();
|
||||
typedef int (*FARPROC)();
|
||||
typedef int (*NEARPROC)();
|
||||
|
||||
#define FAILED(x) (x < 0)
|
||||
|
||||
//EAPS3: Copied from malloc.h in Visual Studio.
|
||||
#define _HEAPEMPTY (-1)
|
||||
#define _HEAPOK (-2)
|
||||
#define _HEAPBADBEGIN (-3)
|
||||
#define _HEAPBADNODE (-4)
|
||||
#define _HEAPEND (-5)
|
||||
#define _HEAPBADPTR (-6)
|
||||
#define _FREEENTRY 0
|
||||
#define _USEDENTRY 1
|
||||
|
||||
// use for api's 'ignored' params for clarity
|
||||
#define XBOX_DONTCARE 0
|
||||
|
||||
// trap debugging output
|
||||
#define OutputDebugString(v) printf(v);
|
||||
|
||||
// not defined in ps3_system.cpp.
|
||||
// DWORD GetTickCount();
|
||||
|
||||
// this comment means nothing
|
||||
|
||||
#define LOWORD(l) ((WORD)((DWORD_PTR)(l) & 0xffff))
|
||||
#define HIWORD(l) ((WORD)((DWORD_PTR)(l) >> 16))
|
||||
#define S_OK ((HRESULT)0x00000000L)
|
||||
|
||||
#ifndef _strnicmp
|
||||
#define _strnicmp Q_strncasecmp
|
||||
#endif
|
||||
|
||||
#ifndef wcsnicmp
|
||||
// ???
|
||||
#endif
|
||||
|
||||
#endif
|
||||
7
common/ps3/ps3_psgl_valve.h
Normal file
7
common/ps3/ps3_psgl_valve.h
Normal file
@@ -0,0 +1,7 @@
|
||||
|
||||
#ifndef _PS3_PSGL_VALVE_H_
|
||||
#define _PS3_PSGL_VALVE_H_
|
||||
|
||||
#define GL_VALVE_WRITE_ONLY_NO_OVERWRITE 0x88BB
|
||||
|
||||
#endif // _PS3_PSGL_VALVE_H_
|
||||
39
common/ps3/ps3_rtti.h
Normal file
39
common/ps3/ps3_rtti.h
Normal file
@@ -0,0 +1,39 @@
|
||||
#ifndef __PS3_RTTI__
|
||||
#define __PS3_RTTI__
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
namespace ps3_rtti
|
||||
{
|
||||
template<class Klass>
|
||||
class type_trait
|
||||
{
|
||||
private:
|
||||
static const size_t m_nameSize=16;
|
||||
|
||||
public:
|
||||
static const int m_typeTag;
|
||||
static char m_name[m_nameSize];
|
||||
static int TypeInfo() {return int(&m_typeTag);}
|
||||
static const char* TypeName()
|
||||
{
|
||||
snprintf(m_name,m_nameSize,"%x",TypeInfo());
|
||||
return m_name;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#define TYPE_INFO int
|
||||
#define TYPEID(t) ps3_rtti::type_trait<t>::TypeInfo()
|
||||
#define TYPENAME(t) ps3_rtti::type_trait<t>::TypeName()
|
||||
#define TYPE_INFO_EQUAL(i1, i2) i1 == i2
|
||||
#define INSTANCTIATE_TYPE(t) \
|
||||
namespace ps3_rtti \
|
||||
{ \
|
||||
template <> const int type_trait<t>::m_typeTag=0; \
|
||||
template <> char type_trait<t>::m_name[16] = ""; \
|
||||
}
|
||||
|
||||
#define INVALID_TYPE_INFO int(0)
|
||||
|
||||
#endif
|
||||
24
common/ps3/ps3_sn.h
Normal file
24
common/ps3/ps3_sn.h
Normal file
@@ -0,0 +1,24 @@
|
||||
//========= Copyright © , Valve LLC, All rights reserved. ============
|
||||
//
|
||||
// These are the workarounds for snTuner inability to patch prx'es,
|
||||
// as well as access prx symbols after attaching to a running game
|
||||
// snTuner functions are exposed through pointers to functions in ELF
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
#ifndef VALVE_PS3_SN_HDR
|
||||
#define VALVE_PS3_SN_HDR
|
||||
|
||||
// Currently these are only defined on PS3, but there's no harm in declaring them on other platforms
|
||||
|
||||
|
||||
#ifdef _PS3
|
||||
extern "C" void(*g_pfnPushMarker)( const char * pName );
|
||||
extern "C" void(*g_pfnPopMarker)();
|
||||
extern "C" void(*g_pfnSwapBufferMarker)();
|
||||
#else
|
||||
inline void g_pfnPushMarker( const char * pName ){}
|
||||
inline void g_pfnPopMarker(){}
|
||||
inline void g_pfnSwapBufferMarker(){}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
203
common/ps3/ps3_vxconsole.h
Normal file
203
common/ps3/ps3_vxconsole.h
Normal file
@@ -0,0 +1,203 @@
|
||||
//========= Copyright © 1996-2007, Valve LLC, All rights reserved. ============
|
||||
//
|
||||
// Purpose: PS3 VXConsole Common. Used for public remote access items and types.
|
||||
//
|
||||
//=============================================================================
|
||||
#ifndef PS3_VXCONSOLE_H
|
||||
#define PS3_VXCONSOLE_H
|
||||
#pragma once
|
||||
|
||||
|
||||
//PS3
|
||||
|
||||
// sent during connection, used to explicitly guarantee a binary compatibility
|
||||
#define VXCONSOLE_PROTOCOL_VERSION 0x1001 // also used for the LPAR protocol number
|
||||
#define VXCONSOLE_PROTOCOL_PORT 0
|
||||
#define VXCONSOLE_PS3 1
|
||||
|
||||
|
||||
|
||||
#define VXCONSOLE_TTY_STREAM 13
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char labelString[64];
|
||||
COLORREF color;
|
||||
} xrProfile_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char messageString[256];
|
||||
float time;
|
||||
float deltaTime;
|
||||
size_t memory;
|
||||
int deltaMemory;
|
||||
} xrTimeStamp_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char nameString[256];
|
||||
char shaderString[256];
|
||||
int refCount;
|
||||
} xrMaterial_t;
|
||||
|
||||
enum cacheableState_e
|
||||
{
|
||||
CS_STATIC = 0, // texture is not lru managed
|
||||
CS_EVICTED, // texture mip0 is not in memory
|
||||
CS_LOADING, // texture mip0 is loading
|
||||
CS_VALID, // texture mip0 is valid for rendering
|
||||
CS_MAX
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char nameString[256];
|
||||
char groupString[64];
|
||||
char formatString[64];
|
||||
int size;
|
||||
int width;
|
||||
int height;
|
||||
int depth;
|
||||
int numLevels;
|
||||
int binds;
|
||||
int refCount;
|
||||
int sRGB;
|
||||
int edram;
|
||||
int procedural;
|
||||
int cacheableState;
|
||||
int cacheableSize : 31; // Packing avoids game-to-vxconsole protocol version conflict
|
||||
uint final : 1;
|
||||
int failed;
|
||||
int pwl;
|
||||
int reduced;
|
||||
} xrTexture_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char nameString[256];
|
||||
char formatString[64];
|
||||
int rate;
|
||||
int bits;
|
||||
int channels;
|
||||
int looped;
|
||||
int dataSize;
|
||||
int numSamples;
|
||||
int streamed;
|
||||
int quality;
|
||||
} xrSound_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char nameString[128];
|
||||
char helpString[256];
|
||||
} xrCommand_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
float position[3];
|
||||
float angle[3];
|
||||
char mapPath[256];
|
||||
char savePath[256];
|
||||
int build;
|
||||
int skill;
|
||||
char details[1024];
|
||||
} xrMapInfo_t;
|
||||
|
||||
struct xrModel_t
|
||||
{
|
||||
char nameString[256];
|
||||
int dataSize;
|
||||
int numVertices;
|
||||
int triCount;
|
||||
int dataSizeLod0;
|
||||
int numVerticesLod0;
|
||||
int triCountLod0;
|
||||
int numBones;
|
||||
int numParts;
|
||||
int numLODs;
|
||||
int numMeshes;
|
||||
};
|
||||
|
||||
|
||||
struct xModelList_t
|
||||
{
|
||||
char name[MAX_PATH];
|
||||
int dataSize;
|
||||
int numVertices;
|
||||
int triCount;
|
||||
int dataSizeLod0;
|
||||
int numVerticesLod0;
|
||||
int triCountLod0;
|
||||
int numBones;
|
||||
int numParts;
|
||||
int numLODs;
|
||||
int numMeshes;
|
||||
};
|
||||
|
||||
|
||||
struct xrDataCacheItem_t
|
||||
{
|
||||
char nameString[256];
|
||||
char sectionString[64];
|
||||
int size;
|
||||
int lockCount;
|
||||
unsigned int clientId;
|
||||
unsigned int itemData;
|
||||
unsigned int handle;
|
||||
};
|
||||
|
||||
struct xrVProfNodeItem_t
|
||||
{
|
||||
char nameString[128];
|
||||
char budgetGroupString[128];
|
||||
unsigned int budgetGroupColor;
|
||||
unsigned int totalCalls;
|
||||
double inclusiveTime;
|
||||
double exclusiveTime;
|
||||
};
|
||||
|
||||
|
||||
struct xDataCacheItem_t
|
||||
{
|
||||
char name[MAX_PATH];
|
||||
char section[64];
|
||||
int size;
|
||||
int lockCount;
|
||||
unsigned int clientId;
|
||||
unsigned int itemData;
|
||||
unsigned int handle;
|
||||
};
|
||||
|
||||
struct xVProfNodeItem_t
|
||||
{
|
||||
const char *pName;
|
||||
const char *pBudgetGroupName;
|
||||
unsigned int budgetGroupColor;
|
||||
unsigned int totalCalls;
|
||||
double inclusiveTime;
|
||||
double exclusiveTime;
|
||||
};
|
||||
|
||||
// Types of action taken in response to an rc_Assert() message
|
||||
enum AssertAction_t
|
||||
{
|
||||
ASSERT_ACTION_BREAK = 0, // Break on this Assert
|
||||
ASSERT_ACTION_IGNORE_THIS, // Ignore this Assert once
|
||||
ASSERT_ACTION_IGNORE_ALWAYS, // Ignore this Assert from now on
|
||||
ASSERT_ACTION_IGNORE_FILE, // Ignore all Asserts from this file from now on
|
||||
ASSERT_ACTION_IGNORE_ALL, // Ignore all Asserts from now on
|
||||
ASSERT_ACTION_OTHER // A more complex response requiring additional data (e.g. "ignore this Assert 5 times")
|
||||
};
|
||||
|
||||
//id's for dispatching binary notifications to proper handlers
|
||||
enum XBX_DBGBinaryNotification_HandlerID_t
|
||||
{
|
||||
XBX_DBG_BNH_STACKTRANSLATOR,
|
||||
|
||||
XBX_DBG_BNH_END,
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // PS3_VXCONSOLE_H
|
||||
1600
common/ps3/ps3_win32stubs.h
Normal file
1600
common/ps3/ps3_win32stubs.h
Normal file
File diff suppressed because it is too large
Load Diff
255
common/ps3/ps3stubs.h
Normal file
255
common/ps3/ps3stubs.h
Normal file
@@ -0,0 +1,255 @@
|
||||
//========= Copyright © 1996-2004, Valve LLC, All rights reserved. ============
|
||||
//
|
||||
// Purpose: Win32 replacements for Xbox code
|
||||
//
|
||||
//=============================================================================
|
||||
#ifndef PS3STUBS_H
|
||||
#define PS3STUBS_H
|
||||
|
||||
#include "ps3_platform.h"
|
||||
#include "tier0/platform.h"
|
||||
|
||||
// Content creation/open flags
|
||||
#define XCONTENTFLAG_NONE 0x00
|
||||
#define XCONTENTFLAG_CREATENEW 0x00
|
||||
#define XCONTENTFLAG_CREATEALWAYS 0x00
|
||||
#define XCONTENTFLAG_OPENEXISTING 0x00
|
||||
#define XCONTENTFLAG_OPENALWAYS 0x00
|
||||
#define XCONTENTFLAG_TRUNCATEEXISTING 0x00
|
||||
|
||||
// Content attributes
|
||||
#define XCONTENTFLAG_NOPROFILE_TRANSFER 0x00
|
||||
#define XCONTENTFLAG_NODEVICE_TRANSFER 0x00
|
||||
#define XCONTENTFLAG_STRONG_SIGNED 0x00
|
||||
#define XCONTENTFLAG_ALLOWPROFILE_TRANSFER 0x00
|
||||
#define XCONTENTFLAG_MOVEONLY_TRANSFER 0x00
|
||||
|
||||
#define XDEVICE_TYPE_GAMEPAD 0
|
||||
#define XDEVICE_TYPE_MEMORY_UNIT 1
|
||||
#define XDEVICE_TYPE_VOICE_MICROPHONE 2
|
||||
#define XDEVICE_TYPE_VOICE_HEADPHONE 3
|
||||
#define XDEVICE_TYPE_HIGHFIDELITY_MICROPHONE 4
|
||||
|
||||
// Constants for gamepad buttons
|
||||
#define XINPUT_GAMEPAD_DPAD_UP 0x0001
|
||||
#define XINPUT_GAMEPAD_DPAD_DOWN 0x0002
|
||||
#define XINPUT_GAMEPAD_DPAD_LEFT 0x0004
|
||||
#define XINPUT_GAMEPAD_DPAD_RIGHT 0x0008
|
||||
#define XINPUT_GAMEPAD_START 0x0010
|
||||
#define XINPUT_GAMEPAD_BACK 0x0020
|
||||
#define XINPUT_GAMEPAD_LEFT_THUMB 0x0040
|
||||
#define XINPUT_GAMEPAD_RIGHT_THUMB 0x0080
|
||||
#define XINPUT_GAMEPAD_LEFT_SHOULDER 0x0100 // AG - Shoudler buttons should correspond to BLACK and WHITE in xboxStubs.h, but they don't seem to have proper bitfield values
|
||||
#define XINPUT_GAMEPAD_RIGHT_SHOULDER 0x0200
|
||||
#define XINPUT_GAMEPAD_LEFT_TRIGGER 0x0400
|
||||
#define XINPUT_GAMEPAD_RIGHT_TRIGGER 0x0800
|
||||
#define XINPUT_GAMEPAD_A 0x1000
|
||||
#define XINPUT_GAMEPAD_B 0x2000
|
||||
#define XINPUT_GAMEPAD_X 0x4000
|
||||
#define XINPUT_GAMEPAD_Y 0x8000
|
||||
|
||||
#define XINPUT_LIGHTGUN_ONSCREEN 0x2000
|
||||
#define XINPUT_LIGHTGUN_FRAME_DOUBLER 0x4000
|
||||
#define XINPUT_LIGHTGUN_LINE_DOUBLER 0x8000
|
||||
|
||||
//#define XINPUT_GAMEPAD_LEFT_TRIGGER 6
|
||||
//#define XINPUT_GAMEPAD_RIGHT_TRIGGER 7
|
||||
|
||||
#define XDEVICE_PORT0 0
|
||||
#define XDEVICE_PORT1 1
|
||||
#define XDEVICE_PORT2 2
|
||||
#define XDEVICE_PORT3 3
|
||||
#ifdef CONTROLLER2_CHEATS_ENABLED
|
||||
#define XBX_MAX_DPORTS 2
|
||||
#else
|
||||
#define XBX_MAX_DPORTS 1
|
||||
#endif // CONTROLLER2_CHEATS_ENABLED
|
||||
|
||||
#define XDEVICE_NO_SLOT 0
|
||||
#define XDEVICE_TOP_SLOT 0
|
||||
#define XDEVICE_BOTTOM_SLOT 1
|
||||
|
||||
#define CLR_DEFAULT 0xFF000000
|
||||
#define CLR_WARNING 0x0000FFFF
|
||||
#define CLR_ERROR 0x000000FF
|
||||
|
||||
// Device types available in XINPUT_CAPABILITIES
|
||||
#define XINPUT_DEVTYPE_GAMEPAD 0x01
|
||||
#define XINPUT_DEVTYPE_USB_KEYBOARD 0x02
|
||||
|
||||
// Device subtypes available in XINPUT_CAPABILITIES
|
||||
#define XINPUT_DEVSUBTYPE_UNKNOWN 0x00
|
||||
#define XINPUT_DEVSUBTYPE_GAMEPAD 0x01
|
||||
#define XINPUT_DEVSUBTYPE_WHEEL 0x02
|
||||
#define XINPUT_DEVSUBTYPE_ARCADE_STICK 0x03
|
||||
#define XINPUT_DEVSUBTYPE_FLIGHT_STICK 0x04
|
||||
#define XINPUT_DEVSUBTYPE_DANCEPAD 0x05
|
||||
|
||||
// Flags for XINPUT_CAPABILITIES
|
||||
#define XINPUT_CAPS_FFB_SUPPORTED 0x0001
|
||||
#define XINPUT_CAPS_WIRELESS 0x0002
|
||||
#define XINPUT_CAPS_VOICE_SUPPORTED 0x0004
|
||||
#define XINPUT_CAPS_PMD_SUPPORTED 0x0008
|
||||
|
||||
// Flags for XInputGetCapabilities
|
||||
#define XINPUT_FLAG_GAMEPAD 0x00000001
|
||||
#define XINPUT_FLAG_KEYBOARD 0x00000002
|
||||
#define XINPUT_FLAG_REMOTE 0x00000004
|
||||
#define XINPUT_FLAG_ANYDEVICE 0x000000FF
|
||||
|
||||
// Gamepad thresholds
|
||||
#define XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE 7849
|
||||
#define XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE 8689
|
||||
#define XINPUT_GAMEPAD_TRIGGER_THRESHOLD 30
|
||||
|
||||
// Wind
|
||||
|
||||
|
||||
// Structures used by XInput APIs
|
||||
typedef struct _XINPUT_GAMEPAD
|
||||
{
|
||||
WORD wButtons;
|
||||
BYTE bLeftTrigger;
|
||||
BYTE bRightTrigger;
|
||||
short sThumbLX;
|
||||
short sThumbLY;
|
||||
short sThumbRX;
|
||||
short sThumbRY;
|
||||
} XINPUT_GAMEPAD, *PXINPUT_GAMEPAD;
|
||||
|
||||
typedef struct _XINPUT_STATE
|
||||
{
|
||||
DWORD dwPacketNumber;
|
||||
XINPUT_GAMEPAD Gamepad;
|
||||
} XINPUT_STATE, *PXINPUT_STATE;
|
||||
|
||||
typedef struct _XINPUT_VIBRATION
|
||||
{
|
||||
WORD wLeftMotorSpeed;
|
||||
WORD wRightMotorSpeed;
|
||||
} XINPUT_VIBRATION, *PXINPUT_VIBRATION;
|
||||
|
||||
typedef struct _XINPUT_CAPABILITIES
|
||||
{
|
||||
BYTE Type;
|
||||
BYTE SubType;
|
||||
WORD Flags;
|
||||
XINPUT_GAMEPAD Gamepad;
|
||||
XINPUT_VIBRATION Vibration;
|
||||
} XINPUT_CAPABILITIES, *PXINPUT_CAPABILITIES;
|
||||
|
||||
//typedef enum
|
||||
//{
|
||||
// XK_NULL,
|
||||
// XK_BUTTON_UP,
|
||||
// XK_BUTTON_DOWN,
|
||||
// XK_BUTTON_LEFT,
|
||||
// XK_BUTTON_RIGHT,
|
||||
// XK_BUTTON_START,
|
||||
// XK_BUTTON_BACK,
|
||||
// XK_BUTTON_STICK1,
|
||||
// XK_BUTTON_STICK2,
|
||||
// XK_BUTTON_A,
|
||||
// XK_BUTTON_B,
|
||||
// XK_BUTTON_X,
|
||||
// XK_BUTTON_Y,
|
||||
// XK_BUTTON_BLACK,
|
||||
// XK_BUTTON_WHITE,
|
||||
// XK_BUTTON_LTRIGGER,
|
||||
// XK_BUTTON_RTRIGGER,
|
||||
// XK_STICK1_UP,
|
||||
// XK_STICK1_DOWN,
|
||||
// XK_STICK1_LEFT,
|
||||
// XK_STICK1_RIGHT,
|
||||
// XK_STICK2_UP,
|
||||
// XK_STICK2_DOWN,
|
||||
// XK_STICK2_LEFT,
|
||||
// XK_STICK2_RIGHT,
|
||||
// XK_MAX_KEYS,
|
||||
//} xKey_t;
|
||||
//
|
||||
//typedef enum
|
||||
//{
|
||||
// XVRB_NONE, // off
|
||||
// XVRB_ERROR, // fatal error
|
||||
// XVRB_ALWAYS, // no matter what
|
||||
// XVRB_WARNING, // non-fatal warnings
|
||||
// XVRB_STATUS, // status reports
|
||||
// XVRB_ALL,
|
||||
//} xverbose_e;
|
||||
|
||||
typedef struct _XINPUT_RUMBLE
|
||||
{
|
||||
WORD wLeftMotorSpeed;
|
||||
WORD wRightMotorSpeed;
|
||||
} XINPUT_RUMBLE, *PXINPUT_RUMBLE;
|
||||
|
||||
#define XINPUT_FEEDBACK_HEADER_INTERNAL_SIZE 58
|
||||
typedef struct _XINPUT_FEEDBACK_HEADER
|
||||
{
|
||||
DWORD dwStatus;
|
||||
void* hEvent;
|
||||
BYTE Reserved[XINPUT_FEEDBACK_HEADER_INTERNAL_SIZE];
|
||||
} XINPUT_FEEDBACK_HEADER, *PXINPUT_FEEDBACK_HEADER;
|
||||
|
||||
typedef struct _XINPUT_FEEDBACK
|
||||
{
|
||||
XINPUT_FEEDBACK_HEADER Header;
|
||||
union
|
||||
{
|
||||
XINPUT_RUMBLE Rumble;
|
||||
};
|
||||
} XINPUT_FEEDBACK, *PXINPUT_FEEDBACK;
|
||||
|
||||
//typedef struct _XINPUT_GAMEPAD
|
||||
//{
|
||||
// WORD wButtons;
|
||||
// BYTE bAnalogButtons[8];
|
||||
// short sThumbLX;
|
||||
// short sThumbLY;
|
||||
// short sThumbRX;
|
||||
// short sThumbRY;
|
||||
//} XINPUT_GAMEPAD, *PXINPUT_GAMEPAD;
|
||||
|
||||
typedef struct _XPP_DEVICE_TYPE
|
||||
{
|
||||
unsigned long Reserved[3];
|
||||
} XPP_DEVICE_TYPE, *PXPP_DEVICE_TYPE;
|
||||
|
||||
typedef struct _XDEVICE_PREALLOC_TYPE
|
||||
{
|
||||
PXPP_DEVICE_TYPE DeviceType;
|
||||
DWORD dwPreallocCount;
|
||||
} XDEVICE_PREALLOC_TYPE, *PXDEVICE_PREALLOC_TYPE;
|
||||
|
||||
//typedef struct _XINPUT_STATE
|
||||
//{
|
||||
// DWORD dwPacketNumber;
|
||||
// XINPUT_GAMEPAD Gamepad;
|
||||
//} XINPUT_STATE, *PXINPUT_STATE;
|
||||
|
||||
typedef struct _XINPUT_POLLING_PARAMETERS
|
||||
{
|
||||
BYTE fAutoPoll:1;
|
||||
BYTE fInterruptOut:1;
|
||||
BYTE ReservedMBZ1:6;
|
||||
BYTE bInputInterval;
|
||||
BYTE bOutputInterval;
|
||||
BYTE ReservedMBZ2;
|
||||
} XINPUT_POLLING_PARAMETERS, *PXINPUT_POLLING_PARAMETERS;
|
||||
|
||||
/*EAPS3
|
||||
void XBX_DebugString(xverbose_e verbose, COLORREF color, const char* format, ...);
|
||||
void XBX_ProcessEvents(void);
|
||||
void XInitDevices(DWORD dwPreallocTypeCount, PXDEVICE_PREALLOC_TYPE PreallocTypes);
|
||||
DWORD XGetDevices(PXPP_DEVICE_TYPE DeviceType);
|
||||
bool XGetDeviceChanges(PXPP_DEVICE_TYPE DeviceType, DWORD *pdwInsertions, DWORD *pdwRemovals);
|
||||
HANDLE XInputOpen(PXPP_DEVICE_TYPE DeviceType, DWORD dwPort, DWORD dwSlot, PXINPUT_POLLING_PARAMETERS pPollingParameters);
|
||||
void XInputClose(HANDLE hDevice);
|
||||
DWORD XInputSetState(HANDLE hDevice, PXINPUT_FEEDBACK pFeedback);
|
||||
DWORD XInputGetState(HANDLE hDevice, PXINPUT_STATE pState);
|
||||
DWORD XInputPoll(HANDLE hDevice);
|
||||
unsigned int XBX_GetSystemTime(void);
|
||||
*/
|
||||
|
||||
#endif // XBOXSTUBS_H
|
||||
273
common/ps3/rsx_spu_double_ring.cpp
Normal file
273
common/ps3/rsx_spu_double_ring.cpp
Normal file
@@ -0,0 +1,273 @@
|
||||
//================ Copyright (c) 1996-2010 Valve Corporation. All Rights Reserved. =================
|
||||
//
|
||||
// Double ring buffer used for bidirectional communication between RSX and SPU
|
||||
// One ring buffer is (externally managed) jobchain(s) that call into entries in IO address space
|
||||
// that RSX patches (changing from JTS to RET). The other ring buffer is supposedly in local memory
|
||||
// and is supposedly split into segments. RSX consumes the local memory buffer, and releases it
|
||||
// segment-by-segment. SPU runs ahead of it and produces the segments and notifies the RSX
|
||||
// using JTS external to the classes here
|
||||
//
|
||||
//
|
||||
#include <cell/spurs.h>
|
||||
#include "ps3/dxabstract_gcm_shared.h"
|
||||
#include "ps3/rsx_spu_double_ring.h"
|
||||
#include "ps3/vjobchain4.h"
|
||||
#include "vjobs/pcring.h"
|
||||
#include "ps3/ps3gcmlabels.h"
|
||||
|
||||
// Can be LWSYNC or NOP if followed by RET
|
||||
// Must be RET otherwise
|
||||
// JTS->LWSYNC mutation allows for only 4-byte inline transfer from RSX, guaranteeing atomicity
|
||||
#define MUTABLE_GUARD_COMMAND CELL_SPURS_JOB_COMMAND_LWSYNC
|
||||
|
||||
#ifndef SPU
|
||||
void RsxSpuDoubleRing::SetIoBuffer( void * pIoBuffer, uint nIoBufferByteSize )
|
||||
{
|
||||
m_pIoBuffer = ( IoBufferEntry_t * )pIoBuffer;
|
||||
m_nIoBufferNextIndex = 0;
|
||||
m_nIoBufferCount = nIoBufferByteSize / sizeof( *m_pIoBuffer );
|
||||
Assert( !( m_nIoBufferCount & ( m_nIoBufferCount - 1 ) ) );
|
||||
|
||||
// Don't initialize if IO buffer is being measured
|
||||
if ( !m_pIoBuffer )
|
||||
return;
|
||||
// init all to RET, which means it's released and most of them ready to be reused
|
||||
for( int i = 0; i < m_nIoBufferCount; ++i )
|
||||
{
|
||||
m_pIoBuffer[i].m_nMutableGuard = MUTABLE_GUARD_COMMAND;
|
||||
m_pIoBuffer[i].m_nConstRet = CELL_SPURS_JOB_COMMAND_RET;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void RsxSpuDoubleRing::OnGcmInit( uint nIoBufferOffsetDelta )
|
||||
{
|
||||
m_nIoBufferOffsetDelta = nIoBufferOffsetDelta;
|
||||
}
|
||||
|
||||
|
||||
void RsxSpuDoubleRing::SetRsxBuffer( void * eaRsxBuffer, uint nRsxBufferSize, uint nIdealSegmentSize, uint nMaxJobsPerSegment )
|
||||
{
|
||||
if( nIdealSegmentSize & ( nIdealSegmentSize - 1 ) )
|
||||
{
|
||||
Error( "RsxSpuDoubleRing: invalid ideal segment size %d, must be a power of 2\n", nIdealSegmentSize );
|
||||
}
|
||||
if( nIdealSegmentSize > nRsxBufferSize / 2 )
|
||||
{
|
||||
Error( "RsxSpuDoubleRing: invalid ideal segment size %d (full buffer size %d), must be at most half the buffer size", nIdealSegmentSize, nRsxBufferSize );
|
||||
}
|
||||
|
||||
m_nMaxSegmentsPerRing = nRsxBufferSize / MIN( nIdealSegmentSize, nMaxJobsPerSegment * 128 );
|
||||
|
||||
if( m_nIoBufferCount < /*ARRAYSIZE( m_pIoBaseGuards )*/4 * m_nMaxSegmentsPerRing ) // + 1 for the initial slot
|
||||
{
|
||||
Error( "RsxSpuDoubleRing: IO buffer is too small: there may be up to %d segments per ring, and there are only %d IO guard (JTS-RET) elements. Make IO buffer at least %u bytes large.\n", m_nMaxSegmentsPerRing, m_nIoBufferCount, 4 * m_nMaxSegmentsPerRing * sizeof( *m_pIoBuffer ) );
|
||||
}
|
||||
|
||||
m_nIdealSegmentSize = nIdealSegmentSize;
|
||||
m_nMaxJobsPerSegment = nMaxJobsPerSegment;
|
||||
|
||||
|
||||
m_eaRsxBuffer = ( uintp )eaRsxBuffer;
|
||||
m_eaRsxBufferEnd = m_eaRsxBuffer + nRsxBufferSize;
|
||||
|
||||
m_nIoBufferNextIndex = 0;
|
||||
m_nRingRsxNextSegment = 0; // consider the rsx ring already done
|
||||
|
||||
// nothing is allocated by SPU
|
||||
m_eaRingSpuBase = m_eaRsxBufferEnd;
|
||||
// we consider that the last segment was signaled beyond the end of this segment
|
||||
m_eaRingSpuLastSegment = m_eaRsxBufferEnd;
|
||||
|
||||
m_nRingSpuJobCount = 0;
|
||||
|
||||
// this segment is for reference to the bottom of rsx buffer only
|
||||
// the whole RSX buffer is free for SPU to use
|
||||
m_eaRingRsxBase = m_eaRsxBuffer;
|
||||
|
||||
m_ringSpu.EnsureCapacity( m_nMaxSegmentsPerRing );
|
||||
m_ringRsx.EnsureCapacity( m_nMaxSegmentsPerRing );
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void RsxSpuDoubleRing::InternalGuardAndLock( VjobChain4 * pSyncChain, uintp eaRsxMem )
|
||||
{
|
||||
if( m_nRingRsxNextSegment >= m_ringRsx.Count() )
|
||||
{
|
||||
// if we exhausted all RSX ring segments, it only may mean that m_eaRingRsxBase == m_eaRsxBuffer, so this can not happen
|
||||
VjobSpuLog(
|
||||
"RsxSpuDoubleRing::InternalGuardAndLock: Unexpected error in RSX-SPU double ring, something's very wrong\n"
|
||||
"Please tell Sergiy the following numbers: %d,%d,%d,%d. @%X,@%X\n",
|
||||
m_nRingRsxNextSegment, m_ringRsx.Count(), m_ringSpu.Count(), m_ringSpu.GetCapacity(),
|
||||
m_eaRingRsxBase, m_eaRingSpuBase
|
||||
);
|
||||
}
|
||||
|
||||
// the next most common case when we have to wait for RSX: we don't have to switch the ring because there's plenty of space still available
|
||||
// find the next segment to wait for ( may skip several segments )
|
||||
|
||||
Assert( m_nRingRsxNextSegment < m_ringRsx.Count() );
|
||||
Segment_t segment;
|
||||
|
||||
if( m_nRingRsxNextSegment >= m_ringRsx.Count() || m_ringSpu.Count() >= m_ringSpu.GetCapacity() )
|
||||
{
|
||||
VjobSpuLog(
|
||||
"RsxSpuDoubleRing::InternalGuardAndLock() hit an error condition, but will try to continue\n"
|
||||
"Please tell Sergiy the following numbers: %d>=%d|%d>=%d. @%X,@%X\n",
|
||||
m_nRingRsxNextSegment, m_ringRsx.Count(), m_ringSpu.Count(), m_ringSpu.GetCapacity(),
|
||||
m_eaRingRsxBase, m_eaRingSpuBase
|
||||
);
|
||||
}
|
||||
|
||||
for( ; ; )
|
||||
{
|
||||
segment = m_ringRsx[m_nRingRsxNextSegment++];
|
||||
Assert( segment.m_eaBase < m_eaRingRsxBase );
|
||||
if( eaRsxMem >= segment.m_eaBase )
|
||||
{
|
||||
break; // we found the segment to wait on
|
||||
}
|
||||
if( m_nRingRsxNextSegment >= m_ringRsx.Count() )
|
||||
{
|
||||
// we exhausted all segments in the ring, so wait for the last segment and assume that'll be the end of this ring
|
||||
segment.m_eaBase = m_eaRsxBuffer;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// we either found the segment to wait on here, or exhausted all segments from the RSX ring.
|
||||
// even if we exhausted all segments, it still means we found the LAST segment and we'll use that segment as the guard
|
||||
|
||||
uint64 * eaCall = pSyncChain->Push( ); // wait for the RSX to finish rendering from this memory before writing into it
|
||||
VjobDmaPutfUint64( CELL_SPURS_JOB_COMMAND_CALL( segment.m_pSpuJts ), (uint32)eaCall, VJOB_IOBUFFER_DMATAG );
|
||||
|
||||
m_eaRingSpuBase = eaRsxMem;
|
||||
m_eaRingRsxBase = segment.m_eaBase;
|
||||
}
|
||||
|
||||
|
||||
// Important side effects: may add to m_ringSpu
|
||||
void RsxSpuDoubleRing::InternalSwitchRing( VjobChain4 * pSyncChain )
|
||||
{
|
||||
// if we haven't already, we need to wait for the segment 0 to avoid racing over it with SPU (to ensure serialization)
|
||||
if( m_nRingRsxNextSegment < m_ringRsx.Count() )
|
||||
{
|
||||
// this should be a very rare occurence, because we don't normally jump across multiple segments; usually we have many allocations in a single segment
|
||||
uint64 * eaCall = pSyncChain->Push( );
|
||||
VjobDmaPutfUint64( CELL_SPURS_JOB_COMMAND_CALL( m_ringRsx.Tail().m_pSpuJts ), (uint32)eaCall, VJOB_IOBUFFER_DMATAG );
|
||||
}
|
||||
|
||||
if( m_eaRingSpuBase < m_eaRingSpuLastSegment )
|
||||
{
|
||||
// since the last segment was created, there were allocations. Create a new segment to sync up to those allocations
|
||||
Assert( m_eaRsxBuffer <= m_eaRingSpuBase );
|
||||
m_eaRingSpuBase = m_eaRsxBuffer;
|
||||
CommitSpuSegment( );
|
||||
}
|
||||
else
|
||||
{
|
||||
// since the last segment was created, there were NO allocations. Extend the last segment to include the slack we're dropping now
|
||||
m_ringSpu.Tail().m_eaBase = m_eaRsxBuffer;
|
||||
}
|
||||
|
||||
// now we switch the ring : SPU ring becomes RSX ring, RSX ring retires
|
||||
//m_ringRsx.RemoveAll();
|
||||
//m_ringRsx.Swap( m_ringSpu );
|
||||
m_ringRsx.Assign( m_ringSpu );
|
||||
m_ringSpu.RemoveAll();
|
||||
|
||||
AssertSpuMsg( m_ringRsx.Count() >= 2, "RSX ring has only %d segments! Something is very wrong with RSX-SPU double-ring\n", m_ringRsx.Count() );
|
||||
Assert( m_ringRsx.Count() < m_nMaxSegmentsPerRing );
|
||||
/*
|
||||
for( uint i = ARRAYSIZE( m_pIoBaseGuards ); i--> 1; ) // range: ARRAYSIZE( m_pIoBaseGuards ) - 1 ... 1
|
||||
{
|
||||
m_pIoBaseGuards[i] = m_pIoBaseGuards[i - 1];
|
||||
}
|
||||
m_pIoBaseGuards[0] = m_ringRsx.Tail().m_pSpuJts;
|
||||
*/
|
||||
m_eaRingSpuBase = m_eaRsxBufferEnd;
|
||||
m_eaRingSpuLastSegment = m_eaRsxBufferEnd;
|
||||
m_eaRingRsxBase = m_eaRsxBufferEnd;
|
||||
m_nRingSpuJobCount = 0;
|
||||
m_nRingRsxNextSegment = 0;
|
||||
|
||||
// IMPORTANT RSX L2 CACHE INVALIDATION POINT
|
||||
// we've run out of a ring; start a new one, invalidate the texture cache because we're using it for fragment programs and
|
||||
// the new ring will reuse the same memory which can be in RSX L2 cache, which doesn't invalidate when we DMA the new content into the new ring
|
||||
GCM_FUNC( cellGcmSetInvalidateTextureCache, CELL_GCM_INVALIDATE_TEXTURE );
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline void WaitGuard( volatile uint64 *pGuard, uint64 nValueToWaitFor )
|
||||
{
|
||||
int nAttempts = 0;
|
||||
|
||||
while( VjobDmaGetUint64( (uint)pGuard, DMATAG_SYNC, 0, 0 ) != nValueToWaitFor )
|
||||
{
|
||||
if( 100 == nAttempts++ )
|
||||
{
|
||||
VjobSpuLog( "Stall in WaitGuard : probably not enough IO buffer memory for the SPU side ring\n" );
|
||||
}
|
||||
}
|
||||
/*
|
||||
if( *pGuard != nValueToWaitFor )
|
||||
{
|
||||
g_nWaitGuardSpins++;
|
||||
extern bool g_bEnableStallWarnings;
|
||||
if( g_bEnableStallWarnings )
|
||||
{
|
||||
Warning( "Stall in WaitGuard : probably not enough IO buffer memory for the SPU side ring\n" );
|
||||
}
|
||||
while( *pGuard != nValueToWaitFor )
|
||||
{
|
||||
g_nWaitGuardSpins++;
|
||||
sys_timer_usleep( 60 );
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
// creates a new segment in SPU ring, allocates a JTS-RET guard for it, and pushes GCM command to release it
|
||||
// Assumption: the memory in eaBase and up has already been used up by RSX commands up to this point
|
||||
// Important side effects: adds to m_ringSpu
|
||||
void RsxSpuDoubleRing::CommitSpuSegment( )
|
||||
{
|
||||
// check that RSX ran away at least 2 segments ahead; this guarantees that there are no SPU jobs waiting to be unblocked by any IoBuffer guards
|
||||
volatile uint64 * pIoBaseGuard = &( m_pIoBuffer[( m_nIoBufferNextIndex + m_nMaxSegmentsPerRing * 3 ) & ( m_nIoBufferCount - 1 )].m_nMutableGuard ); //m_pIoBaseGuards[ ARRAYSIZE( m_pIoBaseGuards ) - 1 ];
|
||||
WaitGuard( pIoBaseGuard, MUTABLE_GUARD_COMMAND );
|
||||
|
||||
uint64 * eaJtsRetGuard = &( m_pIoBuffer[ ( m_nIoBufferNextIndex++ ) & ( m_nIoBufferCount - 1 ) ].m_nMutableGuard );
|
||||
Assert( VjobDmaGetUint64( ( uint )eaJtsRetGuard, DMATAG_SYNC, 0, 0 ) == MUTABLE_GUARD_COMMAND );
|
||||
VjobDmaPutfUint64( CELL_SPURS_JOB_COMMAND_JTS, (uint)eaJtsRetGuard, VJOB_IOBUFFER_DMATAG );
|
||||
|
||||
m_ringSpu.AddToTail( Segment_t( m_eaRingSpuBase, eaJtsRetGuard ) );
|
||||
|
||||
// Signal from RSX to SPU that RSX is done with this segment of local buffer and will go ahead and render using the next shader
|
||||
|
||||
void * lsCmdBufferData = NULL;
|
||||
|
||||
GCM_CTX_RESERVE( 2 + 4 + 10 + 2 + 4 ); // don't let callback insert anything between the following commands
|
||||
//GCM_FUNC( cellGcmSetWriteBackEndLabel, GCM_LABEL_DEBUG0, uintp( eaJtsRetGuard ) );
|
||||
GCM_FUNC( cellGcmSetTransferLocation, CELL_GCM_LOCATION_MAIN );
|
||||
GCM_FUNC( cellGcmSetInlineTransferPointer, uintp( eaJtsRetGuard ) + m_nIoBufferOffsetDelta, 2, &lsCmdBufferData );
|
||||
|
||||
// CELL_SPURS_JOB_OPCODE_RET (7|(14 << 3))
|
||||
|
||||
( ( uint32* )lsCmdBufferData )[0] = ( uint32( uint64( MUTABLE_GUARD_COMMAND ) >> 32 ) ); // uint64 to avoid any compiler issues
|
||||
( ( uint32* )lsCmdBufferData )[1] = ( uint32( MUTABLE_GUARD_COMMAND ) );
|
||||
|
||||
GCM_FUNC( cellGcmSetWriteTextureLabel, GCM_LABEL_DEBUG_FPCP_RING, uintp( eaJtsRetGuard ) );
|
||||
|
||||
m_eaRingSpuLastSegment = m_eaRingSpuBase;
|
||||
|
||||
m_nRingSpuJobCount = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
243
common/ps3/saverestore_ps3_api_ui.h
Normal file
243
common/ps3/saverestore_ps3_api_ui.h
Normal file
@@ -0,0 +1,243 @@
|
||||
//===== Copyright © 1996-2010, Valve Corporation, All rights reserved. ======//
|
||||
//
|
||||
// Purpose: A convenient, clean interface for communicating between UI and
|
||||
// the PS3 save system.
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//===========================================================================//
|
||||
|
||||
#ifndef PS3_SAVEUIAPI_H
|
||||
#define PS3_SAVEUIAPI_H
|
||||
|
||||
#include "threadtools.h"
|
||||
#include "ps3_pathinfo.h"
|
||||
|
||||
|
||||
class CUtlBuffer;
|
||||
|
||||
|
||||
enum eSaveOperationTag
|
||||
{
|
||||
kSAVE_TAG_UNKNOWN = 0,
|
||||
kSAVE_TAG_INITIALIZE,
|
||||
kSAVE_TAG_WRITE_STEAMINFO,
|
||||
kSAVE_TAG_WRITE_AUTOSAVE, // writing an autosave to the container
|
||||
kSAVE_TAG_READ_SAVE, // reading a save from the container
|
||||
kSAVE_TAG_WRITE_SAVE, // writing a manual save to the container
|
||||
kSAVE_TAG_READ_SCREENSHOT, // reading a screenshot from the container
|
||||
kSAVE_TAG_DELETE_SAVE, // deleting a save from the container
|
||||
};
|
||||
|
||||
|
||||
// this class will hold the result of an async operation.
|
||||
// poll JobDone() until it returns true, then you can
|
||||
// look at the other fields for what actually transpired.
|
||||
class CPS3SaveRestoreAsyncStatus
|
||||
{
|
||||
public:
|
||||
inline bool JobDone() { return !!m_bDone; }
|
||||
|
||||
inline int GetSonyReturnValue(); // will return either an error from the enum below or one of these (defined by Sony):
|
||||
/*
|
||||
CELL_SAVEDATA_RET_OK
|
||||
success
|
||||
|
||||
CELL_SAVEDATA_ERROR_CBRESULT
|
||||
Callback function returned an error
|
||||
|
||||
CELL_SAVEDATA_ERROR_ACCESS_ERROR
|
||||
HDD access error
|
||||
|
||||
CELL_SAVEDATA_ERROR_INTERNAL
|
||||
Fatal internal error
|
||||
|
||||
CELL_SAVEDATA_ERROR_PARAM
|
||||
Error in parameter to be set to utility (application bug)
|
||||
|
||||
CELL_SAVEDATA_ERROR_NOSPACE
|
||||
Insufficient free space (application bug: lack of free space must be judged and handled within the callback function)
|
||||
|
||||
CELL_SAVEDATA_ERROR_BROKEN
|
||||
Save data corrupted (modification detected, etc.)
|
||||
|
||||
CELL_SAVEDATA_ERROR_FAILURE
|
||||
Save/load of save data failed (file could not be found, etc.)
|
||||
|
||||
CELL_SAVEDATA_ERROR_BUSY
|
||||
Save data utility function was called simultaneously
|
||||
|
||||
CELL_SAVEDATA_ERROR_NOUSER
|
||||
Specified user does not exist
|
||||
|
||||
CELL_SAVEDATA_ERROR_SIZEOVER
|
||||
Exceeds the maximum size of the saved data
|
||||
|
||||
CELL_SAVEDATA_ERROR_NODATA
|
||||
Specified save data does not exist on the HDD
|
||||
|
||||
CELL_SAVEDATA_ERROR_NOTSUPPORTED
|
||||
Called in an unsupported state
|
||||
*/
|
||||
enum eSaveErrors // our own error types; not from Sony but formatted the same so as to look uniform.
|
||||
{
|
||||
CELL_SAVEDATA_ERROR_THREAD_WAS_BUSY = -11,
|
||||
CELL_SAVEDATA_ERROR_FILE_NOT_FOUND = -12, // you tried to load a file that wasn't in the container
|
||||
CELL_SAVEDATA_ERROR_WRONG_USER = -13, // tried to open or operate on a container belonging to a different user
|
||||
CELL_SAVEDATA_ERROR_NO_TOC = -14, // failed to read TOC
|
||||
CELL_SAVEDATA_ERROR_WRAPPER = -15, // a general failure somewhere in the wrapper classes.
|
||||
CELL_SAVEDATA_ERROR_NO_WORK_TO_DO = -16,
|
||||
CELL_SAVEDATA_WARNING_ASYNC_FAILSAFE = -17, // an operation completed but somehow forgot to trip the async object (so a failsafe triggered)
|
||||
|
||||
};
|
||||
|
||||
uint32 m_nCurrentOperationTag; // an arbitrary enum that you can set to whatever you like, except 0. Zero means "not doing anything."
|
||||
|
||||
int m_nSonyRetValue;
|
||||
bool m_bUseSystemDialogs; ///< when true, says that we should have the OS pop up dialogs for error conditions, rather than letting the game handle them based on the return value here.
|
||||
CInterlockedInt m_bDone;
|
||||
uint32 m_uiAdditionalDetails;
|
||||
|
||||
CPS3SaveRestoreAsyncStatus() : m_bDone(true), m_bUseSystemDialogs(false), m_nSonyRetValue(0), m_nCurrentOperationTag(kSAVE_TAG_UNKNOWN), m_uiAdditionalDetails( 0 )
|
||||
{};
|
||||
};
|
||||
|
||||
inline int CPS3SaveRestoreAsyncStatus::GetSonyReturnValue()
|
||||
{
|
||||
return m_nSonyRetValue;
|
||||
}
|
||||
|
||||
class IPS3SaveSteamInfoProvider
|
||||
{
|
||||
public:
|
||||
virtual CUtlBuffer * GetInitialLoadBuffer() = 0;
|
||||
virtual CUtlBuffer * GetSaveBufferForCommit() = 0;
|
||||
virtual CUtlBuffer * PrepareSaveBufferForCommit() = 0;
|
||||
};
|
||||
|
||||
// the interface class
|
||||
class IPS3SaveRestoreToUI : public IAppSystem
|
||||
{
|
||||
public:
|
||||
// the maximum possible size of a COMMENT field (including the terminal zero)
|
||||
enum { PS3_SAVE_COMMENT_LENGTH = 128 };
|
||||
|
||||
enum FileSecurity_t
|
||||
{
|
||||
kSECURE,
|
||||
kHACKABLE,
|
||||
kSYSTEM,
|
||||
};
|
||||
|
||||
// information about one file in the container
|
||||
struct CPS3ContainerFileInfo
|
||||
{
|
||||
|
||||
char fileName[64];
|
||||
char comment[PS3_SAVE_COMMENT_LENGTH];
|
||||
FileSecurity_t fileType;
|
||||
uint32 size; // in bytes
|
||||
time_t modtime; // modification time as a POSIX time_t
|
||||
|
||||
CPS3ContainerFileInfo() { memset(fileName, 0, sizeof(fileName)); memset(comment, 0, sizeof(comment)); }
|
||||
};
|
||||
|
||||
// the struct that gets written into by GetContainerInfo()
|
||||
struct CPS3ContainerFacts
|
||||
{
|
||||
int hddFreeSizeKB; // free size on disk IN KILOBYTES
|
||||
int sizeKB; // current size of container in kilobytes
|
||||
bool bOwnedByAnotherUser; // can't load if this is the case
|
||||
|
||||
CUtlVectorConservative< CPS3ContainerFileInfo > files;
|
||||
};
|
||||
|
||||
|
||||
struct PS3SaveGameInfo_t
|
||||
{
|
||||
PS3SaveGameInfo_t() : m_nFileTime(0) {}
|
||||
|
||||
CUtlString m_InternalName; // eg 0000005.SAV
|
||||
CUtlString m_Filename; // eg autosave.ps3.sav
|
||||
CUtlString m_ScreenshotFilename; // eg autosave.ps3.tga if one exists
|
||||
CUtlString m_Comment;
|
||||
time_t m_nFileTime;
|
||||
};
|
||||
|
||||
virtual ~IPS3SaveRestoreToUI(){};
|
||||
public:
|
||||
|
||||
/// You have to call this before doing any other save operation. In particular,
|
||||
/// there may be an error opening the container. Poll on Async, and when it's done,
|
||||
/// look in the return value to see if it succeeded, or if not, why not.
|
||||
/// When bCreateIfMissing is set, it will create a new container where none exists.
|
||||
virtual void Initialize( CPS3SaveRestoreAsyncStatus *pAsync, IPS3SaveSteamInfoProvider *pSteamInfoProvider, bool bCreateIfMissing, int nKBRequired ) = 0;
|
||||
|
||||
// Save the given file into the container. (ie /dev_hdd1/tempsave/foo.ps3.sav will
|
||||
// be written into the container as foo.ps3.sav ). You can optionally specify a second
|
||||
// file to be written at the same time, eg a screenshot, because batching two writes
|
||||
// to happen at once is far far faster than having two batches one after another.
|
||||
// ALL game progress files must be
|
||||
// written as secure; for now, even the screenshots should be, as that puts the work
|
||||
// of CRC onto the operating system.
|
||||
virtual void Write( CPS3SaveRestoreAsyncStatus *pAsync, const char *pSourcepath, const char *pScreenshotPath, const char *pComment, FileSecurity_t nSecurity = kSECURE ) = 0;
|
||||
|
||||
// A more complicated and intelligent form of save writing, specifically for the case of autosaves.
|
||||
// The source filename given (as an absolute path) will be written to "autosave.ps3.sav".
|
||||
// Meanwhile, the existing "autosave.ps3.sav" will be renamed "autosave01.ps3.sav",
|
||||
// any "autosave01.ps3.sav" will be renamed "autosave02.ps3.sav", and so on up to a maximum
|
||||
// number of autosaves N, plus the base autosave.ps3.sav. The highest "autosave%02d.ps3.sav"
|
||||
// will therefore have a number N. Excess autosaves with numbers >N will be deleted.
|
||||
// If you specify a ScreenshotExtension (such as "tga"), the same operation is performed
|
||||
// for every file above, where ."sav" is replaced with the given extension.
|
||||
virtual void WriteAutosave( CPS3SaveRestoreAsyncStatus *pAsync,
|
||||
const char *pSourcePath, // eg "/dev_hdd1/tempsave/autosave.ps3.sav"
|
||||
const char *pComment, // the comment field for the new autosave.
|
||||
const unsigned int nMaxNumAutosaves ) = 0; // should be at least 1; the highest numbered autosave will be N-1.
|
||||
|
||||
// A way of writing clouded files into container, clouded files over
|
||||
// a certain age are purged from container
|
||||
virtual void WriteCloudFile( CPS3SaveRestoreAsyncStatus *pAsync,
|
||||
const char *pSourcePath,
|
||||
const unsigned int nMaxNumCloudFiles ) = 0; // should be at least 1; the highest numbered cloud file will be N-1.
|
||||
|
||||
// Load a file from the container into the given directory.
|
||||
// give it a pointer to a CPS3SaveRestoreAsyncStatus struct that you have created and
|
||||
// intend to poll.
|
||||
virtual void Load( CPS3SaveRestoreAsyncStatus *pAsync, const char *pFilename, const char *pDestFullPath ) = 0;
|
||||
|
||||
// kill one or two files (eg, save and screenshot).
|
||||
// async will respond when done.
|
||||
virtual void Delete( CPS3SaveRestoreAsyncStatus *pAsync, const char *pFilename, const char *pOtherFilename = NULL ) = 0;
|
||||
|
||||
// synchronously retrieve information on the files in the container. Lacks some of the container-wide'
|
||||
// info of the above function, and may have slightly out of date information, but is a synchronous call
|
||||
// and returns precisely the structure needed by CBaseModPanel::GetSaveGameInfos().
|
||||
virtual void GetFileInfoSync( CUtlVector< PS3SaveGameInfo_t > &saveGameInfos, bool bFindAll ) = 0;
|
||||
|
||||
// try to find Steam's schema file for the user and stuff it into the container.
|
||||
// returns false if it couldn't find the file locally (in which case you should
|
||||
// not wait for the async object to be "done", as the job wasn't initiated);
|
||||
// true if it found it locally and queued up an async job to write it.
|
||||
virtual void WriteSteamInfo( CPS3SaveRestoreAsyncStatus *pAsync ) = 0;
|
||||
|
||||
// returns whether save thread is busy
|
||||
virtual bool IsSaveUtilBusy() = 0;
|
||||
|
||||
// returns the m_nCurrentOperationTag field of the most recent async op to
|
||||
// have run, or kSAVE_TAG_UNKNOWN if none has been enqueued yet. This tag
|
||||
// changes the moment a job is made active and remains until the next job
|
||||
// starts.
|
||||
virtual uint32 GetCurrentOpTag() = 0;
|
||||
|
||||
// returns the version of container, used to fire off events when container
|
||||
// contents changes.
|
||||
virtual uint32 GetContainerModificationVersion() = 0;
|
||||
|
||||
// sets the cloud crypto key.
|
||||
virtual void SetCloudFileCryptoKey( uint64 uiCloudCryptoKey ) = 0;
|
||||
};
|
||||
|
||||
|
||||
#define IPS3SAVEUIAPI_VERSION_STRING "IPS3SAVEUIAPI_001"
|
||||
|
||||
#endif
|
||||
90
common/ps3/spu_job_main.cpp
Normal file
90
common/ps3/spu_job_main.cpp
Normal file
@@ -0,0 +1,90 @@
|
||||
//========= Copyright © 1996-2004, Valve LLC, All rights reserved. ============
|
||||
//
|
||||
// This common file serves as redirection to make minimal SPU-only preparation
|
||||
// of a job and call into its Main function. The Main function is hidden behind
|
||||
// the unique namespace, just like all global symbols, so that multiple similar
|
||||
// jobs can easily compile into and link with the vjobs.prx module that can call
|
||||
// them on PPU either for debugging, for fallback case, or for main processing
|
||||
// on Xbox360
|
||||
//
|
||||
|
||||
//#include <cell/spurs/job_chain.h>
|
||||
#include <cell/spurs/job_queue.h>
|
||||
#include <cell/spurs/job_context.h>
|
||||
#include <spu_printf.h>
|
||||
|
||||
#ifdef USE_LSGUARD
|
||||
#include <cell/lsguard.h>
|
||||
#endif
|
||||
|
||||
#ifndef VJOB
|
||||
#error "Please define VJOB to the project name in SPU job project. This will isolate it from other jobs when they compile into the common elf, prx or dll"
|
||||
#endif
|
||||
|
||||
namespace VJOB
|
||||
{
|
||||
extern void Main( CellSpursJobContext2* stInfo, CellSpursJob256 *job );
|
||||
}
|
||||
|
||||
CellSpursJobContext2* g_stInfo = 0;
|
||||
uint32_t g_InterlockedBuffer[32] __attribute__((aligned(128)));
|
||||
|
||||
#ifdef VJOB_JOBCHAIN_JOB
|
||||
// JobChain job: the symbol is "job"
|
||||
|
||||
extern "C"
|
||||
void cellSpursJobMain2(CellSpursJobContext2* stInfo, CellSpursJob256 *job)
|
||||
{
|
||||
extern CellSpursJobContext2* g_stInfo;
|
||||
g_stInfo = stInfo;
|
||||
VJOB::Main( stInfo, job );
|
||||
}
|
||||
#else
|
||||
// JobQueue job: the symbol is "jqjob"
|
||||
void cellSpursJobQueueMain(
|
||||
CellSpursJobContext2 *pContext,
|
||||
CellSpursJob256 *pJob
|
||||
)
|
||||
{
|
||||
extern CellSpursJobContext2* g_stInfo;
|
||||
g_stInfo = pContext;
|
||||
VJOB::Main( pContext, pJob );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void CheckBufferOverflow_Impl()
|
||||
{
|
||||
uint16_t nCause;
|
||||
int nResult;
|
||||
nResult = cellSpursJobMemoryCheckTest( &nCause );
|
||||
if ( nResult != CELL_OK )
|
||||
{
|
||||
spu_printf( "cellSpursJobMemoryCheckTest() failed = %08X\n", nResult );
|
||||
__asm volatile ("stopd $0,$0,$0");
|
||||
}
|
||||
|
||||
#ifdef USE_LSGUARD
|
||||
nResult = cellLsGuardCheckCorruption();
|
||||
if ( nResult != CELL_OK )
|
||||
{
|
||||
spu_printf( "cellLsGuardCheckCorruption() failed = %08X\n", nResult );
|
||||
__asm volatile ("stopd $0,$0,$0");
|
||||
cellLsGuardRehash(); // We rehash to detect the next corruption
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void CheckDmaGet_Impl( const void * pBuffer, size_t nSize )
|
||||
{
|
||||
#ifdef USE_LSGUARD
|
||||
int nResult;
|
||||
nResult = cellLsGuardCheckWriteAccess( pBuffer, nSize );
|
||||
if ( nResult != CELL_OK )
|
||||
{
|
||||
spu_printf( "cellLsGuardCheckWriteAccess() failed = %08X\n", nResult );
|
||||
spu_printf( "Address: %08X - Size: %d\n", (int)pBuffer, (int)nSize );
|
||||
__asm volatile ("stopd $0,$0,$0");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
435
common/ps3/spu_job_shared.cpp
Normal file
435
common/ps3/spu_job_shared.cpp
Normal file
@@ -0,0 +1,435 @@
|
||||
//========== Copyright © Valve Corporation, All rights reserved. ========
|
||||
#include "ps3/spu_job_shared.h"
|
||||
|
||||
uint g_nBreakMask = 0;
|
||||
|
||||
|
||||
void* AlignBuffer( void * pBuffer, uint nBytes )
|
||||
{
|
||||
if( !( uintp( pBuffer ) & 15 ) )
|
||||
{
|
||||
return pBuffer;
|
||||
}
|
||||
|
||||
Assert( nBytes < 232*1024 ); // sanity check
|
||||
|
||||
vector int *pBegin = ( vector int * )( pBuffer ), *pEnd = ( vector int* )( uintp( pBuffer ) + nBytes );
|
||||
vector int vLast = *pBegin;
|
||||
vector int *pLast = pBegin;
|
||||
|
||||
vector unsigned char vShuf = vec_lvsl( 0, (uint8*)pBuffer );
|
||||
while( pLast < pEnd )
|
||||
{
|
||||
vector int * pNext = pLast + 1;
|
||||
vector int vNext = *pNext;
|
||||
*pLast = vec_perm( vLast, vNext, vShuf );
|
||||
|
||||
pLast = pNext;
|
||||
vLast = vNext;
|
||||
}
|
||||
|
||||
return ( void* )( uintp( pBuffer ) & -16 );
|
||||
}
|
||||
|
||||
//
|
||||
// Adds constant nAdd to the given unaligned buffer of uint16's
|
||||
//
|
||||
void UnalignedBufferAddU16( uint16 * pBuffer, uint nCount, uint16 nAdd )
|
||||
{
|
||||
#ifdef SPU
|
||||
if( nCount )
|
||||
{
|
||||
uint16 *pBufferEnd = pBuffer + nCount;
|
||||
vector unsigned short vuAdd = vec_splat_u16( nAdd );
|
||||
vector unsigned short vuLeft = spu_rlmaskqwbyte( vuAdd, -( 0xF & int( pBuffer ) ) );
|
||||
vector unsigned short vuRight = spu_slqwbyte( vuAdd, 0xF & -int( pBufferEnd ) );
|
||||
vector unsigned short * pLeft = ( vector unsigned short * )( uintp( pBuffer ) & -16 ), * pRight = ( vector unsigned short* )( uintp( pBufferEnd - 1 ) & -16 );
|
||||
if( pLeft == pRight )
|
||||
{
|
||||
*pLeft = vec_add( *pLeft, vec_and( vuLeft, vuRight ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
*pLeft = vec_add( *pLeft, vuLeft );
|
||||
*pRight = vec_add( *pRight, vuRight );
|
||||
for( vector unsigned short * p = pLeft + 1; p < pRight; ++p )
|
||||
{
|
||||
*p = vec_add( *p, vuAdd );
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
for( uint i = 0; i < nCount; ++i )
|
||||
{
|
||||
pBuffer[i] += nAdd;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void TestUnalignedBufferAddU16( )
|
||||
{
|
||||
uint16 ALIGN16 test[8 * 6] ALIGN16_POST;
|
||||
for( uint l = 0; l <= 8; ++l )
|
||||
{
|
||||
for( uint e = l; e < ARRAYSIZE( test ); ++e )
|
||||
{
|
||||
V_memset( test, 0, sizeof( test ) );
|
||||
UnalignedBufferAddU16( test + l, e - l, e+1 );
|
||||
for( uint t = 0; t < l; ++ t )
|
||||
Assert( test[t] == 0 );
|
||||
for( uint t = l; t < e; ++t )
|
||||
Assert( test[t] == e+1 );
|
||||
for( uint t = e; t < ARRAYSIZE( test ); ++t )
|
||||
Assert( test[t] == 0 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef SPU
|
||||
|
||||
void TestAlignBuffer()
|
||||
{
|
||||
for( uint i = 0; i < 16; ++i )
|
||||
{
|
||||
uint8 ALIGN16 test[16 * 10] ALIGN16_POST;
|
||||
for( uint j = i; j < sizeof( test ); ++j )
|
||||
test[j] = uint8( j - i );
|
||||
uint8 * pBeginTest = (uint8*)AlignBuffer( test + i, sizeof( test ) - 16 );
|
||||
Assert( pBeginTest == test );
|
||||
for( uint j = 0; j < sizeof( test ) - 16; ++j )
|
||||
Assert( test[j] == uint8( j ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
CellSpursJobContext2* g_stInfo = NULL;
|
||||
|
||||
static void SyncDmaListTransfer( void * pDmaList, uint nDmaListSize, void * pTarget, uint nTargetMaxSize )
|
||||
{
|
||||
Assert( !( nDmaListSize & 7 ) && !( uintp( pDmaList ) & 0xF ) );
|
||||
//uintp dmaTarget = ( uintp ) pTarget, dmaTargetEnd = dmaTarget + nTargetMaxSize;
|
||||
|
||||
CellSpursJobInputList * pInputDmaList = ( CellSpursJobInputList* )pDmaList, *pInputDmaListEnd = ( CellSpursJobInputList * )( uintp( pDmaList ) + nDmaListSize );
|
||||
|
||||
uintp lsDmaTarget = ( uintp ) pTarget, lsDmaTargetEnd = lsDmaTarget + nTargetMaxSize;
|
||||
for ( CellSpursJobInputList * pDmaElement = pInputDmaList; pDmaElement < pInputDmaListEnd; pDmaElement++ )
|
||||
{
|
||||
Assert( pDmaElement->asInputList.size <= 16 * 1024 ); // max size of a DMA element
|
||||
uintp lsDmaEnd = lsDmaTarget + pDmaElement->asInputList.size;
|
||||
Assert( lsDmaEnd <= lsDmaTargetEnd );
|
||||
V_memcpy( ( void* )lsDmaTarget, ( const void* ) pDmaElement->asInputList.eal, pDmaElement->asInputList.size );
|
||||
lsDmaTarget = AlignValue( lsDmaEnd, 16 ); // for small transfers, we must stalign every transfer by 16
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void VjobPushJob( void ( *pfnMain )( CellSpursJobContext2 * stInfo, CellSpursJob256 * job ), CellSpursJob128 * job )
|
||||
{
|
||||
CellSpursJobContext2 info;
|
||||
V_memset( &info, 0, sizeof( info ) );
|
||||
void * ioBuffer = MemAlloc_AllocAligned( job->header.sizeInOrInOut, 16 );
|
||||
info.ioBuffer = ioBuffer;
|
||||
info.eaJobDescriptor = ( uintp ) job;
|
||||
|
||||
CellSpursJob256 jobCopy;
|
||||
V_memcpy( &jobCopy, job, sizeof( *job ) );
|
||||
|
||||
SyncDmaListTransfer( job->workArea.dmaList, job->header.sizeDmaList, ioBuffer, job->header.sizeInOrInOut );
|
||||
|
||||
g_stInfo = &info;
|
||||
pfnMain( &info, ( CellSpursJob256* ) job );
|
||||
g_stInfo = NULL;
|
||||
|
||||
MemAlloc_FreeAligned( ioBuffer );
|
||||
}
|
||||
|
||||
|
||||
void VjobSpuLog( const char * p, ... )
|
||||
{
|
||||
va_list args;
|
||||
va_start( args, p );
|
||||
char szBuffer[2048];
|
||||
V_vsnprintf( szBuffer, sizeof( szBuffer ), p, args );
|
||||
Msg( "SPU-on-PPU: %s\n", szBuffer );
|
||||
va_end( args );
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define Check(b) if(!(b))DebuggerBreak();
|
||||
|
||||
|
||||
void VjobDmaPut(
|
||||
const void * ls,
|
||||
uint64_t ea,
|
||||
uint32_t size,
|
||||
uint32_t tag,
|
||||
uint32_t tid,
|
||||
uint32_t rid
|
||||
)
|
||||
{
|
||||
Check( !( size & 0xF ) && size <= 16 * 1024 );
|
||||
Check( !( ea & 0xF ) && !( uintp( ls ) & 0xF ) );
|
||||
V_memcpy( ( void* )( uintp )ea, ls, size );
|
||||
}
|
||||
|
||||
|
||||
void VjobDmaLargePut(
|
||||
const void * ls,
|
||||
uint64_t ea,
|
||||
uint32_t size,
|
||||
uint32_t tag,
|
||||
uint32_t tid,
|
||||
uint32_t rid
|
||||
)
|
||||
{
|
||||
Check( !( size & 0xF ) && size <= 240 * 1024 );
|
||||
Check( !( ea & 0xF ) && !( uintp( ls ) & 0xF ) );
|
||||
V_memcpy( ( void* )( uintp )ea, ls, size );
|
||||
}
|
||||
|
||||
void VjobDmaLargePutf(
|
||||
const void * ls,
|
||||
uint64_t ea,
|
||||
uint32_t size,
|
||||
uint32_t tag,
|
||||
uint32_t tid,
|
||||
uint32_t rid
|
||||
)
|
||||
{
|
||||
VjobDmaLargePut( ls, ea, size, tag, tid, rid );
|
||||
}
|
||||
|
||||
void VjobDmaUnalignedPutf(
|
||||
const void *ls,
|
||||
uint64_t ea,
|
||||
uint32_t size,
|
||||
uint32_t tag,
|
||||
uint32_t tid,
|
||||
uint32_t rid
|
||||
)
|
||||
{
|
||||
Assert( 0 == ( 0xF & ( uintp( ls ) ^ ea ) ) );
|
||||
V_memcpy( (void*)(uintp)ea, ls, size );
|
||||
}
|
||||
|
||||
|
||||
void VjobDmaUnalignedPut(
|
||||
const void *ls,
|
||||
uint64_t ea,
|
||||
uint32_t size,
|
||||
uint32_t tag,
|
||||
uint32_t tid,
|
||||
uint32_t rid
|
||||
)
|
||||
{
|
||||
Assert( 0 == ( 0xF & ( uintp( ls ) ^ ea ) ) );
|
||||
V_memcpy( (void*)(uintp)ea, ls, size );
|
||||
}
|
||||
|
||||
|
||||
void VjobDmaLargePutb(
|
||||
const void * ls,
|
||||
uint64_t ea,
|
||||
uint32_t size,
|
||||
uint32_t tag,
|
||||
uint32_t tid,
|
||||
uint32_t rid
|
||||
)
|
||||
{
|
||||
VjobDmaLargePut( ls, ea, size, tag, tid, rid );
|
||||
}
|
||||
|
||||
|
||||
void VjobDmaPutf(
|
||||
const void * ls,
|
||||
uint64_t ea,
|
||||
uint32_t size,
|
||||
uint32_t tag,
|
||||
uint32_t tid,
|
||||
uint32_t rid
|
||||
)
|
||||
{
|
||||
Check( !( size & 0xF ) && size <= 16 * 1024 );
|
||||
Check( !( ea & 0xF ) && !( uintp( ls ) & 0xF ) );
|
||||
V_memcpy( ( void* )( uintp )ea, ls, size );
|
||||
}
|
||||
|
||||
|
||||
void VjobDmaSmallPut(
|
||||
const void * ls,
|
||||
uint64_t ea,
|
||||
uint32_t size,
|
||||
uint32_t tag,
|
||||
uint32_t tid,
|
||||
uint32_t rid
|
||||
)
|
||||
{
|
||||
Check( !( size & ( size - 1 ) ) );
|
||||
Check( !( 0xF & ( ea ^ uintp( ls ) ) ) );
|
||||
if ( size == 4 )
|
||||
{
|
||||
// special case to handle atomically, because we may use this to write RSX registers
|
||||
*( uint32* )( uintp )ea = *( uint32* )ls;
|
||||
}
|
||||
else
|
||||
{
|
||||
V_memcpy( ( void* )( uintp )ea, ls, size );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void VjobDmaGet(
|
||||
void * ls,
|
||||
uint64_t ea,
|
||||
uint32_t size,
|
||||
uint32_t tag,
|
||||
uint32_t tid,
|
||||
uint32_t rid
|
||||
)
|
||||
{
|
||||
Check( !( size & ( size - 1 ) ) );
|
||||
Check( !( 0xF & ( ea | uintp( ls ) ) ) );
|
||||
if ( size == 4 )
|
||||
{
|
||||
// special case to handle atomically, because we may use this to read RSX registers
|
||||
*( uint32* )ls = *( uint32* )( uintp )ea;
|
||||
}
|
||||
else
|
||||
{
|
||||
V_memcpy( ls, ( const void* )( uintp )ea, size );
|
||||
}
|
||||
}
|
||||
|
||||
void VjobDmaGetf(
|
||||
void * ls,
|
||||
uint64_t ea,
|
||||
uint32_t size,
|
||||
uint32_t tag,
|
||||
uint32_t tid,
|
||||
uint32_t rid
|
||||
)
|
||||
{
|
||||
VjobDmaGet( ls, ea, size, tag, tid, rid );
|
||||
}
|
||||
|
||||
// NOTE: implementation must wait for tag
|
||||
uint32_t VjobDmaGetUint32(
|
||||
uint64_t ea,
|
||||
uint32_t tag,
|
||||
uint32_t tid,
|
||||
uint32_t rid
|
||||
)
|
||||
{
|
||||
return * ( volatile uint32 * )( uintp )ea;
|
||||
}
|
||||
|
||||
void VjobDmaPutUint32(
|
||||
uint32_t value,
|
||||
uint64_t ea,
|
||||
uint32_t tag,
|
||||
uint32_t tid,
|
||||
uint32_t rid
|
||||
)
|
||||
{
|
||||
( * ( volatile uint32 * )( uintp )ea ) = value;
|
||||
}
|
||||
|
||||
uint64_t VjobDmaGetUint64(
|
||||
uint64_t ea,
|
||||
uint32_t tag,
|
||||
uint32_t tid,
|
||||
uint32_t rid
|
||||
)
|
||||
{
|
||||
return *( volatile uint64 * )( uintp )ea;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void VjobDmaPutUint64(
|
||||
uint64_t value,
|
||||
uint64_t ea,
|
||||
uint32_t tag,
|
||||
uint32_t tid,
|
||||
uint32_t rid
|
||||
)
|
||||
{
|
||||
( * ( volatile uint64 * )( uintp )ea ) = value;
|
||||
}
|
||||
|
||||
|
||||
void VjobDmaListGet(
|
||||
void * ls,
|
||||
uint64_t ea,
|
||||
const CellDmaListElement * list,
|
||||
uint32_t listSize,
|
||||
uint32_t tag,
|
||||
uint32_t tid,
|
||||
uint32_t rid
|
||||
)
|
||||
{
|
||||
Check( !( listSize % 8 ) );
|
||||
uint8 * pLsTarget = ( uint8* )ls;
|
||||
for ( uint i = 0; i < listSize / 8; ++i )
|
||||
{
|
||||
uint64 nSize = list[i].size;
|
||||
VjobDmaGet( pLsTarget, ea + list[i].eal, ( uint32 )nSize, tag, tid, rid );
|
||||
}
|
||||
}
|
||||
|
||||
void VjobDmaSmallGet(
|
||||
void * ls,
|
||||
uint64_t ea,
|
||||
uint32_t size,
|
||||
uint32_t tag,
|
||||
uint32_t tid,
|
||||
uint32_t rid
|
||||
)
|
||||
{
|
||||
Check( !( size & ( size - 1 ) ) );
|
||||
Check( !( 0xF & ( ea ^ uintp( ls ) ) ) );
|
||||
V_memcpy( ls, ( const void* )( uintp )ea, size );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void VjobDmaSmallPutf(
|
||||
const void * ls,
|
||||
uint64_t ea,
|
||||
uint32_t size,
|
||||
uint32_t tag,
|
||||
uint32_t tid,
|
||||
uint32_t rid
|
||||
)
|
||||
{
|
||||
Check( !( size & ( size - 1 ) ) );
|
||||
Check( !( 0xF & ( ea ^ uintp( ls ) ) ) );
|
||||
V_memcpy( ( void* )( uintp )ea, ls, size );
|
||||
}
|
||||
|
||||
void VjobDmaSmallPutb(
|
||||
const void * ls,
|
||||
uint64_t ea,
|
||||
uint32_t size,
|
||||
uint32_t tag,
|
||||
uint32_t tid,
|
||||
uint32_t rid
|
||||
)
|
||||
{
|
||||
Check( !( size & ( size - 1 ) ) );
|
||||
Check( !( 0xF & ( ea ^ uintp( ls ) ) ) );
|
||||
V_memcpy( ( void* )( uintp )ea, ls, size );
|
||||
}
|
||||
|
||||
void VjobPpuRereadEA( uintp ea )
|
||||
{
|
||||
__lwsync();
|
||||
int eaContent = *( volatile int * ) ea;
|
||||
__lwsync();
|
||||
}
|
||||
#endif
|
||||
753
common/ps3/spu_job_shared.h
Normal file
753
common/ps3/spu_job_shared.h
Normal file
@@ -0,0 +1,753 @@
|
||||
//========= Copyright © 1996-2004, Valve LLC, All rights reserved. ============
|
||||
//
|
||||
// This is the common include file to be included in SPU jobs.
|
||||
// It takes care to remap/emulate some SPU-specific functinality on PPU
|
||||
//
|
||||
#ifndef PS3_SPU_JOB_SHARED_HDR
|
||||
#define PS3_SPU_JOB_SHARED_HDR
|
||||
|
||||
#ifdef _PS3
|
||||
|
||||
#include <ps3/ps3_platform.h>
|
||||
#include <cell/spurs/job_chain.h>
|
||||
#include <cell/spurs/job_queue.h>
|
||||
#include <cell/spurs/job_queue_port2.h>
|
||||
#include <cell/dma/types.h>
|
||||
|
||||
//
|
||||
// NOTE: Enable the following block for debugging GCM on SPU; works as of SDK 350
|
||||
//
|
||||
#if 0 && defined( __SPU__ )
|
||||
#include <cell/gcm/gcm_macros.h>
|
||||
|
||||
#undef CELL_GCM_ASSERT
|
||||
#undef CELL_GCM_ASSERTS
|
||||
#define CELL_GCM_ASSERT(condition) Assert( condition )
|
||||
#define CELL_GCM_ASSERTS(condition, description) AssertSpuMsg( condition, description )
|
||||
#define CELL_GCM_ASSERT_ENABLE
|
||||
#endif
|
||||
|
||||
enum DmaTagEnum_t
|
||||
{
|
||||
DMATAG_SYNC = 2, // used for synchronous transfers, where we need the transfer to finish very soon/immediately after issuing
|
||||
DMATAG_TEXTURES = 3,
|
||||
DMATAG_SHADERS = 4,
|
||||
DMATAG_SCRATCH = 5, // used for DMA PUTs from Scratch memory, so we need to wait for this to finish before job finishes
|
||||
|
||||
// each jobchain needs 2 dma tags, up to tag 30
|
||||
// DMATAG_EDGE_JOBCHAIN = 8,
|
||||
// DMATAG_FPCP_JOBCHAIN = 10,
|
||||
// DMATAG_GCM_JOBCHAIN = 12,
|
||||
|
||||
DMATAG_ANIM = 8, // non immediate dma's
|
||||
DMATAG_BUILDINDICES = 8,
|
||||
DMATAG_BUILDRENDERABLES = 8,
|
||||
|
||||
|
||||
}; // shouldn't overlap with the tags used by the workload
|
||||
|
||||
// Enable this define to disable assert. This may be necessary to detect timing issues in DEBUG and RELEASE,
|
||||
// or incorrectly generated code from compiler. When LSGUARD is enabled, we disable asserts to force potential issues.
|
||||
#ifdef USE_LSGUARD
|
||||
# define DISABLE_ASSERT
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
inline T* AddBytes( T* p, int nBytes )
|
||||
{
|
||||
return ( T* )( int( p ) + nBytes );
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T Min( T a, T b )
|
||||
{
|
||||
return a < b ? a : b;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T Max( T a, T b )
|
||||
{
|
||||
return a > b ? a : b;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void Swap( T& a , T & b )
|
||||
{
|
||||
T c = a; a = b; b = c;
|
||||
}
|
||||
|
||||
|
||||
// <sergiy> should I port platform.h to SPU?
|
||||
#ifdef SPU
|
||||
#include <cell/spurs/job_context.h>
|
||||
#include "cell/spurs/common.h"
|
||||
#include <cell/atomic.h>
|
||||
#include <spu_intrinsics.h>
|
||||
#include <vmx2spu.h>
|
||||
|
||||
#define PPU_ONLY(X)
|
||||
#define SPU_ONLY(X) X
|
||||
#define vector __vector
|
||||
|
||||
void CheckBufferOverflow_Impl();
|
||||
void CheckDmaGet_Impl( const void * pBuffer, size_t nSize );
|
||||
|
||||
#if defined(_CERT) || defined(DISABLE_ASSERT)
|
||||
# define VjobSpuLog(...)
|
||||
# define DebuggerBreak()
|
||||
# define Warning(...)
|
||||
# define CheckBufferOverflow()
|
||||
# define CheckDmaGet(p, size)
|
||||
#else
|
||||
# include <spu_printf.h>
|
||||
# define VjobSpuLog( MSG, ... ) spu_printf( "[%d]" MSG, cellSpursGetCurrentSpuId(), ##__VA_ARGS__ )
|
||||
# define Msg( MSG, ... ) spu_printf( "[%d]" MSG, cellSpursGetCurrentSpuId(), ##__VA_ARGS__ )
|
||||
#ifndef BASETYPES_H
|
||||
#define DebuggerBreak() __asm volatile ("stopd $0,$0,$0")
|
||||
#endif
|
||||
# define Warning( MSG, ... ) spu_printf( "[%d] Warning: " MSG, cellSpursGetCurrentSpuId(), ##__VA_ARGS__ )
|
||||
# define CELL_DMA_ASSERT_VERBOSE
|
||||
# define CheckBufferOverflow() CheckBufferOverflow_Impl()
|
||||
# define CheckDmaGet(p, size) CheckDmaGet_Impl( p, size )
|
||||
#endif
|
||||
|
||||
#define LWSYNC_PPU_ONLY()
|
||||
|
||||
#define VJOB_IOBUFFER_DMATAG g_stInfo->dmaTag // fake DMA tag
|
||||
|
||||
#include <cell/spurs/common.h>
|
||||
|
||||
#define VjobDmaPut cellDmaPut
|
||||
#define VjobDmaGet cellDmaGet
|
||||
#define VjobDmaGetf cellDmaGetf
|
||||
#define VjobDmaListGet cellDmaListGet
|
||||
#define VjobDmaLargePut cellDmaLargePut
|
||||
#define VjobDmaLargePutf cellDmaLargePutf
|
||||
//#define VjobDmaLargePutb cellDmaLargePutb
|
||||
#define VjobDmaPutf cellDmaPutf
|
||||
#define VjobDmaSmallPut cellDmaSmallPut
|
||||
#define VjobDmaSmallPutf cellDmaSmallPutf
|
||||
//#define VjobDmaSmallPutb cellDmaSmallPutb
|
||||
#define VjobDmaSmallGet cellDmaSmallGet
|
||||
#define VjobWaitTagStatusAll cellDmaWaitTagStatusAll
|
||||
#define VjobWaitTagStatusImmediate cellDmaWaitTagStatusImmediate
|
||||
#define VjobDmaGetUint32 cellDmaGetUint32
|
||||
#define VjobDmaPutUint32 cellDmaPutUint32
|
||||
#define VjobDmaGetUint64 cellDmaGetUint64
|
||||
#define VjobDmaPutUint64 cellDmaPutUint64
|
||||
#define VjobDmaUnalignedPutf cellDmaUnalignedPutf
|
||||
#define VjobDmaUnalignedPut cellDmaUnalignedPut
|
||||
|
||||
#define VjobDmaPutfUintTemplate(SIZE, value, ea, tag, tid, rid) \
|
||||
do { \
|
||||
uint64_t __cellDma_ea = ea; \
|
||||
uint32_t __cellDma_tag = tag; \
|
||||
qword _buf = (qword)spu_splats(value); \
|
||||
cellDmaDataAssert(__cellDma_ea,sizeof(uint##SIZE##_t),__cellDma_tag); \
|
||||
cellDmaAndWait(cellDmaEa2Ls(__cellDma_ea,&_buf),__cellDma_ea,sizeof(uint##SIZE##_t),__cellDma_tag,MFC_CMD_WORD(tid,rid,MFC_PUTF_CMD)); \
|
||||
} while(0)
|
||||
|
||||
#define VjobDmaPutfUint8(value, ea, tag) cellDmaPutUintTemplate(8, ((uint8_t)value), ea, tag, 0, 0)
|
||||
#define VjobDmaPutfUint16(value, ea, tag) cellDmaPutUintTemplate(16, ((uint16_t)value), ea, tag, 0, 0)
|
||||
#define VjobDmaPutfUint32(value, ea, tag) cellDmaPutUintTemplate(32, ((uint32_t)value), ea, tag, 0, 0)
|
||||
#define VjobDmaPutfUint64(value, ea, tag) cellDmaPutUintTemplate(64, ((uint64_t)value), ea, tag, 0, 0)
|
||||
|
||||
|
||||
|
||||
#define VjobSpuId() int( cellSpursGetCurrentSpuId() )
|
||||
|
||||
#define V_memset __builtin_memset
|
||||
#define V_memcpy __builtin_memcpy
|
||||
|
||||
#if !defined ARRAYSIZE
|
||||
#define ARRAYSIZE( ARRAY ) ( sizeof( ARRAY ) / sizeof( ( ARRAY )[0] ) )
|
||||
#endif
|
||||
|
||||
typedef signed int int32;
|
||||
typedef unsigned int uint;
|
||||
typedef signed char int8;
|
||||
typedef unsigned char uint8;
|
||||
typedef signed short int16;
|
||||
typedef unsigned short uint16;
|
||||
typedef signed int int32;
|
||||
typedef unsigned int uint32;
|
||||
typedef signed long long int64;
|
||||
typedef unsigned long long uint64;
|
||||
typedef unsigned int uintp;
|
||||
|
||||
typedef vector float fltx4 ;
|
||||
|
||||
#define INT_MAX 0x7fffffff
|
||||
|
||||
#define DECL_ALIGN(x) __attribute__( ( aligned( x ) ) )
|
||||
|
||||
|
||||
|
||||
#ifndef BASETYPES_H
|
||||
|
||||
#define ALIGN16 DECL_ALIGN(16)
|
||||
#define ALIGN16_POST
|
||||
#define ALIGN128 DECL_ALIGN(128)
|
||||
#define ALIGN128_POST
|
||||
template <typename T>
|
||||
inline T AlignValue( T val, uintp alignment )
|
||||
{
|
||||
return ( T )( ( ( uintp )val + alignment - 1 ) & ~( alignment - 1 ) );
|
||||
}
|
||||
|
||||
#define ALIGN_VALUE( val, alignment ) ( ( val + alignment - 1 ) & ~( alignment - 1 ) )
|
||||
|
||||
inline bool IsPowerOfTwo( uint x )
|
||||
{
|
||||
return ( x & ( x - 1 ) ) == 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#define FORCEINLINE inline /* __attribute__ ((always_inline)) */
|
||||
|
||||
#define IsPlatformPS3() 1
|
||||
#define IsPlatformPS3_PPU() 0
|
||||
#define IsPlatformPS3_SPU() 1
|
||||
#define IsPlatformX360() 0
|
||||
#define IsPlatformOSX() 0
|
||||
|
||||
#if !defined RESTRICT
|
||||
#define RESTRICT
|
||||
#endif
|
||||
|
||||
#define V_memset __builtin_memset
|
||||
#define V_memcpy __builtin_memcpy
|
||||
|
||||
inline void VjobPpuRereadEA( uintp ea ){}
|
||||
|
||||
#if defined(_CERT) || defined(DISABLE_ASSERT)
|
||||
|
||||
#define Assert(x) ((void)(0))
|
||||
#define AssertSpuMsg(x,MSG,...)((void)0)
|
||||
#ifndef DBG_H
|
||||
#define COMPILE_TIME_ASSERT( pred ) // to avoid any unpredictable affects in the optimizer
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#define DBGFLAG_ASSERT
|
||||
#ifndef DBG_H
|
||||
#define Assert(x) do{if( !( x ) ) { spu_printf( "Assert on SPU[%d](" #x ")\n", cellSpursGetCurrentSpuId() ); DebuggerBreak(); } }while(0)
|
||||
#endif
|
||||
#define AssertSpuMsg(x,MSG,...) do{if( !( x ) ) { spu_printf( "Assert on SPU[%d](" #x "), " MSG, cellSpursGetCurrentSpuId(), ## __VA_ARGS__ ); DebuggerBreak(); } }while(0)
|
||||
#ifndef DBG_H
|
||||
#define COMPILE_TIME_ASSERT( pred ) switch(0){case 0:case pred:;}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// mimic the PPU class on SPU
|
||||
// template< int bytesAlignment, class T >
|
||||
// class CAlignedNewDelete : public T
|
||||
// {public:
|
||||
// }
|
||||
|
||||
// WARNING: SLOWNESS. DO NOT USE IN PRODUCTION.
|
||||
inline void DebugMemcpyEa( uint eaDest, uint eaSrc, uint nSize, void *lsScratch )
|
||||
{
|
||||
Assert( ! ( 0xF & ( eaSrc | eaDest | nSize ) ) );
|
||||
uint nBytesLeft = nSize, nOffset = 0;
|
||||
while( nBytesLeft )
|
||||
{
|
||||
uint nChunk = Min<uint>( 16 * 1024, nBytesLeft );
|
||||
VjobDmaGet( lsScratch, eaSrc + nOffset, nChunk, DMATAG_SYNC, 0, 0 );
|
||||
VjobWaitTagStatusAll( 1 << DMATAG_SYNC );
|
||||
VjobDmaPut( lsScratch, eaDest + nOffset, nChunk, DMATAG_SYNC, 0, 0 );
|
||||
VjobWaitTagStatusAll( 1 << DMATAG_SYNC );
|
||||
nBytesLeft -= nChunk;
|
||||
nOffset += nChunk;
|
||||
}
|
||||
}
|
||||
|
||||
#define vec_to_uint32(X) si_to_uint( ( qword )( X ) )
|
||||
|
||||
|
||||
#define VjobQueuePort2PushJob( eaPort, eaJob, sizeDesc, tag, dmaTag, flag ) cellSpursJobQueuePort2PushJob( (uintp)( eaPort ), (uintp)( eaJob ), ( sizeDesc ), ( tag ), ( dmaTag ), ( flag ) )
|
||||
#define VjobQueuePort2PushSync( eaPort2, tagMask, dmaTag, flag ) cellSpursJobQueuePort2PushSync( ( uintp ) ( eaPort2), ( tagMask ), ( dmaTag ), ( flag ) )
|
||||
|
||||
|
||||
inline void VjobQueuePort2PushJobBlocking( CellSpursJobQueuePort2 *eaPort2, CellSpursJobHeader *eaJob, size_t sizeDesc, uint nQueueTag, uint nDmaTag )
|
||||
{
|
||||
int nError;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
nError = cellSpursJobQueuePort2PushJob( uintp( eaPort2 ), uintp( eaJob ) , sizeDesc, nQueueTag, nDmaTag, CELL_SPURS_JOBQUEUE_FLAG_NON_BLOCKING );
|
||||
if( nError != CELL_SPURS_JOB_ERROR_AGAIN )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( nError != CELL_OK )
|
||||
{
|
||||
VjobSpuLog( "Cannot push job, error %d. RSX is going to hang, then SPUs, then PPU.\n", nError );
|
||||
DebuggerBreak();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline void VjobQueuePort2PushSyncBlocking( CellSpursJobQueuePort2 *eaPort2, unsigned tagMask, uint nDmaTag )
|
||||
{
|
||||
int nError;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
nError = cellSpursJobQueuePort2PushSync( uintp( eaPort2 ), tagMask, nDmaTag, CELL_SPURS_JOBQUEUE_FLAG_NON_BLOCKING );
|
||||
if( nError != CELL_SPURS_JOB_ERROR_AGAIN )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( nError != CELL_OK )
|
||||
{
|
||||
VjobSpuLog( "Cannot push job, error %d. RSX is going to hang, then SPUs, then PPU.\n", nError );
|
||||
DebuggerBreak();
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#include "tier0/platform.h"
|
||||
#include "tier1/strtools.h"
|
||||
#include "mathlib/ssemath.h"
|
||||
#include <altivec.h>
|
||||
#include <cell/spurs/job_context_types.h>
|
||||
|
||||
inline uint32_t GetCurrentSpuId()
|
||||
{
|
||||
return 0xFFFFFFFF;
|
||||
}
|
||||
using namespace ::cell::Spurs;
|
||||
extern void VjobSpuLog( const char * p, ... );
|
||||
|
||||
#define VJOB_IOBUFFER_DMATAG 0 // fake DMA tag
|
||||
|
||||
#define PPU_ONLY(X) X
|
||||
#define SPU_ONLY(X)
|
||||
|
||||
|
||||
#ifdef _DEBUG
|
||||
#define AssertSpuMsg(x,MSG,...) do { if( !( x ) ) { Warning( "Assert(" #x "), " MSG, ## __VA_ARGS__ ); DebuggerBreak(); } }while( 0 )
|
||||
#else
|
||||
#define AssertSpuMsg(x,MSG,...)
|
||||
#endif
|
||||
|
||||
|
||||
#define VjobQueuePort2PushJob( eaPort, eaJob, sizeDesc, tag, dmaTag, flag ) cellSpursJobQueuePort2PushJob( (CellSpursJobQueuePort2 *)( eaPort ), (CellSpursJobHeader *)( eaJob ), ( sizeDesc ), ( tag ), ( flag ) )
|
||||
#define VjobQueuePort2PushSync( eaPort2, tagMask, dmaTag, flag ) cellSpursJobQueuePort2PushSync( (CellSpursJobQueuePort2 *) ( eaPort2), ( tagMask ), ( flag ) )
|
||||
|
||||
inline void VjobQueuePort2PushJobBlocking( CellSpursJobQueuePort2 *eaPort2, CellSpursJobHeader *eaJob, size_t sizeDesc, uint nQueueTag, uint nDmaTag )
|
||||
{
|
||||
int nError = cellSpursJobQueuePort2PushJob( eaPort2, eaJob, sizeDesc, nQueueTag, 0 );// synchronous call
|
||||
(void) nError;
|
||||
Assert( nError == CELL_OK );
|
||||
}
|
||||
|
||||
inline void VjobQueuePort2PushSyncBlocking( CellSpursJobQueuePort2 *eaPort2, unsigned tagMask, uint nDmaTag )
|
||||
{
|
||||
int nError = cellSpursJobQueuePort2PushSync( eaPort2, tagMask, 0 ); // synchronous call
|
||||
(void) nError;
|
||||
Assert( nError == CELL_OK );
|
||||
}
|
||||
|
||||
|
||||
#define VjobSpuId() -1
|
||||
|
||||
#define LWSYNC_PPU_ONLY() __lwsync()
|
||||
|
||||
extern void VjobDmaPut(
|
||||
const void * ls,
|
||||
uint64_t ea,
|
||||
uint32_t size,
|
||||
uint32_t tag,
|
||||
uint32_t tid,
|
||||
uint32_t rid
|
||||
);
|
||||
|
||||
extern void VjobDmaGet(
|
||||
void * ls,
|
||||
uint64_t ea,
|
||||
uint32_t size,
|
||||
uint32_t tag,
|
||||
uint32_t tid,
|
||||
uint32_t rid
|
||||
);
|
||||
|
||||
extern void VjobDmaGetf(
|
||||
void * ls,
|
||||
uint64_t ea,
|
||||
uint32_t size,
|
||||
uint32_t tag,
|
||||
uint32_t tid,
|
||||
uint32_t rid
|
||||
);
|
||||
|
||||
extern void VjobDmaListGet(
|
||||
void *ls,
|
||||
uint64_t ea,
|
||||
const CellDmaListElement *list,
|
||||
uint32_t listSize,
|
||||
uint32_t tag,
|
||||
uint32_t tid,
|
||||
uint32_t rid
|
||||
);
|
||||
|
||||
|
||||
extern void VjobDmaLargePut(
|
||||
const void * ls,
|
||||
uint64_t ea,
|
||||
uint32_t size,
|
||||
uint32_t tag,
|
||||
uint32_t tid,
|
||||
uint32_t rid
|
||||
);
|
||||
|
||||
extern void VjobDmaLargePutf(
|
||||
const void * ls,
|
||||
uint64_t ea,
|
||||
uint32_t size,
|
||||
uint32_t tag,
|
||||
uint32_t tid,
|
||||
uint32_t rid
|
||||
);
|
||||
|
||||
extern void VjobDmaLargePutb(
|
||||
const void * ls,
|
||||
uint64_t ea,
|
||||
uint32_t size,
|
||||
uint32_t tag,
|
||||
uint32_t tid,
|
||||
uint32_t rid
|
||||
);
|
||||
|
||||
extern void VjobDmaPutf(
|
||||
const void * ls,
|
||||
uint64_t ea,
|
||||
uint32_t size,
|
||||
uint32_t tag,
|
||||
uint32_t tid,
|
||||
uint32_t rid
|
||||
);
|
||||
|
||||
extern void VjobDmaSmallPut(
|
||||
const void * ls,
|
||||
uint64_t ea,
|
||||
uint32_t size,
|
||||
uint32_t tag,
|
||||
uint32_t tid,
|
||||
uint32_t rid
|
||||
);
|
||||
|
||||
extern void VjobDmaSmallGet(
|
||||
void * ls,
|
||||
uint64_t ea,
|
||||
uint32_t size,
|
||||
uint32_t tag,
|
||||
uint32_t tid,
|
||||
uint32_t rid
|
||||
);
|
||||
|
||||
|
||||
extern void VjobDmaSmallPutb(
|
||||
const void * ls,
|
||||
uint64_t ea,
|
||||
uint32_t size,
|
||||
uint32_t tag,
|
||||
uint32_t tid,
|
||||
uint32_t rid
|
||||
);
|
||||
|
||||
extern void VjobDmaSmallPutf(
|
||||
const void * ls,
|
||||
uint64_t ea,
|
||||
uint32_t size,
|
||||
uint32_t tag,
|
||||
uint32_t tid,
|
||||
uint32_t rid
|
||||
);
|
||||
|
||||
|
||||
// NOTE: implementation must wait for tag
|
||||
uint32_t VjobDmaGetUint32(
|
||||
uint64_t ea,
|
||||
uint32_t tag,
|
||||
uint32_t tid,
|
||||
uint32_t rid
|
||||
);
|
||||
|
||||
void VjobDmaPutUint32(
|
||||
uint32_t value,
|
||||
uint64_t ea,
|
||||
uint32_t tag,
|
||||
uint32_t tid,
|
||||
uint32_t rid
|
||||
);
|
||||
|
||||
uint64_t VjobDmaGetUint64(
|
||||
uint64_t ea,
|
||||
uint32_t tag,
|
||||
uint32_t tid,
|
||||
uint32_t rid
|
||||
);
|
||||
|
||||
void VjobDmaPutUint64(
|
||||
uint64_t value,
|
||||
uint64_t ea,
|
||||
uint32_t tag,
|
||||
uint32_t tid,
|
||||
uint32_t rid
|
||||
);
|
||||
|
||||
void VjobDmaUnalignedPutf(
|
||||
const void *ls,
|
||||
uint64_t ea,
|
||||
uint32_t size,
|
||||
uint32_t tag,
|
||||
uint32_t tid,
|
||||
uint32_t rid
|
||||
);
|
||||
|
||||
void VjobDmaUnalignedPut(
|
||||
const void *ls,
|
||||
uint64_t ea,
|
||||
uint32_t size,
|
||||
uint32_t tag,
|
||||
uint32_t tid,
|
||||
uint32_t rid
|
||||
);
|
||||
|
||||
|
||||
// These functions are empty because I'm too lazy to implement deferred DMA emulation ...
|
||||
inline uint VjobWaitTagStatusAll( uint nTagMask ){ return nTagMask;}
|
||||
inline uint VjobWaitTagStatusImmediate( uint nTagMask ) { return nTagMask ; }
|
||||
|
||||
|
||||
#define VjobDmaPutfUint8(value, ea, tag) *(uint8*)ea = (uint8)value
|
||||
#define VjobDmaPutfUint16(value, ea, tag) *(uint16*)ea = (uint16)value
|
||||
#define VjobDmaPutfUint32(value, ea, tag) *(uint32*)ea = (uint32)value
|
||||
#define VjobDmaPutfUint64(value, ea, tag) *(uint64*)ea = (uint64)value
|
||||
|
||||
|
||||
void VjobPushJob( void ( *pfnMain )( CellSpursJobContext2 * stInfo, CellSpursJob256 * job ), CellSpursJob128 * job );
|
||||
extern void VjobSpuLog( const char * p, ... );
|
||||
extern void VjobPpuRereadEA( uintp ea );
|
||||
|
||||
inline void DebugMemcpyEa( uint eaDest, uint eaSrc, uint nSize, void *lsScratch )
|
||||
{
|
||||
Assert( ! ( 0xF & ( eaSrc | eaDest | nSize ) ) );
|
||||
memcpy( (void*)eaDest, (void*)eaSrc, nSize );
|
||||
}
|
||||
|
||||
extern void TestAlignBuffer();
|
||||
|
||||
#define vec_to_uint32(X) (*(uint32*)&(X))
|
||||
|
||||
#endif // SPU
|
||||
|
||||
|
||||
#define VjobDmaEa2Ls16(ea, ls) ((uintptr_t)(ls)+((uint32_t)(ea)&15))
|
||||
#define VjobDmaEa2Ls128(ea, ls) ((uintptr_t)(ls)+((uint32_t)(ea)&127))
|
||||
|
||||
inline uint32* PrepareSmallPut32( vector unsigned int * lsAligned, volatile uint32 * eaUnaligned, uint32 nInitialValue )
|
||||
{
|
||||
Assert( !( 3 & uint( lsAligned ) ) );
|
||||
uint32 * ls = ( uint32* )VjobDmaEa2Ls16( eaUnaligned, lsAligned );
|
||||
*ls = nInitialValue;
|
||||
return ls;
|
||||
}
|
||||
|
||||
inline uint64* PrepareSmallPut64( vector unsigned int * lsAligned, volatile uint64 * eaUnaligned, uint64 nInitialValue )
|
||||
{
|
||||
Assert( !( 7 & uint( lsAligned ) ) );
|
||||
uint64 * ls = ( uint64* )VjobDmaEa2Ls16( eaUnaligned, lsAligned );
|
||||
*ls = nInitialValue;
|
||||
return ls;
|
||||
}
|
||||
|
||||
|
||||
|
||||
extern CellSpursJobContext2* g_stInfo;
|
||||
|
||||
#ifndef IsDebug
|
||||
# ifdef _DEBUG
|
||||
# define IsDebug() true
|
||||
# else
|
||||
# define IsDebug() false
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef IsCert
|
||||
# ifdef _CERT
|
||||
# define IsCert() true
|
||||
# else
|
||||
# define IsCert() false
|
||||
# endif
|
||||
#endif
|
||||
|
||||
extern uint g_nBreakMask ;
|
||||
#ifdef _CERT
|
||||
# define BreakOn( nId )
|
||||
#else
|
||||
# define BreakOn( nId ) do \
|
||||
{ \
|
||||
if( g_nBreakMask & ( 1 << nId ) ) \
|
||||
DebuggerBreak(); \
|
||||
}while( 0 )
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
inline void VjobDebugSpinCycles( uint nCycles )
|
||||
{
|
||||
if( !IsCert() )
|
||||
{
|
||||
#ifdef SPU
|
||||
uint nStart = spu_read_decrementer();
|
||||
while( nStart - spu_read_decrementer() < nCycles / 40 )
|
||||
continue;
|
||||
#else
|
||||
sys_timer_usleep( nCycles / 3200 );
|
||||
/*
|
||||
uint nStart = __mftb();
|
||||
|
||||
while( __mftb() - nStart() < nCycles / 40 )
|
||||
continue;
|
||||
*/
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// this is the DMA list element without notify or reserved fields, so that it's easy to fill it in
|
||||
// and be sure there is no garbage left (in notify and reserved fields) and there are no bit field operations (to store size, which is effectively only 14-bit value)
|
||||
struct BasicDmaListElement_t
|
||||
{
|
||||
uint32 size;
|
||||
uint32 eal;
|
||||
};
|
||||
|
||||
|
||||
// shifts unaligned pBuffer of given size left by 0..15 bytes to make it aligned
|
||||
// returns the aligned pointer, pBuffer & -16
|
||||
extern void* AlignBuffer( void * pBuffer, uint nBytes);
|
||||
|
||||
|
||||
//
|
||||
// Adds constant nAdd to the given unaligned buffer of uint16's
|
||||
//
|
||||
extern void UnalignedBufferAddU16( uint16 * pBuffer, uint nCount, uint16 nAdd );
|
||||
|
||||
// SpursJob_t must be one of CellSpursJob64, CellSpursJob128, CellSpursJob256,...
|
||||
// JobParam_t is the parameter structure passed to the job
|
||||
template < typename JobParam_t , typename SpursJob_t >
|
||||
inline JobParam_t * VjobGetJobParams( void * pJob )
|
||||
{
|
||||
Assert( sizeof( JobParam_t ) + sizeof( CellSpursJobHeader ) <= sizeof( SpursJob_t ) );
|
||||
JobParam_t * pJobParams = ( JobParam_t* ) ( uintp( pJob ) + ( sizeof( SpursJob_t ) - sizeof( JobParam_t ) ) );
|
||||
Assert( uintp( pJobParams + 1 ) == uintp( pJob ) + sizeof( SpursJob_t ) );
|
||||
return pJobParams;
|
||||
}
|
||||
|
||||
extern void UnalignedBufferAddU16( );
|
||||
|
||||
|
||||
template <uint n> struct Log2{};
|
||||
template<>struct Log2<8> {enum{VALUE=3};};
|
||||
template<>struct Log2<16>{enum{VALUE=4};};
|
||||
template<>struct Log2<32>{enum{VALUE=5};};
|
||||
template<>struct Log2<256>{enum{VALUE=8};};
|
||||
|
||||
#define COMPILE_TIME_LOG2(VAL) ( Log2<VAL>::VALUE )
|
||||
|
||||
inline void ZeroMemAligned( void * p, uint nSize )
|
||||
{
|
||||
Assert( !( ( uintp( p ) | nSize ) & 15 ) );
|
||||
for( uint i = 0; i < nSize; i += 16 )
|
||||
{
|
||||
*( vec_uint4* )( uintp( p ) + i ) = (vec_uint4){0,0,0,0};
|
||||
}
|
||||
}
|
||||
|
||||
inline void CopyMemAligned( void * pDst, const void * pSrc, uint nSize )
|
||||
{
|
||||
Assert( !( ( uintp( pDst ) | uintp( pSrc ) | nSize ) & 15 ) );
|
||||
for( uint i = 0; i < nSize; i += 16 )
|
||||
{
|
||||
*( vec_uint4* )( uintp( pDst ) + i ) = *( vec_uint4* )( uintp( pSrc ) + i );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Reference implementation
|
||||
//
|
||||
template <uint nBitCount>
|
||||
class CBitArray
|
||||
{
|
||||
public:
|
||||
void Clear()
|
||||
{
|
||||
for( uint i = 0; i < ( nBitCount >> 7 ); ++i )
|
||||
{
|
||||
m_qword[i] = ( vec_uint4 ){0,0,0,0};
|
||||
}
|
||||
//m_nSetCount = 0;
|
||||
}
|
||||
void SetRange( uint nStart, uint nEnd )
|
||||
{
|
||||
nEnd = Min( nEnd, nBitCount );
|
||||
if( nStart > nEnd )
|
||||
return;
|
||||
//m_nSetCount = Max( nEnd, m_nSetCount );
|
||||
|
||||
uint nMask = uint( -1 ) >> ( nStart & 0x1F );
|
||||
for( uint i = ( nStart >> 5 ); i < ( nEnd >> 5); ++i )
|
||||
{
|
||||
m_u32[i] |= nMask;
|
||||
nMask = uint( -1 );
|
||||
}
|
||||
nMask &= ~( uint( -1 ) >> ( nEnd & 0x1F ) );
|
||||
m_u32[ nEnd >> 5 ] |= nMask;
|
||||
}
|
||||
//uint GetSetCount()const{return m_nSetCount;}
|
||||
|
||||
uint GetFirst1( uint nFrom )const
|
||||
{
|
||||
for( uint i = nFrom; i < nBitCount; ++i )
|
||||
if( GetBit( i ) )
|
||||
return i;
|
||||
return nBitCount;
|
||||
}
|
||||
|
||||
uint GetFirst0( uint nFrom )const
|
||||
{
|
||||
for( uint i = nFrom; i < nBitCount; ++i )
|
||||
if( !GetBit( i ) )
|
||||
return i;
|
||||
return nBitCount;
|
||||
}
|
||||
|
||||
uint GetBit( uint n )const
|
||||
{
|
||||
return m_u32[ n >> 5 ] & ( 0x80000000 >> ( n & 0x1F ) );
|
||||
}
|
||||
protected:
|
||||
union
|
||||
{
|
||||
vec_uint4 m_qword[ ( nBitCount + 127 ) / 128 ];
|
||||
uint32 m_u32[ ( nBitCount + 31 ) / 32 ];
|
||||
};
|
||||
//uint m_nSetCount;
|
||||
};
|
||||
|
||||
#endif // _PS3
|
||||
|
||||
#endif
|
||||
0
common/ps3/spugcm_lsring.h
Normal file
0
common/ps3/spugcm_lsring.h
Normal file
151
common/ps3/spugcm_lsring0.h
Normal file
151
common/ps3/spugcm_lsring0.h
Normal file
@@ -0,0 +1,151 @@
|
||||
//========== Copyright © Valve Corporation, All rights reserved. ========
|
||||
// Easy ("tier0") implementations of simple GCM contexts
|
||||
//
|
||||
#ifndef PS3_SPUGCM_LSRING0_HDR
|
||||
#define PS3_SPUGCM_LSRING0_HDR
|
||||
|
||||
class CSpuGcmMeasureBuffer: public CellGcmContextData
|
||||
{
|
||||
public:
|
||||
CSpuGcmMeasureBuffer( )
|
||||
{
|
||||
this->begin = 0;
|
||||
this->end = 0;
|
||||
this->current = 0;
|
||||
this->callback = CallbackDelegator;
|
||||
}
|
||||
|
||||
uint GetSizeBytes()const
|
||||
{
|
||||
return uintp( this->end );
|
||||
}
|
||||
uint GetSizeWords()const
|
||||
{
|
||||
return this->end - this->begin;
|
||||
}
|
||||
protected:
|
||||
void Callback( uint nCount )
|
||||
{
|
||||
this->end = ( uint32* )AlignValue( uintp( this->current + nCount ), 16 );
|
||||
}
|
||||
static int32_t CallbackDelegator( struct CellGcmContextData *pContext, uint32_t nCount )
|
||||
{
|
||||
static_cast<CSpuGcmMeasureBuffer*>( pContext )->Callback( nCount );
|
||||
return CELL_OK;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class CSpuGcmAlignedBuffer: public CellGcmContextData
|
||||
{
|
||||
public:
|
||||
|
||||
void Init( void * lsBuffer, uint lsBufferSize, uint eaBegin, uint nIoOffsetDelta )
|
||||
{
|
||||
uint nShift = ( eaBegin - uint( lsBuffer ) ) & 0x7F;
|
||||
this->begin = ( uint32* )( uintp( lsBuffer ) + nShift );
|
||||
m_eaBuffer = eaBegin;
|
||||
m_nIoOffsetDelta = nIoOffsetDelta;
|
||||
this->end = ( uint32* )( uintp( this->begin ) + lsBufferSize );
|
||||
this->current = this->begin;
|
||||
this->callback = CallbackDelegator;
|
||||
|
||||
Assert( uint( this->begin ) >= uint( lsBuffer ) && !( 0x7F & ( uint( this->begin ) ^ eaBegin ) ) );
|
||||
}
|
||||
|
||||
uint LsToLocalOffset( uint32 * lsCommand )
|
||||
{
|
||||
return EaToLocalOffset( LsToEa( lsCommand ) );
|
||||
}
|
||||
uint LsToEa( uint32 * lsCommand )
|
||||
{
|
||||
return uintp( lsCommand ) - uintp( this->begin ) + m_eaBuffer;
|
||||
}
|
||||
uint32 * EaToLs( uint32 eaCommand )
|
||||
{
|
||||
return ( uint32* )( ( eaCommand - m_eaBuffer ) + uintp( this->begin ) );
|
||||
}
|
||||
uint EaToLocalOffset( uint eaCommand )
|
||||
{
|
||||
return eaCommand + m_nIoOffsetDelta;
|
||||
}
|
||||
|
||||
void AlignWithNops()
|
||||
{
|
||||
while ( 0xF & uintp( this->current ) )
|
||||
{
|
||||
*( this->current++ ) = CELL_GCM_METHOD_NOP;
|
||||
}
|
||||
}
|
||||
|
||||
void AppendJumpToNext()
|
||||
{
|
||||
*( this->current++ ) = CELL_GCM_JUMP( LsToLocalOffset( this->current + 1 ) );
|
||||
}
|
||||
void AppendJumpToNextIfNeededForDmaPutJtn()
|
||||
{
|
||||
// the JTN is not needed if the whole buffer fits into 128-byte cache line
|
||||
Assert( this->current < this->end );
|
||||
if( ( uintp( this->current ) ^ ( uintp( this->end ) - 1 ) ) & -128 )
|
||||
{
|
||||
// the first and the last bytes are in separate cache lines; we need to insert JTN at the beginning
|
||||
AppendJumpToNext();
|
||||
}
|
||||
}
|
||||
|
||||
void Append( const SetLabelAlignedCommand_t & cmd )
|
||||
{
|
||||
AlignWithNops();
|
||||
*( vector unsigned int * )( this->current ) = cmd.m_cmd.m_vuCmd;
|
||||
this->current += 4;
|
||||
}
|
||||
|
||||
|
||||
// DMA put a segment of command buffer using JTN method. The start of the buffer shall be JTN, unless the buffer is small enough to be DMA'd
|
||||
void DmaPutJtn()
|
||||
{
|
||||
Assert( this->current <= this->end && !( 0x7F & ( uintp( this->begin ) ^ m_eaBuffer ) ) );
|
||||
while ( this->current < this->end )
|
||||
{
|
||||
*( this->current ++ ) = CELL_GCM_METHOD_NOP;
|
||||
}
|
||||
// skip the first 16 bytes where JTN resides; skip the whole cache line, while we're at it
|
||||
Assert( this->current <= this->end );
|
||||
uint32 * pRest = ( uint32* )( ( uintp( this->begin ) + 128 ) & -128 );
|
||||
Assert( pRest > this->begin );
|
||||
if ( pRest < this->end )
|
||||
{
|
||||
//VjobSpuLog( "lsring0 put %p..%p->%X tag:%d\n", pRest, this->end, LsToEa( pRest ), VJOB_IOBUFFER_DMATAG );
|
||||
Assert( !( 0x7F & LsToEa( pRest ) ) );
|
||||
VjobDmaPut( pRest, LsToEa( pRest ), uintp( this->end ) - uintp( pRest ), VJOB_IOBUFFER_DMATAG, 0, 0 );
|
||||
//VjobSpuLog( "lsring0 putf (JTN %X) %p..%p->%X tag:%d\n", *this->begin, this->begin, pRest, m_eaBuffer, VJOB_IOBUFFER_DMATAG );
|
||||
VjobDmaPutf( this->begin, m_eaBuffer, uintp( pRest ) - uintp( this->begin ), VJOB_IOBUFFER_DMATAG, 0, 0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
// this case is pretty simple and doesn't require JTN at the beginning of the memory block , because it will be DMA'd atomically
|
||||
// check that we really start the block with JTN
|
||||
//Assert( CELL_GCM_JUMP( EaToLocalOffset( m_eaBuffer ) + 4 ) == *this->begin );
|
||||
// overwrite JTN with NOP as we won't need JTN
|
||||
//*this->begin = CELL_GCM_METHOD_NOP;
|
||||
Assert( pRest >= this->end && this->end - this->begin <= 128 / 4 );
|
||||
VjobDmaPutf( this->begin, m_eaBuffer, uintp( this->end ) - uintp( this->begin ), VJOB_IOBUFFER_DMATAG, 0, 0 );
|
||||
}
|
||||
}
|
||||
protected:
|
||||
uint m_eaBuffer;
|
||||
uint m_nIoOffsetDelta;
|
||||
protected:
|
||||
void Callback( uint nCount )
|
||||
{
|
||||
DebuggerBreak();
|
||||
}
|
||||
static int32_t CallbackDelegator( struct CellGcmContextData *pContext, uint32_t nCount )
|
||||
{
|
||||
static_cast<CSpuGcmAlignedBuffer*>( pContext )->Callback( nCount );
|
||||
return CELL_ERROR_ERROR_FLAG;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
382
common/ps3/vjobchain.cpp
Normal file
382
common/ps3/vjobchain.cpp
Normal file
@@ -0,0 +1,382 @@
|
||||
//========== Copyright © Valve Corporation, All rights reserved. ========
|
||||
|
||||
#include "vjobchain.h"
|
||||
#include "vjobutils.h"
|
||||
#include "vjobs/root.h"
|
||||
#include "tier1/strtools.h"
|
||||
#include "tier0/miniprofiler.h"
|
||||
|
||||
CMiniProfiler g_mpRun, g_mpJoin, g_mpPush, g_mpPush2;
|
||||
|
||||
int VjobChain::Init( VJobsRoot * pRoot, uint nMaxContention, const char* pFormatName, ... )
|
||||
{
|
||||
Assert( !( uintp( &m_guard ) & 0x7F ) );
|
||||
{
|
||||
va_list args
|
||||
va_start( args, pFormatName );
|
||||
V_vsnprintf( m_name, sizeof( m_name ), pFormatName, args );
|
||||
}
|
||||
|
||||
cell::Spurs::JobChainAttribute attr;
|
||||
uint8_t nVjobChainPriority[8] = {0,12,12,12,12,12,0,0}; // priority lower than the main job queue, in order to yield
|
||||
attr.initialize( &attr, m_headBlock, 128, 1, nVjobChainPriority, nMaxContention, true, 0,1, false, 256, 1 );
|
||||
attr.setName( m_name );
|
||||
m_pLastBlock = NULL; // NOT running by default
|
||||
CELL_MUST_SUCCEED( JobChain::createWithAttribute( &pRoot->m_spurs, &m_spursJobChain, &attr ) );
|
||||
|
||||
V_memset( &m_notifyArea, 0, sizeof( m_notifyArea ) );
|
||||
V_memset( &m_jobNotify, 0, sizeof( m_jobNotify ) );
|
||||
m_jobNotify.header = *( pRoot->m_pJobNotify );
|
||||
m_jobNotify.header.useInOutBuffer = 1;
|
||||
Assert( !( uint( &m_jobNotify ) & 63 ) ); // should be 64-byte aligned
|
||||
AddInputDma( &m_jobNotify, sizeof( m_notifyArea ), &m_notifyArea );
|
||||
m_notifyArea.m_nCopyFrom = 1;
|
||||
m_notifyArea.m_nCopyTo = 0; // SPU will mark copyTo = 1, PPU will mark it back to 0; at this time, we may actually mark the notify as completed
|
||||
m_jobNotify.workArea.userData[1] = 0; // function: default
|
||||
|
||||
|
||||
CELL_MUST_SUCCEED( m_guard.initialize( &m_spursJobChain, &m_guard, 1 /*notifyCount*/, 1 /*requestSpuCount(ignored)*/, 1 /*autoReset*/ ) );
|
||||
|
||||
m_headBlock[0] = CELL_SPURS_JOB_COMMAND_SYNC; // wait for all previous list commands to finish
|
||||
m_headBlock[1] = CELL_SPURS_JOB_COMMAND_JOB( &m_jobNotify );
|
||||
m_headBlock[2] = CELL_SPURS_JOB_COMMAND_GUARD( &m_guard );
|
||||
m_headBlock[BLOCK_COMMANDS] = ( uint64 )-1ll;
|
||||
|
||||
CELL_MUST_SUCCEED( m_spursJobChain.run() );
|
||||
|
||||
m_nSpinWaitNotify = 0;
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
int VjobChain::Run()
|
||||
{
|
||||
if( !IsRunning() )
|
||||
{
|
||||
CMiniProfilerGuard mpg( &g_mpRun );
|
||||
Assert( m_notifyArea.m_nCopyTo ); // the jobchain must be joined if its not in Running state
|
||||
m_notifyArea.m_nCopyTo = 0;
|
||||
m_pLastBlock = m_headBlock;
|
||||
m_nCurrentBlockCommands = 3; // right after the SYNC-JOB(notify)-GUARD prefix
|
||||
m_headBlock[m_nCurrentBlockCommands] = CELL_SPURS_JOB_COMMAND_JTS;
|
||||
// __lwsync(); // make sure we complete sync reset and write JTS before notify - probably not necessary because the guard should have a barrier for sure
|
||||
m_guard.notify(); // let the jobchain go
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
return CELL_OK; // it's valid to try to run a running chain in our interface...
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
int VjobChain::End( )
|
||||
{
|
||||
if( IsRunning() )
|
||||
{
|
||||
Assert( m_pLastBlock[m_nCurrentBlockCommands] == CELL_SPURS_JOB_COMMAND_JTS );
|
||||
Assert( m_notifyArea.m_nCopyTo == 0 ); // make sure we reset sync correctly
|
||||
m_pLastBlock[m_nCurrentBlockCommands] = CELL_SPURS_JOB_COMMAND_RESET_PC( m_headBlock );
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return -1; // you should not end non-running instance
|
||||
}
|
||||
|
||||
void VjobChain::Shutdown()
|
||||
{
|
||||
if( IsRunning() )
|
||||
{
|
||||
m_pLastBlock[m_nCurrentBlockCommands] = CELL_SPURS_JOB_COMMAND_END;
|
||||
}
|
||||
m_spursJobChain.shutdown();
|
||||
m_spursJobChain.join();
|
||||
}
|
||||
|
||||
|
||||
int VjobChain::Join()
|
||||
{
|
||||
if( IsRunning() )
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
CellSpursJobChainInfo info;
|
||||
m_spursJobChain.getInfo( &info );
|
||||
#endif
|
||||
CMiniProfilerGuard mpg( &g_mpJoin );
|
||||
|
||||
// wait for reset sync notification to come through
|
||||
volatile job_notify::NotifyArea_t *pNotify = &m_notifyArea;
|
||||
Assert( pNotify->m_nCopyFrom );
|
||||
while( !pNotify->m_nCopyTo )
|
||||
{
|
||||
++m_nSpinWaitNotify;
|
||||
}
|
||||
if( m_nSpinWaitNotify )
|
||||
{
|
||||
// <HACK> Sergiy : I'm taking this out for now because jobchain double-buffering is effectively temporarily hosed
|
||||
// Warning( "VjobChain %s: stall in join, %d spins\n", m_name, m_nSpinWaitNotify );
|
||||
m_nSpinWaitNotify = 0;
|
||||
}
|
||||
|
||||
// free up the memory of the jobs that are now known to have dispatched
|
||||
if( m_headBlock != m_pLastBlock )
|
||||
{
|
||||
uint64 *pBlock = m_headBlock;
|
||||
do
|
||||
{
|
||||
Assert( pBlock[BLOCK_COMMANDS] == (uint64)-1ll );
|
||||
uint64 eaNext = pBlock[BLOCK_COMMANDS - 1];
|
||||
Assert( ( eaNext & 0xFFFFFFFF00000007ull ) == 3 );
|
||||
pBlock = ( uint64 * )( uintp( eaNext ) & ~7 );
|
||||
Assert( pBlock[BLOCK_COMMANDS] == (uint64)-1ll );
|
||||
delete[]pBlock;
|
||||
}
|
||||
while( pBlock != m_pLastBlock );
|
||||
}
|
||||
m_pLastBlock = NULL; // idle state
|
||||
return CELL_OK;
|
||||
}
|
||||
else
|
||||
return 0; // valid to join twice;
|
||||
}
|
||||
|
||||
|
||||
void VjobChain::Push( uint64 nCommand )
|
||||
{
|
||||
Assert( IsRunning() );
|
||||
uint64 * pNextCommand = &m_pLastBlock[m_nCurrentBlockCommands++]; // JTS to patch
|
||||
if( m_nCurrentBlockCommands < BLOCK_COMMANDS )
|
||||
{
|
||||
CMiniProfilerGuard mpg( &g_mpPush );
|
||||
pNextCommand[1] = CELL_SPURS_JOB_COMMAND_JTS;
|
||||
__lwsync(); // ordering: create JobHeader, insert next JTS --> patch current JTS with JOB command
|
||||
*pNextCommand = nCommand;
|
||||
}
|
||||
else
|
||||
{
|
||||
CMiniProfilerGuard mpg( &g_mpPush2 );
|
||||
m_pLastBlock = new uint64[BLOCK_COMMANDS+1];
|
||||
m_pLastBlock[BLOCK_COMMANDS] = ( uint64 )-1ll; // marker
|
||||
m_pLastBlock[0] = nCommand;
|
||||
m_pLastBlock[m_nCurrentBlockCommands = 1] = CELL_SPURS_JOB_COMMAND_JTS;
|
||||
__lwsync(); // ordering: create JobHeader, allocate & reset new segment with JOB command in it --> patch JTS in old segment with NEXT command
|
||||
*pNextCommand = CELL_SPURS_JOB_COMMAND_NEXT( m_pLastBlock );
|
||||
}
|
||||
}
|
||||
|
||||
void VjobChain::Push( const uint64 * nCommands, uint nCommandCount )
|
||||
{
|
||||
// todo: make it more optimal by removing extra lwsync's
|
||||
for( uint i = 0; i < nCommandCount; ++i )
|
||||
{
|
||||
Push( nCommands[i] );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int VjobChain2::Init( VJobsRoot * pRoot, uint nMaxContention, const char* pName )
|
||||
{
|
||||
m_vjobChainRing = ( VjobChain * )MemAlloc_AllocAligned( VJOB_CHAINS * sizeof( VjobChain ), 128 );
|
||||
|
||||
for( uint i = 0; i < 2; ++i )
|
||||
{
|
||||
int nError = m_vjobChainRing[i].Init( pRoot, nMaxContention, "%s%d", pName, i );
|
||||
if( nError )
|
||||
return nError;
|
||||
}
|
||||
|
||||
m_nCurrentChain = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void VjobChain2::Begin()
|
||||
{
|
||||
m_vjobChainRing[( m_nCurrentChain + 1 ) % VJOB_CHAINS].Join();
|
||||
VjobChain & jobchain = Jobchain();
|
||||
jobchain.Join(); // join the jobchain that we'll be using now
|
||||
jobchain.Run();
|
||||
}
|
||||
|
||||
void VjobChain2::End()
|
||||
{
|
||||
VjobChain & jobchain = Jobchain();
|
||||
jobchain.End();
|
||||
m_nCurrentChain = ( m_nCurrentChain + 1 ) % VJOB_CHAINS; // swap the job chain
|
||||
}
|
||||
|
||||
void VjobChain2::Shutdown()
|
||||
{
|
||||
for( uint i = 0; i < 2; ++i )
|
||||
{
|
||||
m_vjobChainRing[i].Shutdown();
|
||||
}
|
||||
MemAlloc_FreeAligned( m_vjobChainRing );
|
||||
}
|
||||
|
||||
|
||||
|
||||
int VjobChain3::Init( VJobsRoot * pRoot, uint nMaxContention, uint nMinCommandsPerBuffer, uint8_t nVjobChainPriority[8], const char* pName, uint nDmaTags )
|
||||
{
|
||||
m_pName = pName;
|
||||
const uint nSizeOfJobDescriptor = 128, nMaxGrabbedJob = 4;
|
||||
// we need at least 4 commands
|
||||
uint nBufferSize = sizeof( VjobBufferHeader_t ) + sizeof( uint64 ) * MAX( nMinCommandsPerBuffer, VjobBuffer_t::VERBATIM_COMMAND_COUNT + 2 ); // +2 is for user's command and JTN
|
||||
nBufferSize = AlignValue( nBufferSize, 128 );
|
||||
m_nMaxCommandsPerBuffer = ( nBufferSize - sizeof( VjobBufferHeader_t ) ) / sizeof( uint64 );
|
||||
|
||||
uint nAllocationSize = sizeof( cell::Spurs::JobChain ) + nBufferSize * BUFFER_COUNT;
|
||||
m_pSpursJobChain = ( cell::Spurs::JobChain* )MemAlloc_AllocAligned( nAllocationSize, 128 );
|
||||
V_memset( m_pSpursJobChain, 0, nAllocationSize );
|
||||
m_pBuffers[0] = ( VjobBuffer_t * )( m_pSpursJobChain + 1 );
|
||||
m_nFrontBuffer = 0;
|
||||
m_pFrontBuffer = m_pBuffers[0];
|
||||
for( int i = 1; i < BUFFER_COUNT; ++i )
|
||||
{
|
||||
m_pBuffers[i] = ( VjobBuffer_t * )( uintp( m_pBuffers[ i - 1 ] ) + nBufferSize );
|
||||
}
|
||||
|
||||
cell::Spurs::JobChainAttribute attr;
|
||||
attr.initialize( &attr, m_pFrontBuffer->m_spursCommands, nSizeOfJobDescriptor, nMaxGrabbedJob, nVjobChainPriority, nMaxContention, true, nDmaTags, nDmaTags + 1, false, 256, 1 );
|
||||
attr.setName( pName );
|
||||
CELL_MUST_SUCCEED( JobChain::createWithAttribute( &pRoot->m_spurs, m_pSpursJobChain, &attr ) );
|
||||
|
||||
for( int i = 0; i < BUFFER_COUNT; ++i )
|
||||
{
|
||||
Assert( !( uintp( m_pBuffers[i] ) & 0x7F ) );
|
||||
m_pBuffers[i]->Init( pRoot, m_pSpursJobChain );
|
||||
}
|
||||
|
||||
StartCommandBuffer( 0, CELL_SPURS_JOB_COMMAND_NOP );
|
||||
CELL_MUST_SUCCEED( m_pSpursJobChain->run() );
|
||||
|
||||
#ifdef _DEBUG
|
||||
sys_timer_usleep( 100 );
|
||||
#endif
|
||||
|
||||
m_nSpinWaitNotify = 0;
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void VjobBuffer_t::Init( VJobsRoot * pRoot, cell::Spurs::JobChain * pSpursJobChain )
|
||||
{
|
||||
m_jobNotify.header = *( pRoot->m_pJobNotify );
|
||||
m_jobNotify.header.useInOutBuffer = 1;
|
||||
AddInputDma( &m_jobNotify, sizeof( m_notifyArea ), &m_notifyArea );
|
||||
m_notifyArea.m_nCopyFrom = 1;
|
||||
// SPU will mark copyTo = 1, PPU will mark it back to 0; at this time, we may actually mark the notify as completed; 1 means "previous buffer is free"
|
||||
// Then we'll start command buffer, which will reset the ready flag. But then we run the jobchain, which will run job_notify and set the flag back again, thus starting the ring
|
||||
m_notifyArea.m_nCopyTo = 1;
|
||||
m_jobNotify.workArea.userData[1] = 0; // function: default
|
||||
|
||||
uint nCommands = 0;
|
||||
m_spursCommands[nCommands++] = CELL_SPURS_JOB_COMMAND_SYNC; // wait for all previous list commands to finish
|
||||
m_spursCommands[nCommands++] = CELL_SPURS_JOB_COMMAND_JOB( &m_jobNotify );
|
||||
#ifdef VJOBCHAIN3_GUARD
|
||||
Assert( !( uintp( &m_guard ) & -128 ) );
|
||||
CELL_MUST_SUCCEED( m_guard.initialize( pSpursJobChain, &m_guard, 1 /*notifyCount*/, 1 /*requestSpuCount(ignored)*/, 1 /*autoReset*/ ) );
|
||||
m_spursCommands[nCommands++] = CELL_SPURS_JOB_COMMAND_GUARD( &m_guard );
|
||||
#endif
|
||||
#ifdef _DEBUG
|
||||
m_jobNotify2.header = *( pRoot->m_pJobNotify );
|
||||
m_jobNotify2.header.useInOutBuffer = 1;
|
||||
AddInputDma( &m_jobNotify2, sizeof( m_notifyArea2 ), &m_notifyArea2 );
|
||||
m_jobNotify2.workArea.userData[1] = 0; // function: default
|
||||
m_notifyArea2.m_nCopyFrom = 1;
|
||||
m_notifyArea2.m_nCopyTo = 0; // just for debugging, to see when this job gets executed
|
||||
m_spursCommands[nCommands++] = CELL_SPURS_JOB_COMMAND_JOB( &m_jobNotify2 );
|
||||
#endif
|
||||
Assert( nCommands == VjobBuffer_t::VERBATIM_COMMAND_COUNT );
|
||||
m_spursCommands[VjobBuffer_t::VERBATIM_COMMAND_COUNT] = CELL_SPURS_JOB_COMMAND_JTS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void VjobChain3::WaitForEntryNotify( VjobBuffer_t * pBuffer )
|
||||
{
|
||||
volatile job_notify::NotifyArea_t *pNotify = &pBuffer->m_notifyArea;
|
||||
Assert( pNotify->m_nCopyFrom );
|
||||
while( !pNotify->m_nCopyTo )
|
||||
{
|
||||
++m_nSpinWaitNotify;
|
||||
sys_timer_usleep( 30 );
|
||||
}
|
||||
if( m_nSpinWaitNotify )
|
||||
{
|
||||
Warning( "VjobChain %s: stall in WaitForEntryNotify, %d spins\n", m_pName, m_nSpinWaitNotify );
|
||||
m_nSpinWaitNotify = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
uint64* VjobChain3::SwapCommandBuffer( uint64 nInsertCommand )
|
||||
{
|
||||
uint64 * pSpursIsSpinningHere = &m_pFrontBuffer->m_spursCommands[ m_nFrontBufferCommandCount ];
|
||||
|
||||
Assert( m_nFrontBufferCommandCount < m_nMaxCommandsPerBuffer );
|
||||
uint nNext1Buffer = ( m_nFrontBuffer + 1 ) % BUFFER_COUNT, nNext2Buffer = ( m_nFrontBuffer + 2 ) % BUFFER_COUNT;
|
||||
VjobBuffer_t * pNext1Buffer = m_pBuffers[ nNext1Buffer ], * pNext2Buffer = m_pBuffers[ nNext2Buffer ];
|
||||
|
||||
// before we can declare the next1 buffer "front", we need to make sure it's fully ready to accept commands, i.e. that it was fully read by SPURS
|
||||
// for that, we check the next2 buffer notification area
|
||||
|
||||
WaitForEntryNotify( pNext1Buffer );
|
||||
WaitForEntryNotify( pNext2Buffer );
|
||||
|
||||
// if next2 buffer has been notified, next1 must have been notified long ago
|
||||
Assert( pNext1Buffer->m_notifyArea.m_nCopyTo );
|
||||
uint64* pInsertionPoint = StartCommandBuffer( nNext1Buffer, nInsertCommand );
|
||||
Assert( pNext1Buffer == m_pFrontBuffer );
|
||||
// implicit lwsync is here
|
||||
*pSpursIsSpinningHere = CELL_SPURS_JOB_COMMAND_NEXT( pNext1Buffer->m_spursCommands ); // jump to the next buffer
|
||||
|
||||
return pInsertionPoint;
|
||||
}
|
||||
|
||||
|
||||
uint64* VjobChain3::StartCommandBuffer( uint nNext1Buffer, uint64 nInsertCommand )
|
||||
{
|
||||
m_nFrontBuffer = nNext1Buffer;
|
||||
m_pFrontBuffer = m_pBuffers[ nNext1Buffer ];
|
||||
// the ready marker is presumed to be present; SPURS must have gone through this buffer in the previous ring, otherwise we can't use it
|
||||
Assert( m_pFrontBuffer->m_notifyArea.m_nCopyTo == 1 );
|
||||
// reset the ready marker; SPURS didn't get to this buffer yet (we're about to reuse them and we didn't jump to it yet)
|
||||
m_pFrontBuffer->m_notifyArea.m_nCopyTo = 0;
|
||||
#ifdef _DEBUG
|
||||
m_pFrontBuffer->m_notifyArea2.m_nCopyFrom++;
|
||||
m_pFrontBuffer->m_notifyArea2.m_nCopyTo = 0;
|
||||
#endif
|
||||
uint64 * pCommand = &m_pFrontBuffer->m_spursCommands[ VjobBuffer_t::VERBATIM_COMMAND_COUNT ];
|
||||
*pCommand = nInsertCommand;
|
||||
m_pFrontBuffer->m_spursCommands[ VjobBuffer_t::VERBATIM_COMMAND_COUNT + 1 ] = CELL_SPURS_JOB_COMMAND_JTS;
|
||||
m_nFrontBufferCommandCount = VjobBuffer_t::VERBATIM_COMMAND_COUNT + 1;
|
||||
#ifdef VJOBCHAIN3_GUARD
|
||||
m_pFrontBuffer->m_guard.notify(); // let the jobchain go through
|
||||
// implicit lwsync is here
|
||||
#else
|
||||
__lwsync();
|
||||
#endif
|
||||
return pCommand;
|
||||
}
|
||||
|
||||
|
||||
void VjobChain3::End()
|
||||
{
|
||||
Assert( m_nFrontBufferCommandCount < m_nMaxCommandsPerBuffer );
|
||||
m_pFrontBuffer->m_spursCommands[ m_nFrontBufferCommandCount ] = CELL_SPURS_JOB_COMMAND_END;
|
||||
m_pSpursJobChain->shutdown();
|
||||
}
|
||||
|
||||
void VjobChain3::Join()
|
||||
{
|
||||
Assert( m_pFrontBuffer->m_spursCommands[ m_nFrontBufferCommandCount ] == CELL_SPURS_JOB_COMMAND_END );
|
||||
m_pSpursJobChain->join();
|
||||
|
||||
MemAlloc_FreeAligned( m_pSpursJobChain );
|
||||
m_pSpursJobChain = NULL;
|
||||
}
|
||||
189
common/ps3/vjobchain.h
Normal file
189
common/ps3/vjobchain.h
Normal file
@@ -0,0 +1,189 @@
|
||||
//========== Copyright © Valve Corporation, All rights reserved. ========
|
||||
#if !defined( VJOBS_CHAINUTILS_HDR ) && defined( _PS3 )
|
||||
#define VJOBS_CHAINUTILS_HDR
|
||||
|
||||
#include "tier0/platform.h"
|
||||
#include <cell/spurs.h>
|
||||
#include "ps3/job_notify.h"
|
||||
struct VJobsRoot;
|
||||
|
||||
//
|
||||
// The chain consists of blocks of commands; the head block has SYNC-JOB(notify)-GUARD sequence
|
||||
// initially the chain waits on the GUARD , and is ready to "run". "Run" means releasing the guard.
|
||||
// I'm using GUARD instead of JTS because patching JTS will render it unpatcheable until jobchain execution completes;
|
||||
// and if it's unpatcheable, it effectively can't be used as a guard for the next cycle
|
||||
// Each block refers to the next one by inserting NEXT in the very last slot
|
||||
// the last block is pointed to by m_pLastBlock, which is NULL initially (before entering the "run" state)
|
||||
//
|
||||
//
|
||||
struct ALIGN128 VjobChain
|
||||
{
|
||||
public:
|
||||
cell::Spurs::JobChain m_spursJobChain;
|
||||
cell::Spurs::JobGuard m_guard;
|
||||
CellSpursJob64 m_jobNotify;
|
||||
job_notify::NotifyArea_t m_notifyArea;
|
||||
|
||||
enum { BLOCK_COMMANDS = 256 };
|
||||
uint64 m_headBlock[BLOCK_COMMANDS+1]; // in one variant, the first entry in this list is used for END command; overwrite it with NOP to release the list
|
||||
uint64 * m_pLastBlock;
|
||||
uint m_nCurrentBlockCommands;
|
||||
uint m_nSpinWaitNotify;
|
||||
|
||||
char m_name[16];
|
||||
public:
|
||||
int Init( VJobsRoot * pRoot, uint nMaxContention, const char* pFormatName, ... );
|
||||
bool IsRunning()const { return m_pLastBlock != NULL; }
|
||||
|
||||
int Run();
|
||||
void Push( uint64 nCommand );
|
||||
void Push( const uint64 * nCommands, uint nCommandCount );
|
||||
int End( );
|
||||
int Join();
|
||||
void Shutdown();
|
||||
|
||||
JobChain & Jobchain() { return m_spursJobChain; }
|
||||
|
||||
}ALIGN128_POST;
|
||||
|
||||
|
||||
// VjobChain2 hosts 2 jobchains and double-buffers between them
|
||||
class VjobChain2
|
||||
{
|
||||
public:
|
||||
int Init( VJobsRoot * pRoot, uint nMaxContention, const char* pName );
|
||||
void Begin();
|
||||
void End();
|
||||
void Shutdown();
|
||||
|
||||
VjobChain& Jobchain(){ return m_vjobChainRing[m_nCurrentChain]; }
|
||||
|
||||
protected:
|
||||
enum{VJOB_CHAINS = 2};
|
||||
VjobChain *m_vjobChainRing; // may be more than double-buffered if necessary
|
||||
uint m_nCurrentChain;
|
||||
};
|
||||
|
||||
|
||||
//#define VJOBCHAIN3_GUARD
|
||||
|
||||
struct ALIGN128 VjobBufferHeader_t
|
||||
{
|
||||
public:
|
||||
#ifdef VJOBCHAIN3_GUARD
|
||||
cell::Spurs::JobGuard m_guard;
|
||||
#endif
|
||||
CellSpursJob64 m_jobNotify;
|
||||
job_notify::NotifyArea_t m_notifyArea;
|
||||
#ifdef _DEBUG
|
||||
CellSpursJob64 m_jobNotify2;
|
||||
job_notify::NotifyArea_t m_notifyArea2;
|
||||
#endif
|
||||
}
|
||||
ALIGN128_POST;
|
||||
|
||||
struct VjobBuffer_t: public VjobBufferHeader_t
|
||||
{
|
||||
public:
|
||||
enum ConstEnum_t
|
||||
{
|
||||
VERBATIM_COMMAND_COUNT = 2 // we employ syncronization scheme: SYNC, JOB(notify), ...
|
||||
#ifdef VJOBCHAIN3_GUARD // we add GUARD, ...
|
||||
+ 1
|
||||
#endif
|
||||
#ifdef _DEBUG
|
||||
+ 1 // we add JOB(notify2), ...
|
||||
#else
|
||||
|
||||
#endif
|
||||
};
|
||||
uint64 m_spursCommands[16]; // there will be at least verbatim commands, a user command, and a NEXT
|
||||
|
||||
void Init( VJobsRoot * pRoot, cell::Spurs::JobChain * pSpursJobChain );
|
||||
};
|
||||
|
||||
// VjobChain3 has only 1 jobchain but double-buffers it to facilitate continuous wait-free execution
|
||||
class VjobChain3
|
||||
{
|
||||
protected:
|
||||
enum ConstEnum_t {
|
||||
BUFFER_COUNT = 4
|
||||
};
|
||||
cell::Spurs::JobChain *m_pSpursJobChain;
|
||||
VjobBuffer_t * m_pBuffers[BUFFER_COUNT];
|
||||
VjobBuffer_t * m_pFrontBuffer;
|
||||
uint m_nFrontBuffer; // the buffer currently in use
|
||||
|
||||
uint m_nMaxCommandsPerBuffer; // max count of commands fitting into one buffer
|
||||
uint m_nFrontBufferCommandCount; // count of commands in the current front buffer
|
||||
uint m_nSpinWaitNotify; // did we spin waiting for job_notify ? if we did, we probably need to increase the command buffer size
|
||||
uint64 m_nLastCommandPushed; // at the beginning of the scene, it's considered to be synced up
|
||||
|
||||
|
||||
const char * m_pName;
|
||||
|
||||
public:
|
||||
|
||||
int Init( VJobsRoot * pRoot, uint nMaxContention, uint nMinCommandsPerBuffer, uint8_t nVjobChainPriority[8], const char* pName, uint nDmaTags );
|
||||
uint64* Push( uint64 nCommand );
|
||||
uint64* PushSyncJobSync( uint64 nCommand );
|
||||
void PushSync();
|
||||
void Shutdown(){End();Join();}
|
||||
void End();
|
||||
void Join();
|
||||
|
||||
protected:
|
||||
void WaitForEntryNotify( VjobBuffer_t * pBuffer );
|
||||
uint64* StartCommandBuffer( uint nNext1Buffer, uint64 nInsertCommand );
|
||||
uint64* SwapCommandBuffer( uint64 nInsertCommand );
|
||||
};
|
||||
|
||||
|
||||
|
||||
inline uint64* VjobChain3::Push( uint64 nCommand )
|
||||
{
|
||||
uint64 * pInsertionPoint;
|
||||
if( m_nFrontBufferCommandCount == m_nMaxCommandsPerBuffer - 1 )
|
||||
{
|
||||
// time to switch the buffer
|
||||
pInsertionPoint = SwapCommandBuffer( nCommand );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pFrontBuffer->m_spursCommands[ m_nFrontBufferCommandCount + 1 ] = CELL_SPURS_JOB_COMMAND_JTS;
|
||||
__lwsync(); // Important: this sync ensures that both the command header AND JTS are written before SPU sees them
|
||||
pInsertionPoint = &m_pFrontBuffer->m_spursCommands[ m_nFrontBufferCommandCount ];
|
||||
*pInsertionPoint = nCommand;
|
||||
m_nFrontBufferCommandCount ++;
|
||||
}
|
||||
m_nLastCommandPushed = nCommand;
|
||||
return pInsertionPoint;
|
||||
}
|
||||
|
||||
|
||||
inline void VjobChain3::PushSync()
|
||||
{
|
||||
Push( CELL_SPURS_JOB_COMMAND_LWSYNC );
|
||||
}
|
||||
|
||||
|
||||
inline uint64* VjobChain3::PushSyncJobSync( uint64 nCommand )
|
||||
{
|
||||
if( m_nLastCommandPushed != CELL_SPURS_JOB_COMMAND_LWSYNC )
|
||||
{
|
||||
// we need to wait for previous jobs to finish in order to patch the state efficiently
|
||||
// todo: double-buffer the states to avoid stalls, but only if we become SPU-bound here (un
|
||||
Push( CELL_SPURS_JOB_COMMAND_LWSYNC );
|
||||
}
|
||||
uint64 * pInsertionPoint = Push( nCommand );
|
||||
|
||||
// this is instead of stalling successor because I'm not sure if it stalls all logical successors (some of which may be picked up by other SPUs)
|
||||
// the SYNC here will ensure completion of the previous job before the new jobs will be pushed
|
||||
Push( CELL_SPURS_JOB_COMMAND_LWSYNC );
|
||||
|
||||
return pInsertionPoint;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
175
common/ps3/vjobchain4.cpp
Normal file
175
common/ps3/vjobchain4.cpp
Normal file
@@ -0,0 +1,175 @@
|
||||
//========== Copyright © Valve Corporation, All rights reserved. ========
|
||||
|
||||
#include "ps3/vjobchain4.h"
|
||||
|
||||
vec_uint4 g_cellSpursJts16 = ( vec_uint4 ){ uint( CELL_SPURS_JOB_COMMAND_JTS >> 32 ), uint( CELL_SPURS_JOB_COMMAND_JTS ), uint( CELL_SPURS_JOB_COMMAND_JTS >> 32 ), uint( CELL_SPURS_JOB_COMMAND_JTS ) };
|
||||
|
||||
#ifndef SPU
|
||||
|
||||
#include "ps3/vjobutils.h"
|
||||
#include "vjobs/root.h"
|
||||
#include "tier1/strtools.h"
|
||||
#include "tier0/miniprofiler.h"
|
||||
|
||||
int VjobChain4::Init( VJobsRoot * pRoot, uint nMaxContention, uint nMinCommandsPerBuffer, uint8_t nVjobChainPriority[8], uint nSizeOfJobDescriptor, uint nMaxGrabbedJob, const char* pName, uint nDmaTags )
|
||||
{
|
||||
m_pName = pName;
|
||||
m_eaThis = this;
|
||||
// we need at least 4 commands
|
||||
uint nBufferSize = sizeof( VjobChain4BufferHeader_t ) + sizeof( uint64 ) * MAX( nMinCommandsPerBuffer, VjobChain4Buffer_t::VERBATIM_COMMAND_COUNT + 2 ); // +2 is for user's command and JTN
|
||||
nBufferSize = AlignValue( nBufferSize, 128 );
|
||||
m_nMaxCommandsPerBuffer = ( nBufferSize - sizeof( VjobChain4BufferHeader_t ) ) / sizeof( uint64 );
|
||||
|
||||
uint nAllocationSize = sizeof( cell::Spurs::JobChain ) + nBufferSize * BUFFER_COUNT;
|
||||
m_pSpursJobChain = ( cell::Spurs::JobChain* )MemAlloc_AllocAligned( nAllocationSize, 128 );
|
||||
V_memset( m_pSpursJobChain, 0, nAllocationSize );
|
||||
m_pBuffers[0] = ( VjobChain4Buffer_t * )( m_pSpursJobChain + 1 );
|
||||
m_nFrontBuffer = 0;
|
||||
m_pFrontBuffer = m_pBuffers[0];
|
||||
for( int i = 1; i < BUFFER_COUNT; ++i )
|
||||
{
|
||||
m_pBuffers[i] = ( VjobChain4Buffer_t * )( uintp( m_pBuffers[ i - 1 ] ) + nBufferSize );
|
||||
}
|
||||
|
||||
cell::Spurs::JobChainAttribute attr;
|
||||
attr.initialize( &attr, m_pFrontBuffer->m_spursCommands, nSizeOfJobDescriptor, nMaxGrabbedJob, nVjobChainPriority, nMaxContention, true, nDmaTags, nDmaTags + 1, false, Max<uint>( 256, nSizeOfJobDescriptor ), 1 );
|
||||
attr.setName( pName );
|
||||
CELL_MUST_SUCCEED( JobChain::createWithAttribute( &pRoot->m_spurs, m_pSpursJobChain, &attr ) );
|
||||
|
||||
for( int i = 0; i < BUFFER_COUNT; ++i )
|
||||
{
|
||||
Assert( !( uintp( m_pBuffers[i] ) & 0x7F ) );
|
||||
m_pBuffers[i]->Init( pRoot, m_pSpursJobChain, m_nMaxCommandsPerBuffer );
|
||||
}
|
||||
|
||||
*StartCommandBuffer( 0 ) = CELL_SPURS_JOB_COMMAND_NOP;
|
||||
CELL_MUST_SUCCEED( m_pSpursJobChain->run() );
|
||||
|
||||
#ifdef _DEBUG
|
||||
sys_timer_usleep( 100 );
|
||||
#endif
|
||||
|
||||
m_nSpinWaitNotify = 0;
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void VjobChain4Buffer_t::Init( VJobsRoot * pRoot, cell::Spurs::JobChain * pSpursJobChain, uint nMaxCommandsPerBuffer )
|
||||
{
|
||||
Assert( 0 == ( 0x7F & uintp( &m_jobNotify ) ) );
|
||||
m_jobNotify.header = *( pRoot->m_pJobNotify );
|
||||
m_jobNotify.header.useInOutBuffer = 1;
|
||||
AddInputDma( &m_jobNotify, sizeof( m_notifyArea ), &m_notifyArea );
|
||||
m_notifyArea.m_nCopyFrom = 1;
|
||||
// SPU will mark copyTo = 1, PPU will mark it back to 0; at this time, we may actually mark the notify as completed; 1 means "previous buffer is free"
|
||||
// Then we'll start command buffer, which will reset the ready flag. But then we run the jobchain, which will run job_notify and set the flag back again, thus starting the ring
|
||||
m_notifyArea.m_nCopyTo = 1;
|
||||
m_jobNotify.workArea.userData[1] = 0; // function: default
|
||||
|
||||
uint nCommands = 0;
|
||||
m_spursCommands[nCommands++] = CELL_SPURS_JOB_COMMAND_SYNC; // wait for all previous list commands to finish
|
||||
m_spursCommands[nCommands++] = CELL_SPURS_JOB_COMMAND_JOB( &m_jobNotify );
|
||||
Assert( nCommands == VjobChain4Buffer_t::VERBATIM_COMMAND_COUNT );
|
||||
while( nCommands < nMaxCommandsPerBuffer )
|
||||
{
|
||||
m_spursCommands[nCommands++] = CELL_SPURS_JOB_COMMAND_JTS;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void VjobChain4::End()
|
||||
{
|
||||
Assert( m_nFrontBufferCommandCount < m_nMaxCommandsPerBuffer );
|
||||
m_pFrontBuffer->m_spursCommands[ m_nFrontBufferCommandCount ] = CELL_SPURS_JOB_COMMAND_END;
|
||||
m_pSpursJobChain->shutdown();
|
||||
}
|
||||
|
||||
void VjobChain4::Join()
|
||||
{
|
||||
Assert( m_pFrontBuffer->m_spursCommands[ m_nFrontBufferCommandCount ] == CELL_SPURS_JOB_COMMAND_END );
|
||||
m_pSpursJobChain->join();
|
||||
|
||||
MemAlloc_FreeAligned( m_pSpursJobChain );
|
||||
m_pSpursJobChain = NULL;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
void VjobChain4::WaitForEntryNotify( VjobChain4Buffer_t * eaBuffer )
|
||||
{
|
||||
volatile job_notify::NotifyArea_t *eaNotify = &eaBuffer->m_notifyArea;
|
||||
// it doesn't matter what DMA tag we'll use for synchronous DMA get
|
||||
Assert( VjobDmaGetUint32( (uint)&eaNotify->m_nCopyFrom, DMATAG_SYNC, 0, 0 ) );
|
||||
while( !VjobDmaGetUint32( (uint)&eaNotify->m_nCopyTo, DMATAG_SYNC, 0, 0 ) )
|
||||
{
|
||||
++m_nSpinWaitNotify;
|
||||
#ifndef SPU
|
||||
sys_timer_usleep( 30 );
|
||||
#endif
|
||||
}
|
||||
if( m_nSpinWaitNotify )
|
||||
{
|
||||
VjobSpuLog( "VjobChain: stall in WaitForEntryNotify, %d spins\n", m_nSpinWaitNotify );
|
||||
m_nSpinWaitNotify = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
uint64* VjobChain4::SwapCommandBuffer( )
|
||||
{
|
||||
uint64 * eaSpursIsSpinningHere = &m_pFrontBuffer->m_spursCommands[ m_nFrontBufferCommandCount ];
|
||||
|
||||
Assert( m_nFrontBufferCommandCount < m_nMaxCommandsPerBuffer );
|
||||
uint nNext1Buffer = ( m_nFrontBuffer + 1 ) % BUFFER_COUNT, nNext2Buffer = ( m_nFrontBuffer + 2 ) % BUFFER_COUNT;
|
||||
VjobChain4Buffer_t * eaNext1Buffer = m_pBuffers[ nNext1Buffer ], * eaNext2Buffer = m_pBuffers[ nNext2Buffer ];
|
||||
|
||||
// before we can declare the next1 buffer "front", we need to make sure it's fully ready to accept commands, i.e. that it was fully read by SPURS
|
||||
// for that, we check the next2 buffer notification area
|
||||
|
||||
WaitForEntryNotify( eaNext1Buffer );
|
||||
WaitForEntryNotify( eaNext2Buffer );
|
||||
|
||||
// if next2 buffer has been notified, next1 must have been notified long ago
|
||||
Assert( VjobDmaGetUint32( (uint)&eaNext1Buffer->m_notifyArea.m_nCopyTo, DMATAG_SYNC, 0, 0 ) );
|
||||
uint64* pInsertionPoint = StartCommandBuffer( nNext1Buffer );
|
||||
Assert( eaNext1Buffer == m_pFrontBuffer );
|
||||
// implicit lwsync is here
|
||||
VjobDmaPutfUint64( CELL_SPURS_JOB_COMMAND_NEXT( eaNext1Buffer->m_spursCommands ), (uint)eaSpursIsSpinningHere, DMATAG_SYNC ); // jump to the next buffer
|
||||
|
||||
return pInsertionPoint;
|
||||
}
|
||||
|
||||
#ifndef SPU
|
||||
void FillSpursJts( uint64 * eaCommands, uint nBufferCount )
|
||||
{
|
||||
for( uint i = 0; i < nBufferCount; ++i )
|
||||
eaCommands[ i ] = CELL_SPURS_JOB_COMMAND_JTS;
|
||||
}
|
||||
#endif
|
||||
|
||||
//
|
||||
// Initializes the buffer BEFORE the jobchain can jump to it. It's important to only jump to the next buffer
|
||||
// after this function returns (either by inserting NEXT into previous buffer, or by call Run() on the jobchain)
|
||||
// because this function lacks the necessary synchronization to operate safely on a buffer in-flight
|
||||
//
|
||||
uint64* VjobChain4::StartCommandBuffer( uint nNext1Buffer )
|
||||
{
|
||||
m_nFrontBuffer = nNext1Buffer;
|
||||
m_pFrontBuffer = m_pBuffers[ nNext1Buffer ];
|
||||
// the ready marker is presumed to be present; SPURS must have gone through this buffer in the previous ring, otherwise we can't use it
|
||||
Assert( VjobDmaGetUint32( (uint)&m_pFrontBuffer->m_notifyArea.m_nCopyTo, DMATAG_SYNC, 0, 0) == 1 );
|
||||
// reset the ready marker; SPURS didn't get to this buffer yet (we're about to reuse them and we didn't jump to it yet)
|
||||
VjobDmaPutfUint32( 0, (uint)&m_pFrontBuffer->m_notifyArea.m_nCopyTo, DMATAG_SYNC );
|
||||
uint64 * eaCommand = &m_pFrontBuffer->m_spursCommands[ VjobChain4Buffer_t::VERBATIM_COMMAND_COUNT ];
|
||||
//VjobDmaPutfUint64( nInsertCommand, (uint)eaCommand, DMATAG_SYNC );
|
||||
|
||||
FillSpursJts( eaCommand, m_nMaxCommandsPerBuffer - VjobChain4Buffer_t::VERBATIM_COMMAND_COUNT );
|
||||
m_nFrontBufferCommandCount = VjobChain4Buffer_t::VERBATIM_COMMAND_COUNT + 1;
|
||||
LWSYNC_PPU_ONLY();
|
||||
return eaCommand;
|
||||
}
|
||||
|
||||
|
||||
101
common/ps3/vjobchain4.h
Normal file
101
common/ps3/vjobchain4.h
Normal file
@@ -0,0 +1,101 @@
|
||||
//========== Copyright © Valve Corporation, All rights reserved. ========
|
||||
//
|
||||
// This job chain wrapper is an infinite job chain with dynamic job submission
|
||||
// It is single-threaded and not very fast in the current implementation,
|
||||
// so it'll need to be optimized if we ever become SPU bound and use it often.
|
||||
// To make it multithreaded, the easiest way is to lock every operation
|
||||
// with a compare-exchange flag and a spin-wait, and use getllar to update "this" and the flag atomically
|
||||
//
|
||||
#if !defined( VJOBSCHAINU4_HDR ) && defined( _PS3 )
|
||||
#define VJOBSCHAINU4_HDR
|
||||
|
||||
#include <cell/spurs.h>
|
||||
#include "ps3/job_notify.h"
|
||||
#include "ps3/spu_job_shared.h"
|
||||
struct VJobsRoot;
|
||||
|
||||
|
||||
struct ALIGN128 VjobChain4BufferHeader_t
|
||||
{
|
||||
public:
|
||||
CellSpursJob64 m_jobNotify;
|
||||
job_notify::NotifyArea_t m_notifyArea;
|
||||
}
|
||||
ALIGN128_POST;
|
||||
|
||||
struct VjobChain4Buffer_t: public VjobChain4BufferHeader_t
|
||||
{
|
||||
public:
|
||||
enum ConstEnum_t
|
||||
{
|
||||
VERBATIM_COMMAND_COUNT = 2 // we employ syncronization scheme: SYNC, JOB(notify), ...
|
||||
};
|
||||
uint64 m_spursCommands[32]; // there will be at least verbatim commands, a user command, and a NEXT
|
||||
|
||||
void Init( VJobsRoot * pRoot, cell::Spurs::JobChain * pSpursJobChain, uint nMaxCommandsPerBuffer );
|
||||
};
|
||||
|
||||
// VjobChain4 has only 1 jobchain but double-buffers it to facilitate continuous wait-free execution
|
||||
class ALIGN16 VjobChain4
|
||||
{
|
||||
protected:
|
||||
enum ConstEnum_t {
|
||||
BUFFER_COUNT = 4
|
||||
};
|
||||
VjobChain4 * m_eaThis;
|
||||
cell::Spurs::JobChain *m_pSpursJobChain;
|
||||
VjobChain4Buffer_t * m_pBuffers[BUFFER_COUNT];
|
||||
VjobChain4Buffer_t * m_pFrontBuffer;
|
||||
uint m_nFrontBuffer; // the buffer currently in use
|
||||
|
||||
uint m_nMaxCommandsPerBuffer; // max count of commands fitting into one buffer
|
||||
uint m_nFrontBufferCommandCount; // count of commands in the current front buffer
|
||||
uint m_nSpinWaitNotify; // did we spin waiting for job_notify ? if we did, we probably need to increase the command buffer size
|
||||
|
||||
|
||||
const char * m_pName;
|
||||
|
||||
public:
|
||||
#ifndef SPU
|
||||
int Init( VJobsRoot * pRoot, uint nMaxContention, uint nMinCommandsPerBuffer, uint8_t nVjobChainPriority[8], uint nSizeOfJobDescriptor, uint nMaxGrabbedJob, const char* pName, uint nDmaTags );
|
||||
void Shutdown(){End();Join();}
|
||||
void End();
|
||||
void Join();
|
||||
void Run(){ m_pSpursJobChain->run();}
|
||||
#endif
|
||||
uint64* Push( );
|
||||
const char * GetName()const {return m_pName;}
|
||||
|
||||
protected:
|
||||
void WaitForEntryNotify( VjobChain4Buffer_t * eaBuffer );
|
||||
uint64* StartCommandBuffer( uint nNext1Buffer );
|
||||
uint64* SwapCommandBuffer( );
|
||||
}
|
||||
ALIGN128_POST;
|
||||
|
||||
|
||||
|
||||
inline uint64* VjobChain4::Push( )
|
||||
{
|
||||
uint64 * pInsertionPoint;
|
||||
Assert( m_nFrontBufferCommandCount < m_nMaxCommandsPerBuffer );
|
||||
if( m_nFrontBufferCommandCount == m_nMaxCommandsPerBuffer - 1 )
|
||||
{
|
||||
// time to switch the buffer
|
||||
pInsertionPoint = SwapCommandBuffer( );
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert( VjobDmaGetUint64( (uint)&m_pFrontBuffer->m_spursCommands[ m_nFrontBufferCommandCount + 1 ], DMATAG_SYNC, 0, 0 ) == CELL_SPURS_JOB_COMMAND_JTS );
|
||||
LWSYNC_PPU_ONLY(); // Important: this sync ensures that both the command header AND JTS are written before SPU sees them
|
||||
pInsertionPoint = &m_pFrontBuffer->m_spursCommands[ m_nFrontBufferCommandCount ];
|
||||
m_nFrontBufferCommandCount ++;
|
||||
}
|
||||
return pInsertionPoint;
|
||||
}
|
||||
|
||||
extern vec_uint4 g_cellSpursJts16;
|
||||
|
||||
extern void FillSpursJts( uint64 * eaCommands, uint nBufferCount );
|
||||
|
||||
#endif
|
||||
107
common/ps3/vjobpool.h
Normal file
107
common/ps3/vjobpool.h
Normal file
@@ -0,0 +1,107 @@
|
||||
//========== Copyright © Valve Corporation, All rights reserved. ========
|
||||
#if !defined( VJOBPOOL_HDR ) && defined( _PS3 )
|
||||
#define VJOBPOOL_HDR
|
||||
|
||||
|
||||
|
||||
#include "ps3/spu_job_shared.h"
|
||||
#include "cell/atomic.h"
|
||||
//#include "ps3/vjobutils.h"
|
||||
|
||||
|
||||
|
||||
template < typename Job, uint nAlignment = 128 >
|
||||
class VjobPool
|
||||
{
|
||||
public:
|
||||
|
||||
#ifndef SPU
|
||||
void Init( uint nJobs ) // must be integer-power-of-2
|
||||
{
|
||||
m_nJobIndexMask = nJobs - 1;
|
||||
Assert( !( m_nJobIndexMask & nJobs ) );
|
||||
uint nSizeToAllocate = sizeof( Job ) * nJobs;
|
||||
m_eaPool = ( Job* )MemAlloc_AllocAligned( nSizeToAllocate, nAlignment );
|
||||
V_memset( m_eaPool, 0, nSizeToAllocate );
|
||||
m_nNextJob = 0;
|
||||
m_nWaitSpins = 0;
|
||||
}
|
||||
|
||||
void Shutdown()
|
||||
{
|
||||
// wait for all jobs to finish
|
||||
for ( uint i = 0; i <= m_nJobIndexMask; ++i )
|
||||
{
|
||||
volatile const uint64 * pEa = ( const uint64* ) & m_eaPool[i];
|
||||
while ( *pEa )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
MemAlloc_FreeAligned( m_eaPool );
|
||||
m_eaPool = NULL;
|
||||
}
|
||||
Job * Alloc( const CellSpursJobHeader & header ) // the job header is freed when its eaBinary is overwritten with zeroes from within the job
|
||||
{
|
||||
Job * pJob = Alloc();
|
||||
V_memcpy( pJob, &header, sizeof( header ) );
|
||||
return pJob;
|
||||
}
|
||||
#endif
|
||||
|
||||
Job * Alloc( ); // the job header is freed when its eaBinary is overwritten with zeroes from within the job
|
||||
|
||||
uint GetMarker()const { return m_nNextJob; }
|
||||
uint GetCapacity()const { return m_nJobIndexMask + 1; }
|
||||
int GetReserve( uint nMarker )const { return int( GetCapacity() - ( m_nNextJob - nMarker ) ); }
|
||||
|
||||
public:
|
||||
uint m_nWaitSpins; // debug field
|
||||
protected:
|
||||
Job * m_eaPool;
|
||||
uint m_nJobIndexMask;
|
||||
|
||||
// this is just a hint
|
||||
uint m_nNextJob;
|
||||
};
|
||||
|
||||
|
||||
template < typename Job, uint nAlignment >
|
||||
Job * VjobPool<Job, nAlignment>::Alloc( ) // the job header is freed when its eaBinary is overwritten with zeroes from within the job
|
||||
{
|
||||
uint nNextJob = m_nNextJob;
|
||||
Job * eaJob = NULL;
|
||||
for( ;; )
|
||||
{
|
||||
eaJob = &m_eaPool[ ( nNextJob & m_nJobIndexMask ) ];
|
||||
#ifdef SPU
|
||||
char ALIGN128 temp[128] ALIGN128_POST;
|
||||
// it's important to fill in and compare the first 64 bits, because that's where eaBinary is, and the first 32 bits (MSB) may be zero
|
||||
if( 0 == cellAtomicCompareAndSwap64( (uint64*)temp, ( uintp )eaJob, 0, ~0ull ) )
|
||||
{
|
||||
break;
|
||||
}
|
||||
++m_nWaitSpins;
|
||||
#else
|
||||
// it's important to fill in and compare the first 64 bits, because that's where eaBinary is, and the first 32 bits (MSB) may be zero
|
||||
if( 0 == cellAtomicCompareAndSwap64( ( uint64* )eaJob, 0, ~0ull ) )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if( ( ( ( ++nNextJob ) ^ m_nNextJob ) & m_nJobIndexMask ) == 0 )
|
||||
{
|
||||
// we've made the full circle; yield
|
||||
m_nWaitSpins++;
|
||||
sys_timer_usleep( 30 );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
// this is just a hint
|
||||
m_nNextJob = nNextJob + 1;
|
||||
|
||||
return eaJob;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
175
common/ps3/vjobutils.cpp
Normal file
175
common/ps3/vjobutils.cpp
Normal file
@@ -0,0 +1,175 @@
|
||||
//========== Copyright © Valve Corporation, All rights reserved. ========
|
||||
#include "vjobutils.h"
|
||||
|
||||
#ifdef VJOBS_ON_SPURS
|
||||
|
||||
const char * HumanReadableCellResult( int nCellResult )
|
||||
{
|
||||
switch ( nCellResult )
|
||||
{
|
||||
case CELL_SPURS_CORE_ERROR_AGAIN:
|
||||
return "CELL_SPURS_CORE_ERROR_AGAIN";
|
||||
case CELL_SPURS_CORE_ERROR_INVAL:
|
||||
return "CELL_SPURS_CORE_ERROR_INVAL";
|
||||
case CELL_SPURS_CORE_ERROR_NOSYS:
|
||||
return "CELL_SPURS_CORE_ERROR_NOSYS";
|
||||
case CELL_SPURS_CORE_ERROR_NOMEM:
|
||||
return "CELL_SPURS_CORE_ERROR_NOMEM";
|
||||
case CELL_SPURS_CORE_ERROR_SRCH:
|
||||
return "CELL_SPURS_CORE_ERROR_SRCH";
|
||||
case CELL_SPURS_CORE_ERROR_NOENT:
|
||||
return "CELL_SPURS_CORE_ERROR_NOENT";
|
||||
case CELL_SPURS_CORE_ERROR_NOEXEC:
|
||||
return "CELL_SPURS_CORE_ERROR_NOEXEC";
|
||||
case CELL_SPURS_CORE_ERROR_DEADLK:
|
||||
return "CELL_SPURS_CORE_ERROR_DEADLK";
|
||||
case CELL_SPURS_CORE_ERROR_PERM:
|
||||
return "CELL_SPURS_CORE_ERROR_PERM";
|
||||
case CELL_SPURS_CORE_ERROR_BUSY:
|
||||
return "CELL_SPURS_CORE_ERROR_BUSY";
|
||||
case CELL_SPURS_CORE_ERROR_ABORT:
|
||||
return "CELL_SPURS_CORE_ERROR_ABORT";
|
||||
case CELL_SPURS_CORE_ERROR_FAULT:
|
||||
return "CELL_SPURS_CORE_ERROR_FAULT";
|
||||
case CELL_SPURS_CORE_ERROR_CHILD:
|
||||
return "CELL_SPURS_CORE_ERROR_CHILD";
|
||||
case CELL_SPURS_CORE_ERROR_STAT:
|
||||
return "CELL_SPURS_CORE_ERROR_STAT";
|
||||
case CELL_SPURS_CORE_ERROR_ALIGN:
|
||||
return "CELL_SPURS_CORE_ERROR_ALIGN";
|
||||
case CELL_SPURS_CORE_ERROR_NULL_POINTER:
|
||||
return "CELL_SPURS_CORE_ERROR_NULL_POINTER";
|
||||
|
||||
|
||||
case CELL_SPURS_POLICY_MODULE_ERROR_AGAIN:
|
||||
return "CELL_SPURS_POLICY_MODULE_ERROR_AGAIN";
|
||||
case CELL_SPURS_POLICY_MODULE_ERROR_INVAL:
|
||||
return "CELL_SPURS_POLICY_MODULE_ERROR_INVAL";
|
||||
case CELL_SPURS_POLICY_MODULE_ERROR_NOSYS:
|
||||
return "CELL_SPURS_POLICY_MODULE_ERROR_NOSYS";
|
||||
case CELL_SPURS_POLICY_MODULE_ERROR_NOMEM:
|
||||
return "CELL_SPURS_POLICY_MODULE_ERROR_NOMEM";
|
||||
case CELL_SPURS_POLICY_MODULE_ERROR_SRCH:
|
||||
return "CELL_SPURS_POLICY_MODULE_ERROR_SRCH";
|
||||
case CELL_SPURS_POLICY_MODULE_ERROR_NOENT:
|
||||
return "CELL_SPURS_POLICY_MODULE_ERROR_NOENT";
|
||||
case CELL_SPURS_POLICY_MODULE_ERROR_NOEXEC:
|
||||
return "CELL_SPURS_POLICY_MODULE_ERROR_NOEXEC";
|
||||
case CELL_SPURS_POLICY_MODULE_ERROR_DEADLK:
|
||||
return "CELL_SPURS_POLICY_MODULE_ERROR_DEADLK";
|
||||
case CELL_SPURS_POLICY_MODULE_ERROR_PERM:
|
||||
return "CELL_SPURS_POLICY_MODULE_ERROR_PERM";
|
||||
case CELL_SPURS_POLICY_MODULE_ERROR_BUSY:
|
||||
return "CELL_SPURS_POLICY_MODULE_ERROR_BUSY";
|
||||
case CELL_SPURS_POLICY_MODULE_ERROR_ABORT:
|
||||
return "CELL_SPURS_POLICY_MODULE_ERROR_ABORT";
|
||||
case CELL_SPURS_POLICY_MODULE_ERROR_FAULT:
|
||||
return "CELL_SPURS_POLICY_MODULE_ERROR_FAULT";
|
||||
case CELL_SPURS_POLICY_MODULE_ERROR_CHILD:
|
||||
return "CELL_SPURS_POLICY_MODULE_ERROR_CHILD";
|
||||
case CELL_SPURS_POLICY_MODULE_ERROR_STAT:
|
||||
return "CELL_SPURS_POLICY_MODULE_ERROR_STAT";
|
||||
case CELL_SPURS_POLICY_MODULE_ERROR_ALIGN:
|
||||
return "CELL_SPURS_POLICY_MODULE_ERROR_ALIGN";
|
||||
case CELL_SPURS_POLICY_MODULE_ERROR_NULL_POINTER:
|
||||
return "CELL_SPURS_POLICY_MODULE_ERROR_NULL_POINTER";
|
||||
|
||||
|
||||
case CELL_SPURS_TASK_ERROR_AGAIN:
|
||||
return "CELL_SPURS_TASK_ERROR_AGAIN";
|
||||
case CELL_SPURS_TASK_ERROR_INVAL:
|
||||
return "CELL_SPURS_TASK_ERROR_INVAL";
|
||||
case CELL_SPURS_TASK_ERROR_NOSYS:
|
||||
return "CELL_SPURS_TASK_ERROR_NOSYS";
|
||||
case CELL_SPURS_TASK_ERROR_NOMEM:
|
||||
return "CELL_SPURS_TASK_ERROR_NOMEM";
|
||||
case CELL_SPURS_TASK_ERROR_SRCH:
|
||||
return "CELL_SPURS_TASK_ERROR_SRCH";
|
||||
case CELL_SPURS_TASK_ERROR_NOENT:
|
||||
return "CELL_SPURS_TASK_ERROR_NOENT";
|
||||
case CELL_SPURS_TASK_ERROR_NOEXEC:
|
||||
return "CELL_SPURS_TASK_ERROR_NOEXEC";
|
||||
case CELL_SPURS_TASK_ERROR_DEADLK:
|
||||
return "CELL_SPURS_TASK_ERROR_DEADLK";
|
||||
case CELL_SPURS_TASK_ERROR_PERM:
|
||||
return "CELL_SPURS_TASK_ERROR_PERM";
|
||||
case CELL_SPURS_TASK_ERROR_BUSY:
|
||||
return "CELL_SPURS_TASK_ERROR_BUSY";
|
||||
case CELL_SPURS_TASK_ERROR_ABORT:
|
||||
return "CELL_SPURS_TASK_ERROR_ABORT";
|
||||
case CELL_SPURS_TASK_ERROR_FAULT:
|
||||
return "CELL_SPURS_TASK_ERROR_FAULT";
|
||||
case CELL_SPURS_TASK_ERROR_CHILD:
|
||||
return "CELL_SPURS_TASK_ERROR_CHILD";
|
||||
case CELL_SPURS_TASK_ERROR_STAT:
|
||||
return "CELL_SPURS_TASK_ERROR_STAT";
|
||||
case CELL_SPURS_TASK_ERROR_ALIGN:
|
||||
return "CELL_SPURS_TASK_ERROR_ALIGN";
|
||||
case CELL_SPURS_TASK_ERROR_NULL_POINTER:
|
||||
return "CELL_SPURS_TASK_ERROR_NULL_POINTER";
|
||||
case CELL_SPURS_TASK_ERROR_FATAL:
|
||||
return "CELL_SPURS_TASK_ERROR_FATAL";
|
||||
|
||||
case CELL_SPURS_TASK_ERROR_SHUTDOWN:
|
||||
return "CELL_SPURS_TASK_ERROR_SHUTDOWN";
|
||||
|
||||
case CELL_SPURS_JOB_ERROR_AGAIN:
|
||||
return "CELL_SPURS_JOB_ERROR_AGAIN";
|
||||
case CELL_SPURS_JOB_ERROR_INVAL:
|
||||
return "CELL_SPURS_JOB_ERROR_INVAL";
|
||||
case CELL_SPURS_JOB_ERROR_NOSYS:
|
||||
return "CELL_SPURS_JOB_ERROR_NOSYS";
|
||||
case CELL_SPURS_JOB_ERROR_NOMEM:
|
||||
return "CELL_SPURS_JOB_ERROR_NOMEM";
|
||||
case CELL_SPURS_JOB_ERROR_SRCH:
|
||||
return "CELL_SPURS_JOB_ERROR_SRCH";
|
||||
case CELL_SPURS_JOB_ERROR_NOENT:
|
||||
return "CELL_SPURS_JOB_ERROR_NOENT";
|
||||
case CELL_SPURS_JOB_ERROR_NOEXEC:
|
||||
return "CELL_SPURS_JOB_ERROR_NOEXEC";
|
||||
case CELL_SPURS_JOB_ERROR_DEADLK:
|
||||
return "CELL_SPURS_JOB_ERROR_DEADLK";
|
||||
case CELL_SPURS_JOB_ERROR_PERM:
|
||||
return "CELL_SPURS_JOB_ERROR_PERM";
|
||||
case CELL_SPURS_JOB_ERROR_BUSY:
|
||||
return "CELL_SPURS_JOB_ERROR_BUSY";
|
||||
case CELL_SPURS_JOB_ERROR_JOB_DESCRIPTOR:
|
||||
return "CELL_SPURS_JOB_ERROR_JOB_DESCRIPTOR";
|
||||
case CELL_SPURS_JOB_ERROR_JOB_DESCRIPTOR_SIZE:
|
||||
return "CELL_SPURS_JOB_ERROR_JOB_DESCRIPTOR_SIZE";
|
||||
case CELL_SPURS_JOB_ERROR_FAULT:
|
||||
return "CELL_SPURS_JOB_ERROR_FAULT";
|
||||
case CELL_SPURS_JOB_ERROR_CHILD:
|
||||
return "CELL_SPURS_JOB_ERROR_CHILD";
|
||||
case CELL_SPURS_JOB_ERROR_STAT:
|
||||
return "CELL_SPURS_JOB_ERROR_STAT";
|
||||
case CELL_SPURS_JOB_ERROR_ALIGN:
|
||||
return "CELL_SPURS_JOB_ERROR_ALIGN";
|
||||
case CELL_SPURS_JOB_ERROR_NULL_POINTER:
|
||||
return "CELL_SPURS_JOB_ERROR_NULL_POINTER";
|
||||
|
||||
case CELL_SPURS_JOB_ERROR_MEMORY_SIZE:
|
||||
return "CELL_SPURS_JOB_ERROR_MEMORY_SIZE";
|
||||
case CELL_SPURS_JOB_ERROR_UNKNOWN_COMMAND:
|
||||
return "CELL_SPURS_JOB_ERROR_UNKNOWN_COMMAND";
|
||||
case CELL_SPURS_JOB_ERROR_JOBLIST_ALIGNMENT:
|
||||
return "CELL_SPURS_JOB_ERROR_JOBLIST_ALIGNMENT";
|
||||
case CELL_SPURS_JOB_ERROR_JOB_ALIGNMENT:
|
||||
return "CELL_SPURS_JOB_ERROR_JOB_ALIGNMENT";
|
||||
case CELL_SPURS_JOB_ERROR_CALL_OVERFLOW:
|
||||
return "CELL_SPURS_JOB_ERROR_CALL_OVERFLOW";
|
||||
case CELL_SPURS_JOB_ERROR_ABORT:
|
||||
return "CELL_SPURS_JOB_ERROR_ABORT";
|
||||
case CELL_SPURS_JOB_ERROR_DMALIST_ELEMENT:
|
||||
return "CELL_SPURS_JOB_ERROR_DMALIST_ELEMENT";
|
||||
case CELL_SPURS_JOB_ERROR_NUM_CACHE:
|
||||
return "CELL_SPURS_JOB_ERROR_NUM_CACHE";
|
||||
case CELL_SPURS_JOB_ERROR_INVALID_BINARY:
|
||||
return "CELL_SPURS_JOB_ERROR_INVALID_BINARY";
|
||||
|
||||
default:
|
||||
return "<unknown>";
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
89
common/ps3/vjobutils.h
Normal file
89
common/ps3/vjobutils.h
Normal file
@@ -0,0 +1,89 @@
|
||||
//========== Copyright © Valve Corporation, All rights reserved. ========
|
||||
#ifndef VJOB_SPURS_UTILS_HDR
|
||||
#define VJOB_SPURS_UTILS_HDR
|
||||
|
||||
#ifndef _PS3
|
||||
#error "This is PS3 specific header"
|
||||
#endif
|
||||
|
||||
|
||||
#include "vjobs_interface.h"
|
||||
#include "ps3/vjobutils_shared.h"
|
||||
|
||||
#ifdef VJOBS_ON_SPURS
|
||||
#include "tier0/logging.h"
|
||||
#include "tier0/dbg.h"
|
||||
#include "spu_printf.h"
|
||||
#include "tier0/memalloc.h"
|
||||
#include <cell/spurs.h>
|
||||
#include <cell/spurs/system_workload.h>
|
||||
using namespace ::cell::Spurs;
|
||||
|
||||
DECLARE_LOGGING_CHANNEL( LOG_VJOBS );
|
||||
|
||||
extern const char * HumanReadableCellResult( int nCellResult );
|
||||
inline int CellVerify( int nResult, const char * pCmd, LoggingSeverity_t severity )
|
||||
{
|
||||
Assert( nResult == CELL_OK );
|
||||
if( nResult != CELL_OK )
|
||||
{
|
||||
InternalMsg( LOG_VJOBS, severity, "Cell error %08X (%s) in\n\t%s\n", nResult, HumanReadableCellResult(nResult), pCmd );
|
||||
}
|
||||
return nResult;
|
||||
}
|
||||
|
||||
inline int CellVerify2( int nResult, const char * pCmd, const char * pFile, const int nLine, LoggingSeverity_t severity )
|
||||
{
|
||||
Assert( nResult == CELL_OK );
|
||||
if( nResult != CELL_OK )
|
||||
{
|
||||
InternalMsg( LOG_VJOBS, severity, "Cell error %08X (%s) in\n\t%s\n\t%s:%d", nResult, HumanReadableCellResult(nResult), pCmd, pFile, nLine );
|
||||
}
|
||||
return nResult;
|
||||
}
|
||||
|
||||
#define CELL_VERIFY( CMD ) CellVerify2( CMD, #CMD, __FILE__, __LINE__, LS_ASSERT )
|
||||
#define CELL_MUST_SUCCEED( CMD ) CellVerify2( CMD, #CMD, __FILE__, __LINE__, LS_ERROR )
|
||||
#define CELL_MUST_SUCCEED2( CMD, DESC ) CellVerify2( CMD, DESC, __FILE__, __LINE__, LS_ERROR )
|
||||
|
||||
|
||||
inline CellSpursJob64* NewJob64( const CellSpursJobHeader & jobHeader )
|
||||
{
|
||||
CellSpursJob64 * pJob = (CellSpursJob64 *)MemAlloc_AllocAligned( sizeof(CellSpursJob64), sizeof(CellSpursJob64) );
|
||||
pJob->header = jobHeader;
|
||||
pJob->workArea.dmaList[0] = 0;
|
||||
pJob->workArea.dmaList[1] = 0;
|
||||
return pJob;
|
||||
};
|
||||
|
||||
|
||||
|
||||
inline CellSpursJob128* NewJob128( const CellSpursJobHeader & jobHeader )
|
||||
{
|
||||
CellSpursJob128 * pJob = (CellSpursJob128 *)MemAlloc_AllocAligned( sizeof(CellSpursJob128), sizeof(CellSpursJob128) );
|
||||
__dcbz( pJob );
|
||||
pJob->header = jobHeader;
|
||||
return pJob;
|
||||
};
|
||||
|
||||
inline CellSpursJob256* NewJob256( const CellSpursJobHeader & jobHeader )
|
||||
{
|
||||
CellSpursJob256 * pJob = (CellSpursJob256 *)MemAlloc_AllocAligned( sizeof(CellSpursJob256), sizeof(CellSpursJob256) );
|
||||
__dcbz( pJob );
|
||||
__dcbz( ((uint8*)pJob) + 128 );
|
||||
pJob->header = jobHeader;
|
||||
return pJob;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
inline void DeleteJob( T * pJob )
|
||||
{
|
||||
MemAlloc_FreeAligned( pJob );
|
||||
}
|
||||
|
||||
|
||||
#endif // VJOBS_ON_SPURS
|
||||
|
||||
DECLARE_LOGGING_CHANNEL(LOG_VJOBS);
|
||||
|
||||
#endif
|
||||
224
common/ps3/vjobutils_shared.h
Normal file
224
common/ps3/vjobutils_shared.h
Normal file
@@ -0,0 +1,224 @@
|
||||
//========== Copyright © Valve Corporation, All rights reserved. ========
|
||||
// This is shared between SPU and PPU
|
||||
|
||||
#ifndef COMMON_PS3_VJOBUTILS_SHARED_HDR
|
||||
#define COMMON_PS3_VJOBUTILS_SHARED_HDR
|
||||
|
||||
|
||||
|
||||
#ifndef _PS3
|
||||
#error "This is PS3 specific header"
|
||||
#endif
|
||||
|
||||
#include "spu_job_shared.h"
|
||||
#include <cell/spurs/job_descriptor.h>
|
||||
|
||||
|
||||
template <typename T>
|
||||
inline void AddInputDma( T * pJob, uint nSize, const void * pEa )
|
||||
{
|
||||
Assert( !( nSize & 0xF ) );
|
||||
Assert( !( pJob->header.sizeDmaList & ( sizeof( uint64 ) - 1 ) ) );
|
||||
//int nError = cellSpursJobGetInputList( &pJob->workArea.dmaList[pJob->header.sizeDmaList / sizeof( uint64_t )], nSize, (uint32) pEa );
|
||||
//Assert( nError == CELL_OK );
|
||||
pJob->workArea.dmaList[pJob->header.sizeDmaList / sizeof( uint64_t )] = ( uint64( nSize ) << 32 ) | ( uint32 )pEa;
|
||||
|
||||
// ( nSIze << 32 ) | pEa
|
||||
pJob->header.sizeDmaList += sizeof( uint64_t );
|
||||
pJob->header.sizeInOrInOut += nSize;
|
||||
Assert( pJob->header.sizeDmaList <= sizeof( pJob->workArea ) );
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void AlignInputDma( T * pJob )
|
||||
{
|
||||
pJob->workArea.dmaList[pJob->header.sizeDmaList / sizeof( uint64_t )] = 0;
|
||||
pJob->header.sizeDmaList = AlignValue( pJob->header.sizeDmaList, 16 );
|
||||
Assert( pJob->header.sizeDmaList <= sizeof( pJob->workArea ) );
|
||||
}
|
||||
|
||||
inline void AddCacheDma( struct CellSpursJob128 * pJob, uint nSize, const void * pEa )
|
||||
{
|
||||
int nError = cellSpursJobGetInputList( &pJob->workArea.dmaList[( pJob->header.sizeDmaList + pJob->header.sizeCacheDmaList ) / sizeof( uint64 ) ], nSize, (uint32)pEa );
|
||||
( void )nError;
|
||||
Assert( nError == CELL_OK );
|
||||
pJob->header.sizeCacheDmaList += sizeof( uint64_t );
|
||||
}
|
||||
|
||||
inline uint64 MakeDmaElement( void * pData, uint nSize )
|
||||
{
|
||||
return ((uint32)pData) | (uint64(nSize)<<32);
|
||||
}
|
||||
|
||||
template <uint nSize>
|
||||
inline void V_memcpy16( void *pDest, const void * pSrc )
|
||||
{
|
||||
Assert( !( nSize & 0xF ) && !( uintp( pDest ) & 0xF ) && !( uintp( pSrc ) & 0xF ) );
|
||||
for( uint i = 0; i < nSize / 16; ++i )
|
||||
{
|
||||
( ( vector unsigned int * ) pDest )[i] = ( ( vector unsigned int * ) pSrc )[i];
|
||||
}
|
||||
}
|
||||
|
||||
class CDmaListConstructor
|
||||
{
|
||||
uint32 *m_pListBegin, *m_pList;
|
||||
uint m_sizeInOrInOut;
|
||||
uint m_sizeCacheDmaList;
|
||||
public:
|
||||
CDmaListConstructor( void * pList )
|
||||
{
|
||||
m_pList = m_pListBegin = ( uint32* )pList;
|
||||
m_sizeInOrInOut = m_sizeCacheDmaList = 0;
|
||||
}
|
||||
|
||||
void AddInputDma( uint nSize, const void *pEa )
|
||||
{
|
||||
Assert( !m_sizeCacheDmaList );
|
||||
Assert( !( nSize & 0xF ) && nSize <= 16 * 1024 && ( !nSize || pEa ) );
|
||||
Assert( !IsAddressInStack( pEa ) );
|
||||
m_pList[0] = nSize;
|
||||
m_pList[1] = ( uint32 )pEa;
|
||||
m_pList += 2;
|
||||
|
||||
m_sizeInOrInOut += nSize;
|
||||
}
|
||||
|
||||
void AddCacheDma( uint nSize, const void *pEa )
|
||||
{
|
||||
// WARNING : NEVER use size=0, as there's a bug in SPURS that can corrupt data if you do
|
||||
Assert( !IsAddressInStack( pEa ) && pEa && nSize > 0 );
|
||||
uint32 * pCache = AddBytes( m_pList, m_sizeCacheDmaList );
|
||||
pCache[0] = nSize;
|
||||
pCache[1] = ( uint32 )pEa;
|
||||
|
||||
m_sizeCacheDmaList += 8;
|
||||
Assert( m_sizeCacheDmaList <= 32 );
|
||||
}
|
||||
|
||||
void AddInputDmaLargeUnalignedRegion( void * pBegin, void * pEnd )
|
||||
{
|
||||
uint32 eaBeginAligned = uint32( pBegin ) & -16;
|
||||
uint32 eaEndAligned = AlignValue( uint32( pEnd ), 16 );
|
||||
AddInputDmaLarge( eaEndAligned - eaBeginAligned, ( void* )eaBeginAligned );
|
||||
}
|
||||
|
||||
void* AddInputDmaUnalignedRegion( void * pBegin, void * pEnd, int nAlignment = 16 )
|
||||
{
|
||||
uint32 eaBeginAligned = uint32( pBegin ) & -nAlignment;
|
||||
uint32 eaEndAligned = AlignValue( uint32( pEnd ), nAlignment );
|
||||
AddInputDma( eaEndAligned - eaBeginAligned, ( void* )eaBeginAligned );
|
||||
return ( void* )eaBeginAligned;
|
||||
}
|
||||
|
||||
void AddInputDmaLarge( uint nMinReserve, uint nSize, const void * pEa )
|
||||
{
|
||||
AddInputDmaLarge( nSize, pEa );
|
||||
Assert( !( nMinReserve & 15 ) );
|
||||
if( nMinReserve > nSize )
|
||||
{
|
||||
m_sizeInOrInOut += nMinReserve - nSize;
|
||||
}
|
||||
}
|
||||
|
||||
uint AddInputDmaLargeRegion( const void * pBegin, const void * pEnd )
|
||||
{
|
||||
uint nSize = uintp( pEnd ) - uintp( pBegin );
|
||||
AddInputDmaLarge( nSize, pBegin );
|
||||
return nSize;
|
||||
}
|
||||
|
||||
void AddInputDmaLarge( uint nSize, const void * pEa )
|
||||
{
|
||||
Assert( !( nSize & 0xF ) && nSize < 248 * 1024 );
|
||||
Assert( !IsAddressInStack( pEa ) );
|
||||
uint nSizeRemaining = nSize;
|
||||
uintp eaRemaining = ( uintp )pEa;
|
||||
const uint nMaxDmaElementSize = 16 * 1024;
|
||||
while( nSizeRemaining > nMaxDmaElementSize )
|
||||
{
|
||||
m_pList[0] = nMaxDmaElementSize;
|
||||
m_pList[1] = eaRemaining;
|
||||
m_pList += 2;
|
||||
nSizeRemaining -= nMaxDmaElementSize;
|
||||
eaRemaining += nMaxDmaElementSize;
|
||||
}
|
||||
m_pList[0] = nSizeRemaining;
|
||||
m_pList[1] = eaRemaining;
|
||||
m_pList += 2;
|
||||
|
||||
m_sizeInOrInOut += nSize;
|
||||
}
|
||||
|
||||
void AddSizeInOrInOut( uint nAddIoBufferSize )
|
||||
{
|
||||
Assert( !( nAddIoBufferSize & 0xF ) );
|
||||
m_sizeInOrInOut += nAddIoBufferSize;
|
||||
}
|
||||
|
||||
void EnsureCapacityInOrInOut( uint nCapacity )
|
||||
{
|
||||
Assert( !( nCapacity & 0xF ) );
|
||||
m_sizeInOrInOut = Max( m_sizeInOrInOut, nCapacity );
|
||||
}
|
||||
|
||||
void FinishIoBuffer( CellSpursJobHeader * pHeader )
|
||||
{
|
||||
FinishInOrIoBuffer( pHeader );
|
||||
Assert( pHeader->useInOutBuffer == 1 );
|
||||
}
|
||||
|
||||
void FinishInBuffer( CellSpursJobHeader * pHeader )
|
||||
{
|
||||
FinishInOrIoBuffer( pHeader );
|
||||
Assert( pHeader->useInOutBuffer == 0 );
|
||||
}
|
||||
|
||||
void FinishIoBuffer( CellSpursJobHeader * pHeader, void * pParams )
|
||||
{
|
||||
FinishIoBuffer( pHeader );
|
||||
// we only use up to 256 byte jobs, which have up to 26 DMA slots. Check that the params belongs to this job structure
|
||||
// and check that it doesn't overlap with IO DMA list or cache DMA list
|
||||
Assert( uintp( pParams ) <= uintp( m_pListBegin + 26 * 2 ) && uintp( pParams ) >= uintp( m_pList ) + m_sizeCacheDmaList );
|
||||
}
|
||||
|
||||
void FinishInBuffer( CellSpursJobHeader * pHeader, void * pParams )
|
||||
{
|
||||
FinishInBuffer( pHeader );
|
||||
// we only use up to 256 byte jobs, which have up to 26 DMA slots. Check that the params belongs to this job structure
|
||||
// and check that it doesn't overlap with IO DMA list or cache DMA list
|
||||
Assert( uintp( pParams ) <= uintp( m_pListBegin + 26 * 2 ) && uintp( pParams ) >= uintp( m_pList ) + m_sizeCacheDmaList );
|
||||
}
|
||||
|
||||
inline uint32 * operator [] ( int i )
|
||||
{
|
||||
uint32 * pResult = m_pListBegin + 2 * i;
|
||||
Assert( pResult >= m_pList ); // are we not overwriting the dma list tail that we wrote previously?
|
||||
return pResult;
|
||||
}
|
||||
|
||||
private:
|
||||
void FinishInOrIoBuffer( CellSpursJobHeader * pHeader )
|
||||
{
|
||||
pHeader->sizeDmaList = uintp( m_pList ) - uintp( m_pListBegin );
|
||||
pHeader->sizeInOrInOut = m_sizeInOrInOut;
|
||||
pHeader->sizeCacheDmaList = m_sizeCacheDmaList;
|
||||
}
|
||||
|
||||
// We can't DMA from / to the PPU stack, let's verify that
|
||||
bool IsAddressInStack( const void * pEa )
|
||||
{
|
||||
#if IsPlatformPS3_PPU()
|
||||
uint64 fp = __reg(1);
|
||||
void * minStack = ( void* )( ( uint32 ) fp - 16 * 1024 ); // The 16 * 1024 should is not really necessary (as it means somebody addresses some portion that could be erased by the stack.
|
||||
// Never the less, we want to be more conservative.
|
||||
void * maxStack = (void *)((uint32)fp + 64 * 1024); // Assume that the stack is 64 Kb deep, make sure there is no allocations around if the stack is smaller
|
||||
return ( ( pEa >= minStack ) && ( pEa <= maxStack ) );
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user