You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
132 lines
4.5 KiB
132 lines
4.5 KiB
//========== Copyright © Valve Corporation, All rights reserved. ========
|
|
//
|
|
// This is PPU->SPU fifo queue to feed draw jobs
|
|
//
|
|
|
|
#ifndef SPUDRAWQUEUE_HDR
|
|
#define SPUDRAWQUEUE_HDR
|
|
|
|
#include "tier0/dbg.h"
|
|
#include "tier1/strtools.h"
|
|
#include "vjobs/pcring.h"
|
|
#include "ps3/vjobutils_shared.h"
|
|
#include "vjobs/spudrawqueue_shared.h"
|
|
|
|
extern void StallAndWarning( const char * pWarning );
|
|
|
|
class SpuDrawQueue
|
|
{
|
|
public:
|
|
typedef void ( *FnFlushCallback_t)( SpuDrawQueue * );
|
|
typedef void ( *FnStallCallback_t)( SpuDrawQueue *, uint32 * pGet, uint nWords );
|
|
|
|
void Init( uint nBufferSize, uint32 * pSignal, FnFlushCallback_t fnFlushCallback, FnStallCallback_t fnStallCallback );
|
|
void Shutdown();
|
|
|
|
void PushFlushCallback( FnFlushCallback_t fnFlushCallback );
|
|
void PopFlushCallback();
|
|
|
|
uint32 *AllocWords( uint nWords /*, uint nAlignMask = 0, uint nAlignValue = 0*/ );
|
|
void UnallocToAlign();
|
|
|
|
template<typename T>
|
|
T *AllocAligned( )
|
|
{
|
|
COMPILE_TIME_ASSERT( sizeof( T ) % 4 == 0 );
|
|
Align();
|
|
return ( T* )AllocWords( sizeof( T ) / 4 );
|
|
}
|
|
|
|
template <typename T>
|
|
T *AllocWithHeader( uint nHeader ) { uint32 * pHeader = AllocWords( 1 + sizeof( T ) / 4 ); *pHeader = nHeader; return ( T* )( pHeader + 1 ); }
|
|
|
|
uint Collect( uint32 * pStartBatch, uint32 * pEndBatch, CDmaListConstructor & dmac );
|
|
uint32 * GetCursor(){ return m_pPut; }
|
|
uint32 * GetFlushWatermark() {return m_pFlushWatermark;}
|
|
void Align();
|
|
|
|
void Push4( uint32 a, uint32 b, uint32 c, uint32 d ){ uint32 * p = AllocWords( 4 ); p[0] = a; p[1] = b; p[2] = c; p[3] = d; }
|
|
void Push3( uint32 a, uint32 b, uint32 c ){ uint32 * p = AllocWords( 3 ); p[0] = a; p[1] = b; p[2] = c; }
|
|
void Push2( uint32 a, uint32 b ){ uint32 * p = AllocWords( 2 ); p[0] = a; p[1] = b; }
|
|
void Push1( uint32 a ){ uint32 * p = AllocWords( 1 ); p[0] = a; }
|
|
|
|
enum ConstEnum_t {DMA_ALIGNMENT = 16 };
|
|
|
|
void SetFlushWatermarkFrom( uint32 *pPut );
|
|
|
|
uint32 GetSignal()const{ return ( uint32 )m_pPut; }
|
|
uint32 * GetBuffer()const{ return m_pBuffer; }
|
|
uint32 * GetBufferEnd()const { return m_pBufferEnd; }
|
|
uint32 GetBufferWords()const { return m_pBufferEnd - m_pBuffer; }
|
|
bool IsValidCursor( uint32 * p )const { return m_pBuffer <= p && p <= m_pBufferEnd && 0 == ( uintp( p ) & 3 ); }
|
|
uint32 * NormalizeCursor( uint32 * p ) { Assert( IsValidCursor( p ) ); return ( p >= m_pBufferEnd ? m_pBuffer : p ); }
|
|
uint Length( uint32 * pBegin, uint32 * pEnd )const;
|
|
protected:
|
|
void SetSignal( uint32 nSignal );
|
|
public:
|
|
uint64 m_nAllocWords;
|
|
#ifdef _DEBUG
|
|
uint64 m_nAllocCount, m_nCollectCount;
|
|
uint64 m_nAllocBreak, m_nCollectBreak;
|
|
uint32 * m_nAllocBreakAddress;
|
|
#endif
|
|
protected:
|
|
// the begin and end of the whole buffer
|
|
// it must be 16-byte aligned
|
|
uint32 *m_pBuffer, *m_pBufferEnd;
|
|
|
|
// up to this point, we may write stuff. Starting at this point, SPU is reading data
|
|
// m_pPut==m_pGet means "buffer empty"
|
|
// m_pPut > m_pGet means we can write to the end of the buffer and then start at the start
|
|
// m_pPut < m_pGet means we can write from put to get, exclusively
|
|
uint32 *m_pGet;
|
|
|
|
// this is the point where we can write stuff, up to m_pGet
|
|
uint32 *m_pPut;
|
|
|
|
// external signal in the structure where SPU writes
|
|
volatile uint32 * m_pSignal;
|
|
|
|
uint32 *m_pFlushWatermark;
|
|
|
|
// FlushCallback member is implemented elsewhere. DrawQueue calls this callback
|
|
// as an advice to flush the queue. The callback doesn't have to flush the queue
|
|
// if the current transaction is deemed atomic. Also, even if the queue is flushed,
|
|
// this object does not get immediate feedback until it reads the signal that SPU sets
|
|
// much later, asynchronously. This callback is important to slice the long transactions
|
|
// into smaller chunks that fit into LS
|
|
FnFlushCallback_t m_fnFlushCallback;
|
|
FnStallCallback_t m_fnStallCallback;
|
|
|
|
//enum EnumConst_t{STACK_SIZE = 1 };
|
|
FnFlushCallback_t m_fnFlushCallbackStack;
|
|
};
|
|
|
|
|
|
inline void SpuDrawQueue::SetSignal( uint32 nSignal )
|
|
{
|
|
uint32 *pNewGet = (uint32*)nSignal;
|
|
|
|
// the new get must be between old get and put
|
|
|
|
Assert( pNewGet == m_pGet ||
|
|
( pNewGet > m_pGet ? m_pPut < m_pGet || pNewGet <= m_pPut // the new get doesn't wrap around the buffer,
|
|
: m_pPut < m_pGet && pNewGet <= m_pPut // the new get wraps around the buffer, so the put must wrap around, too
|
|
)
|
|
);
|
|
|
|
m_pGet = pNewGet;
|
|
}
|
|
|
|
|
|
|
|
inline void SpuDrawQueue::Align()
|
|
{
|
|
while( uintp( m_pPut ) & 0xF )
|
|
{
|
|
Push1( 0 );
|
|
}
|
|
}
|
|
|
|
|
|
#endif
|