Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

515 lines
16 KiB

//================ Copyright (c) Valve Corporation. All Rights Reserved. ===========================
//
//
//
//==================================================================================================
#include "tier0/platform.h"
#include "tier0/dbg.h"
#include "tier1/strtools.h"
#include "tier1/utlbuffer.h"
#include "utlmap.h"
#include "ps3gcmmemory.h"
#include "gcmstate.h"
#include "bitmap/imageformat_declarations.h"
#include "gcmtexture.h"
#include "memdbgon.h"
#ifdef _CERT
#define Debugger() ((void)0)
#else
#define Debugger() DebuggerBreak()
#endif
//--------------------------------------------------------------------------------------------------
// Texture Layouts
//--------------------------------------------------------------------------------------------------
#ifdef _CERT
#define GLMTEX_FMT_DESC( x )
#else
#define GLMTEX_FMT_DESC( x ) x ,
#endif
#define CELL_GCM_REMAP_MODE_OIO(order, inputARGB, outputARGB) \
(((order)<<16)|((inputARGB))|((outputARGB)<<8))
#define REMAPO( x ) CELL_GCM_TEXTURE_REMAP_ORDER_X##x##XY
#define REMAP4(a,r,g,b) (((a)<<0)|((r)<<2)|((g)<<4)|((b)<<6))
#define REMAP_ARGB REMAP4( CELL_GCM_TEXTURE_REMAP_FROM_A, CELL_GCM_TEXTURE_REMAP_FROM_R, CELL_GCM_TEXTURE_REMAP_FROM_G, CELL_GCM_TEXTURE_REMAP_FROM_B )
#define REMAP_4 REMAP4( CELL_GCM_TEXTURE_REMAP_REMAP, CELL_GCM_TEXTURE_REMAP_REMAP, CELL_GCM_TEXTURE_REMAP_REMAP, CELL_GCM_TEXTURE_REMAP_REMAP )
#define REMAP_13 REMAP4( CELL_GCM_TEXTURE_REMAP_ONE, CELL_GCM_TEXTURE_REMAP_REMAP, CELL_GCM_TEXTURE_REMAP_REMAP, CELL_GCM_TEXTURE_REMAP_REMAP )
#define REMAP_4X(x) REMAP4( x, x, x, x )
#define REMAP_13X(y, x) REMAP4( y, x, x, x )
#define REMAP_ALL_DEFAULT CELL_GCM_REMAP_MODE_OIO( REMAPO(Y), REMAP_ARGB, REMAP_4 )
#define REMAP_ALL_DEFAULT_X CELL_GCM_REMAP_MODE_OIO( REMAPO(X), REMAP_ARGB, REMAP_4 )
#define CAP( x ) CPs3gcmTextureLayout::Format_t::kCap##x
CPs3gcmTextureLayout::Format_t g_ps3texFormats[PS3_TEX_MAX_FORMAT_COUNT] =
{
// summ-name d3d-format
// gcmRemap
// gcmFormat
// gcmPitchPer4X gcmFlags
{ GLMTEX_FMT_DESC("_D16") D3DFMT_D16,
REMAP_ALL_DEFAULT,
8,
CELL_GCM_TEXTURE_DEPTH16,
0 },
{ GLMTEX_FMT_DESC("_D24X8") D3DFMT_D24X8,
REMAP_ALL_DEFAULT,
16,
CELL_GCM_TEXTURE_DEPTH24_D8,
0 },
{ GLMTEX_FMT_DESC("_D24S8") D3DFMT_D24S8,
REMAP_ALL_DEFAULT,
16,
CELL_GCM_TEXTURE_DEPTH24_D8,
0 },
{ GLMTEX_FMT_DESC("_A8R8G8B8") D3DFMT_A8R8G8B8,
REMAP_ALL_DEFAULT,
16,
CELL_GCM_TEXTURE_A8R8G8B8,
CAP(SRGB) },
{ GLMTEX_FMT_DESC("_X8R8G8B8") D3DFMT_X8R8G8B8,
REMAP_ALL_DEFAULT,
16,
CELL_GCM_TEXTURE_A8R8G8B8,
CAP(SRGB) },
{ GLMTEX_FMT_DESC("_X1R5G5B5") D3DFMT_X1R5G5B5,
CELL_GCM_REMAP_MODE_OIO( REMAPO(X), REMAP_ARGB, REMAP_13 ),
8,
CELL_GCM_TEXTURE_R5G6B5,
0 },
{ GLMTEX_FMT_DESC("_A1R5G5B5") D3DFMT_A1R5G5B5,
REMAP_ALL_DEFAULT_X,
8,
CELL_GCM_TEXTURE_A1R5G5B5,
0 },
{ GLMTEX_FMT_DESC("_L8") D3DFMT_L8,
CELL_GCM_REMAP_MODE_OIO( REMAPO(Y), REMAP_4X(CELL_GCM_TEXTURE_REMAP_FROM_B), REMAP_13 ),
4,
CELL_GCM_TEXTURE_B8,
0 },
{ GLMTEX_FMT_DESC("_A8L8") D3DFMT_A8L8,
CELL_GCM_REMAP_MODE_OIO( REMAPO(Y), REMAP_13X( CELL_GCM_TEXTURE_REMAP_FROM_G, CELL_GCM_TEXTURE_REMAP_FROM_B), REMAP_4 ),
8,
CELL_GCM_TEXTURE_G8B8,
0 },
{ GLMTEX_FMT_DESC("_DXT1") D3DFMT_DXT1,
CELL_GCM_REMAP_MODE_OIO( REMAPO(Y), REMAP_ARGB, REMAP_13 ),
8,
CELL_GCM_TEXTURE_COMPRESSED_DXT1,
CAP(SRGB) | CAP(4xBlocks) },
{ GLMTEX_FMT_DESC("_DXT3") D3DFMT_DXT3,
REMAP_ALL_DEFAULT,
16,
CELL_GCM_TEXTURE_COMPRESSED_DXT23,
CAP(SRGB) | CAP(4xBlocks) },
{ GLMTEX_FMT_DESC("_DXT5") D3DFMT_DXT5,
REMAP_ALL_DEFAULT,
16,
CELL_GCM_TEXTURE_COMPRESSED_DXT45,
CAP(SRGB) | CAP(4xBlocks) },
{ GLMTEX_FMT_DESC("_A16B16G16R16F") D3DFMT_A16B16G16R16F,
REMAP_ALL_DEFAULT_X,
32,
CELL_GCM_TEXTURE_W16_Z16_Y16_X16_FLOAT,
0 },
{ GLMTEX_FMT_DESC("_A16B16G16R16") D3DFMT_A16B16G16R16,
REMAP_ALL_DEFAULT_X,
64,
CELL_GCM_TEXTURE_W32_Z32_Y32_X32_FLOAT,
0 },
{ GLMTEX_FMT_DESC("_A32B32G32R32F") D3DFMT_A32B32G32R32F,
REMAP_ALL_DEFAULT_X,
64,
CELL_GCM_TEXTURE_W32_Z32_Y32_X32_FLOAT,
0 },
{ GLMTEX_FMT_DESC("_R8G8B8") D3DFMT_R8G8B8,
CELL_GCM_REMAP_MODE_OIO( REMAPO(Y),
REMAP4( CELL_GCM_TEXTURE_REMAP_FROM_B, CELL_GCM_TEXTURE_REMAP_FROM_A, CELL_GCM_TEXTURE_REMAP_FROM_R, CELL_GCM_TEXTURE_REMAP_FROM_G ),
REMAP_13 ),
16,
CELL_GCM_TEXTURE_A8R8G8B8,
CAP(SRGB) },
{ GLMTEX_FMT_DESC("_A8") D3DFMT_A8,
CELL_GCM_REMAP_MODE_OIO( REMAPO(Y),
REMAP4( CELL_GCM_TEXTURE_REMAP_FROM_B, CELL_GCM_TEXTURE_REMAP_FROM_R, CELL_GCM_TEXTURE_REMAP_FROM_B, CELL_GCM_TEXTURE_REMAP_FROM_B ),
REMAP_13X( CELL_GCM_TEXTURE_REMAP_REMAP, CELL_GCM_TEXTURE_REMAP_ZERO ) ),
4,
CELL_GCM_TEXTURE_B8,
0 },
{ GLMTEX_FMT_DESC("_R5G6B5") D3DFMT_R5G6B5,
CELL_GCM_REMAP_MODE_OIO( REMAPO(Y),
REMAP4( CELL_GCM_TEXTURE_REMAP_FROM_B, CELL_GCM_TEXTURE_REMAP_FROM_A, CELL_GCM_TEXTURE_REMAP_FROM_R, CELL_GCM_TEXTURE_REMAP_FROM_G ),
REMAP_13 ),
16,
CELL_GCM_TEXTURE_A8R8G8B8,
CAP(SRGB) },
{ GLMTEX_FMT_DESC("_Q8W8V8U8") D3DFMT_Q8W8V8U8,
REMAP_ALL_DEFAULT,
16,
CELL_GCM_TEXTURE_A8R8G8B8,
CAP(SRGB) },
};
uint g_nPs3texFormatCount = PS3_TEX_CANONICAL_FORMAT_COUNT;
#undef CAP
#undef GLMTEX_FMT_DESC
static bool Ps3texLayoutLessFunc( CPs3gcmTextureLayout::Key_t const &a, CPs3gcmTextureLayout::Key_t const &b )
{
return ( memcmp( &a, &b, sizeof( CPs3gcmTextureLayout::Key_t ) ) < 0 );
}
static CUtlMap< CPs3gcmTextureLayout::Key_t, CPs3gcmTextureLayout const * > s_ps3texLayouts( Ps3texLayoutLessFunc );
CPs3gcmTextureLayout const * CPs3gcmTextureLayout::New( Key_t const &k )
{
// look up 'key' in the map and see if it's a hit, if so, bump the refcount and return
// if not, generate a completed layout based on the key, add to map, set refcount to 1, return that
unsigned short index = s_ps3texLayouts.Find( k );
if ( index != s_ps3texLayouts.InvalidIndex() )
{
CPs3gcmTextureLayout const *layout = s_ps3texLayouts[ index ];
++ layout->m_refCount;
return layout;
}
// Need to generate complete information about the texture layout
uint8 nMips = ( k.m_texFlags & kfMip ) ? k.m_nActualMipCount : 1;
uint8 nFaces = ( k.m_texFlags & kfTypeCubeMap ) ? 6 : 1;
uint32 nSlices = nMips * nFaces;
// Allocate layout memory
size_t numLayoutBytes = sizeof( CPs3gcmTextureLayout ) + nSlices * sizeof( Slice_t );
CPs3gcmTextureLayout *layout = ( CPs3gcmTextureLayout * ) MemAlloc_AllocAligned( numLayoutBytes, 16 );
memset( layout, 0, numLayoutBytes );
memcpy( &layout->m_key, &k, sizeof( Key_t ) );
layout->m_refCount = 1;
// Find the format descriptor
for ( int j = 0; j < PS3_TEX_CANONICAL_FORMAT_COUNT; ++ j )
{
if ( g_ps3texFormats[j].m_d3dFormat == k.m_texFormat )
{
layout->m_nFormat = j;
break;
}
Assert( j != PS3_TEX_CANONICAL_FORMAT_COUNT - 1 );
}
layout->m_mipCount = nMips;
//
// Slices
//
bool bSwizzled = layout->IsSwizzled();
size_t fmtPitch = layout->GetFormatPtr()->m_gcmPitchPer4X;
size_t fmtPitchBlock = ( layout->GetFormatPtr()->m_gcmCaps & CPs3gcmTextureLayout::Format_t::kCap4xBlocks ) ? 16 : 4;
size_t numDataBytes = 0;
Slice_t *pSlice = &layout->m_slices[0];
for ( int face = 0; face < nFaces; ++ face )
{
// For cubemaps every next face in swizzled addressing
// must be aligned on 128-byte boundary
if ( bSwizzled )
{
numDataBytes = ( numDataBytes + 127 ) & ~127;
}
for ( int mip = 0; mip < nMips; ++ mip, ++ pSlice )
{
for ( int j = 0; j < ARRAYSIZE( k.m_size ); ++ j )
{
pSlice->m_size[j] = k.m_size[j] >> mip;
pSlice->m_size[j] = MAX( pSlice->m_size[j], 1 );
}
pSlice->m_storageOffset = numDataBytes;
size_t numTexels;
// For linear layout textures every mip row must be padded to the
// width of the original highest level mip so that the pitch was
// the same for every mip
if ( bSwizzled )
numTexels = ( pSlice->m_size[0] * pSlice->m_size[1] * pSlice->m_size[2] );
else
numTexels = ( k.m_size[0] * pSlice->m_size[1] * pSlice->m_size[2] );
size_t numBytes = ( numTexels * fmtPitch ) / fmtPitchBlock;
if ( layout->GetFormatPtr()->m_gcmCaps & CPs3gcmTextureLayout::Format_t::kCap4xBlocks )
{
// Ensure the size of the smallest mipmap levels of DXT1/3/5 textures (the 1x1 and 2x2 mips) is accurately computed.
numBytes = MAX( numBytes, fmtPitch );
}
pSlice->m_storageSize = MAX( numBytes, 1 );
numDataBytes += pSlice->m_storageSize;
}
}
// Make the total size 128-byte aligned
// Realistically it is required only for depth textures
numDataBytes = ( numDataBytes + 127 ) & ~127;
//
// Tiled and ZCull memory adjustments
//
layout->m_gcmAllocType = GCM_MAINPOOLSIZE ? kAllocPs3gcmTextureData0 : kAllocPs3gcmTextureData;
if ( layout->IsTiledMemory() )
{
if( g_nPs3texFormatCount >= PS3_TEX_MAX_FORMAT_COUNT )
{
Error("Modified ps3 format array overflow. Increase PS3_TEX_MAX_FORMAT_COUNT appropriately and recompile\n");
}
Format_t *pModifiedFormat = &g_ps3texFormats[g_nPs3texFormatCount];
V_memcpy( pModifiedFormat, layout->GetFormatPtr(), sizeof( Format_t ) );
layout->m_nFormat = g_nPs3texFormatCount;
g_nPs3texFormatCount ++;
if ( k.m_texFlags & kfTypeDepthStencil )
{
//
// Tiled Zcull Surface
//
uint32 zcullSize[2] = { AlignValue( k.m_size[0], 64 ), AlignValue( k.m_size[1], 64 ) };
uint32 nDepthPitch;
if ( k.m_texFormat == D3DFMT_D16 )
nDepthPitch = cellGcmGetTiledPitchSize( zcullSize[0] * 2 );
else
nDepthPitch = cellGcmGetTiledPitchSize( zcullSize[0] * 4 );
pModifiedFormat->m_gcmPitchPer4X = nDepthPitch;
uint32 uDepthBufferSize32bpp = nDepthPitch * zcullSize[1];
uDepthBufferSize32bpp = AlignValue( uDepthBufferSize32bpp, PS3GCMALLOCATIONALIGN( kAllocPs3gcmDepthBuffer ) );
Assert( uDepthBufferSize32bpp >= numDataBytes );
numDataBytes = uDepthBufferSize32bpp;
layout->m_gcmAllocType = kAllocPs3gcmDepthBuffer;
}
else
{
//
// Tiled Color Surface
//
uint32 nTiledPitch = cellGcmGetTiledPitchSize( k.m_size[0] * layout->GetFormatPtr()->m_gcmPitchPer4X / 4 );
pModifiedFormat->m_gcmPitchPer4X = nTiledPitch;
// We Don't allocate any 512x512 RTs (they are used only when in PAL576i which can use the FB mem pool)
/*if ( k.m_size[0] == 512 && k.m_size[1] == 512 && k.m_size[2] == 1 )
layout->m_gcmAllocType = kAllocPs3gcmColorBuffer512;
else*/
if ( k.m_size[0] == g_ps3gcmGlobalState.m_nRenderSize[0] && k.m_size[1] == g_ps3gcmGlobalState.m_nRenderSize[1] && k.m_size[2] == 1 )
layout->m_gcmAllocType = kAllocPs3gcmColorBufferFB;
else if ( k.m_size[0] == g_ps3gcmGlobalState.m_nRenderSize[0]/4 && k.m_size[1] == g_ps3gcmGlobalState.m_nRenderSize[1]/4 && k.m_size[2] == 1 )
layout->m_gcmAllocType = kAllocPs3gcmColorBufferFBQ;
else
layout->m_gcmAllocType = kAllocPs3gcmColorBufferMisc;
uint32 uRenderSize = nTiledPitch * AlignValue( k.m_size[1], 32 ); // 32-line vertical alignment required in local memory
if ( layout->m_gcmAllocType == kAllocPs3gcmColorBufferMisc )
uRenderSize = AlignValue( uRenderSize, PS3GCMALLOCATIONALIGN( kAllocPs3gcmColorBufferMisc ) );
Assert( uRenderSize >= numDataBytes );
numDataBytes = uRenderSize;
}
}
layout->m_storageTotalSize = numDataBytes;
//
// Finished creating the layout information
//
#ifndef _CERT
// generate summary
// "target, format, +/- mips, base size"
char scratch[1024];
char *targetname = targetname = "2D ";
if ( layout->IsVolumeTex() )
targetname = "3D ";
if ( layout->IsCubeMap() )
targetname = "CUBE";
sprintf( scratch, "[%s %s %dx%dx%d mips=%d slices=%d flags=%02X%s]",
targetname,
layout->GetFormatPtr()->m_formatSummary,
layout->m_key.m_size[0], layout->m_key.m_size[1], layout->m_key.m_size[2],
nMips,
nSlices,
layout->m_key.m_texFlags,
(layout->m_key.m_texFlags & kfSrgbEnabled) ? " SRGB" : ""
);
layout->m_layoutSummary = strdup( scratch );
#endif
// then insert into map. disregard returned index.
s_ps3texLayouts.Insert( k, layout );
return layout;
}
void CPs3gcmTextureLayout::Release() const
{
-- m_refCount;
// keep the layout in the map for easy access
Assert( m_refCount >= 0 );
}
//////////////////////////////////////////////////////////////////////////
//
// Texture management
//
CPs3gcmTexture * CPs3gcmTexture::New( CPs3gcmTextureLayout::Key_t const &key )
{
//
// Allocate a new layout for the texture
//
CPs3gcmTextureLayout const *pLayout = CPs3gcmTextureLayout::New( key );
if ( !pLayout )
{
Debugger();
return NULL;
}
CPs3gcmTexture *tex = (CPs3gcmTexture *)MemAlloc_AllocAligned( sizeof( CPs3gcmTexture ), 16 );
memset( tex, 0, sizeof( CPs3gcmTexture ) ); // NOTE: This clears the CPs3gcmLocalMemoryBlock
tex->m_layout = pLayout;
CPs3gcmAllocationType_t uAllocationType = pLayout->m_gcmAllocType;
if ( key.m_texFlags & CPs3gcmTextureLayout::kfNoD3DMemory )
{
if ( ( uAllocationType == kAllocPs3gcmDepthBuffer ) || ( uAllocationType == kAllocPs3gcmColorBufferMisc ) )
{
Assert( 0 );
Warning( "ERROR: (CPs3gcmTexture::New) depth/colour buffers should not be marked with kfNoD3DMemory!\n" );
}
else
{
// Early-out, storage will be allocated later (via IDirect3DDevice9::AllocateTextureStorage)
return tex;
}
}
tex->Allocate();
return tex;
}
void CPs3gcmTexture::Release()
{
// Wait for RSX to finish using the texture memory
// and free it later
if ( m_lmBlock.Size() )
{
m_lmBlock.Free();
}
m_layout->Release();
MemAlloc_FreeAligned( this );
}
bool CPs3gcmTexture::Allocate()
{
if ( m_lmBlock.Size() )
{
// Already allocated!
Assert( 0 );
Warning( "ERROR: CPs3gcmTexture::Allocate called twice!\n" );
return true;
}
CPs3gcmAllocationType_t uAllocationType = m_layout->m_gcmAllocType;
const CPs3gcmTextureLayout::Key_t & key = m_layout->m_key;
// if kAllocPs3gcmTextureData0 (main memory) fails try kAllocPs3gcmTextureData
if (!m_lmBlock.Alloc( uAllocationType, m_layout->m_storageTotalSize ) )
{
if (m_layout->m_gcmAllocType == kAllocPs3gcmTextureData0)
{
m_layout->m_gcmAllocType = kAllocPs3gcmTextureData;
CPs3gcmAllocationType_t uAllocationType = m_layout->m_gcmAllocType;
m_lmBlock.Alloc( uAllocationType, m_layout->m_storageTotalSize );
}
}
if ( m_layout->IsTiledMemory() )
{
if ( uAllocationType == kAllocPs3gcmDepthBuffer )
{
bool bIs16BitDepth = ( m_layout->GetFormatPtr()->m_gcmFormat == CELL_GCM_TEXTURE_DEPTH16 ) || ( m_layout->m_nFormat == CELL_GCM_TEXTURE_DEPTH16_FLOAT );
uint32 zcullSize[2] = { AlignValue( key.m_size[0], 64 ), AlignValue( key.m_size[1], 64 ) };
uint32 uiZcullIndex = m_lmBlock.ZcullMemoryIndex();
cellGcmBindZcull( uiZcullIndex,
m_lmBlock.Offset(),
zcullSize[0], zcullSize[1],
m_lmBlock.ZcullMemoryStart(),
bIs16BitDepth ? CELL_GCM_ZCULL_Z16 : CELL_GCM_ZCULL_Z24S8,
CELL_GCM_SURFACE_CENTER_1,
CELL_GCM_ZCULL_LESS,
CELL_GCM_ZCULL_LONES,
CELL_GCM_SCULL_SFUNC_ALWAYS,
0, 0 // sRef, sMask
);
uint32 uiTileIndex = m_lmBlock.TiledMemoryIndex();
cellGcmSetTileInfo( uiTileIndex, CELL_GCM_LOCATION_LOCAL, m_lmBlock.Offset(),
m_layout->m_storageTotalSize, m_layout->DefaultPitch(), bIs16BitDepth ? CELL_GCM_COMPMODE_DISABLED : CELL_GCM_COMPMODE_Z32_SEPSTENCIL_REGULAR,
m_lmBlock.TiledMemoryTagAreaBase(), // The area base + size/0x10000 will be allocated as the tag area.
1 ); // Misc depth buffers on bank 1
cellGcmBindTile( uiTileIndex );
}
else if ( uAllocationType == kAllocPs3gcmColorBufferMisc )
{
uint32 uiTileIndex = m_lmBlock.TiledMemoryIndex();
cellGcmSetTileInfo( uiTileIndex, CELL_GCM_LOCATION_LOCAL, m_lmBlock.Offset(),
m_layout->m_storageTotalSize, m_layout->DefaultPitch(), CELL_GCM_COMPMODE_DISABLED,
m_lmBlock.TiledMemoryTagAreaBase(), // The area base + size/0x10000 will be allocated as the tag area.
1 ); // Tile misc color buffers on bank 1
cellGcmBindTile( uiTileIndex );
}
}
#ifdef _DEBUG
memset( Data(), 0, m_layout->m_storageTotalSize ); // initialize texture data to BLACK in DEBUG
#endif
return true;
}