//================ Copyright (c) Valve Corporation. All Rights Reserved. =========================== // // Texture Layout, CPs3gcmTexture, and CPs3gcmTextureData_t // //================================================================================================== #ifndef INCLUDED_GCMTEXTURE_H #define INCLUDED_GCMTEXTURE_H #include "ps3/ps3_platform.h" #include "ps3gcmmemory.h" #include "gcmstate.h" //-------------------------------------------------------------------------------------------------- // Literals //-------------------------------------------------------------------------------------------------- #define PS3_TEX_MAX_FORMAT_COUNT 48 #define PS3_TEX_CANONICAL_FORMAT_COUNT 19 //-------------------------------------------------------------------------------------------------- // Texture layout, texture etc.. //-------------------------------------------------------------------------------------------------- struct ALIGN16 CPs3gcmTextureLayout { #ifndef _CERT char *m_layoutSummary; // for debug visibility #endif // format mapping description struct ALIGN16 Format_t { #ifndef _CERT char *m_formatSummary; // for debug visibility #endif enum GcmCaps_t { kCapSRGB = (1<<0), // GCM can sample it as SRGB kCap4xBlocks = (1<<1), // Pitch is referring to 4 texel blocks and not single texel blocks (DXT) }; D3DFORMAT m_d3dFormat; // what D3D knows it as; see public/bitmap/imageformat.h uint32 m_gcmRemap; // GCM remap mask uint16 m_gcmPitchPer4X; // GCM pitch multiplier per every 4 pixels of width uint8 m_gcmFormat; // GCM format uint8 m_gcmCaps; // GCM caps of this texture } ALIGN16_POST; // const inputs used for hashing struct Key_t { D3DFORMAT m_texFormat; // D3D texel format uint16 m_size[3]; // dimensions of the base mip uint8 m_texFlags; // mipped, autogen mips, render target, ... ? uint8 m_nActualMipCount; // Actual number of mips; on console builds, we typically drop the smallest (highest index) // mips to save space (they waste a lot of space for page-alignment reasons) // high-bit 0x80 indicates cubemap }; // layout flags enum Flags_t { kfDynamicNoSwizzle = (1<<0), // Indicates whether this texture needs to keep a backing store for incremental updates. // (On PS3 this will prevent texture from being swizzled to allow CPU writes at subrect offsets) kfMip = (1<<1), kfMipAuto = (1<<2), kfTypeRenderable = (1<<3), kfTypeDepthStencil = (1<<4), kfTypeCubeMap = (1<<5), kfSrgbEnabled = (1<<6), kfNoD3DMemory = (1<<7), // Allocation of storage for the bits has been deferred (call IDirect3DDevice9::AllocateTextureStorage to do the allocation) // -!!--!!- DO NOT ADD MORE FLAGS -!!--!!- (m_texFlags is only 8 bits) }; // slice information struct Slice_t { uint32 m_storageOffset; //where in the storage slab does this slice live uint32 m_storageSize; //how much storage does this slice occupy uint16 m_size[3]; //texel dimensions of this slice }; // // Structure definition // Key_t m_key; // key of the layout int32 mutable m_refCount; // refcount uint32 m_storageTotalSize; // size of storage slab required uint16 m_nFormat; // format specific info; index in g_ps3texFormats table uint8 m_mipCount; // derived by starting at base size and working down towards 1x1 CPs3gcmAllocationType_t mutable m_gcmAllocType; // type of GCM allocation to determine pool/alignment/etc. #ifndef SPU // slice array Slice_t m_slices[0]; // dynamically allocated 2-d array [faces][mips] public: inline int SlicePitch( int iSlice ) const; inline int DefaultPitch() const; inline const Format_t * GetFormatPtr()const; #endif public: inline bool IsSwizzled() const { return !( m_key.m_texFlags & ( kfDynamicNoSwizzle | kfTypeRenderable ) ) && IsPowerOfTwo( m_key.m_size[0] ) && IsPowerOfTwo( m_key.m_size[1] ) && IsPowerOfTwo( m_key.m_size[2] ); } inline bool IsCubeMap() const { return !!(m_key.m_texFlags & kfTypeCubeMap); } inline bool IsVolumeTex() const { return !!(m_key.m_size[2] > 1); } inline bool IsTiledMemory() const { return (m_key.m_texFlags & ( kfTypeRenderable | kfDynamicNoSwizzle )) == kfTypeRenderable; } inline int FaceCount() const { return ( !IsCubeMap() ) ? 1 : 6; } inline int MipCount() const { return ( m_key.m_texFlags & kfMip ) ? m_key.m_nActualMipCount : 1; } inline int SlicePitch2( int iSlice, const Slice_t* pSlices, const Format_t *pTexFormats ) const{ return !IsTiledMemory() ? ( ( IsSwizzled() ? pSlices[iSlice].m_size[0] : m_key.m_size[0] ) * pTexFormats[m_nFormat].m_gcmPitchPer4X / 4 ) : pTexFormats[m_nFormat].m_gcmPitchPer4X; } inline int DefaultPitch2( const Format_t *pTexFormats ) const { return !IsTiledMemory() ? m_key.m_size[0] * pTexFormats[m_nFormat].m_gcmPitchPer4X / 4 : pTexFormats[m_nFormat].m_gcmPitchPer4X; } inline int SliceIndex( int face, int mip ) const { return mip + ( face * MipCount() ); } public: #ifndef SPU static CPs3gcmTextureLayout const * New( Key_t const &k ); void Release() const; #endif } ALIGN16_POST; extern CPs3gcmTextureLayout::Format_t g_ps3texFormats[PS3_TEX_MAX_FORMAT_COUNT]; extern uint g_nPs3texFormatCount; #ifndef SPU // convenience functions on PPU that use implicit tables always accessible on PPU inline int CPs3gcmTextureLayout::SlicePitch( int iSlice ) const { return SlicePitch2( iSlice, &m_slices[0], g_ps3texFormats ); } inline int CPs3gcmTextureLayout::DefaultPitch() const { return DefaultPitch2( g_ps3texFormats ); } inline const CPs3gcmTextureLayout::Format_t * CPs3gcmTextureLayout::GetFormatPtr()const { return &g_ps3texFormats[ m_nFormat ]; } #endif struct ALIGN16 CPs3gcmTexture { CPs3gcmTextureLayout const *m_layout; // this structure persists. see CPs3gcmTextureLayout::Release( it asserts if refcount goes down to zero ) ALIGN16 CPs3gcmLocalMemoryBlock m_lmBlock ALIGN16_POST; // this structure has the Offset, and the texture bits at that offset persist until all Draw calls are made that use it inline uint32 Offset()const { Assert( m_lmBlock.Size() ); return m_lmBlock.Offset(); } #ifndef SPU inline char * Data() { Assert( m_lmBlock.Size() ); return m_lmBlock.DataInAnyMemory(); } #endif public: #ifndef SPU static CPs3gcmTexture * New( CPs3gcmTextureLayout::Key_t const &key ); void Release(); bool Allocate(); #endif } ALIGN16_POST; struct CPs3gcmTextureData_t { // CPs3gcmTextureLayout const *m_eaLayout uint32 m_eaLayout; // this structure persists. see CPs3gcmTextureLayout::Release( it asserts if refcount goes down to zero ) uint32 m_nLocalOffset; // the offset of the texture bits void Assign( const CPs3gcmTexture * pThat ) { if( pThat ) { m_eaLayout = ( uint32 )pThat->m_layout; m_nLocalOffset = pThat->Offset(); Assert( m_eaLayout ? !( 15 & ( uintp( m_eaLayout ) | m_nLocalOffset ) ) && m_nLocalOffset : !m_nLocalOffset ); } else { Reset(); } } inline uint32 Offset()const { return m_nLocalOffset; } void Reset() { m_eaLayout = 0; m_nLocalOffset = 0; } bool IsNull()const { return !NotNull(); } bool NotNull()const { // either both are null, or none is null Assert( ( m_eaLayout == 0 ) == ( m_nLocalOffset == 0 ) ); return m_eaLayout != 0; } operator bool() const { return NotNull(); } }; // // CPs3BindTexture_t : Everything we need to bind a texture // // This is what the SPU needs to bind the texture struct CPs3BindTexture_t { uint8 m_sampler; uint8 m_nBindFlags; uint8 m_UWrap; uint8 m_VWrap; uint8 m_WWrap; uint8 m_minFilter; uint8 m_magFilter; uint8 m_mipFilter; uint32 m_nLayout; CPs3gcmLocalMemoryBlock *m_pLmBlock; int m_boundStd; int m_hTexture; }; // This is what we store when asked to bind a texture // When the cmd buffer is executed, at this time we lookup // the remaining fields and pack some CPs3BindTexture_t to actually use on the SPU struct CPs3BindParams_t { uint16 m_nBindTexIndex; uint8 m_sampler; uint8 m_nBindFlags; int m_boundStd; int m_hTexture; }; #endif // INCLUDED_GCMTEXTURE_H