mirror of
https://github.com/libretro/RetroArch
synced 2025-03-29 22:20:21 +00:00
5169 lines
183 KiB
C++
5169 lines
183 KiB
C++
#include "rgl_cg.h"
|
|
|
|
static CGbool rglpSupportsVertexProgram( CGprofile p )
|
|
{
|
|
if ( p == CG_PROFILE_SCE_VP_RSX )
|
|
return CG_TRUE;
|
|
return CG_FALSE;
|
|
}
|
|
|
|
static CGbool rglpSupportsFragmentProgram( CGprofile p )
|
|
{
|
|
if ( CG_PROFILE_SCE_FP_RSX == p )
|
|
return CG_TRUE;
|
|
return CG_FALSE;
|
|
}
|
|
|
|
static CGprofile rglpGetLatestProfile( CGGLenum profile_type )
|
|
{
|
|
switch ( profile_type )
|
|
{
|
|
case CG_GL_VERTEX:
|
|
return CG_PROFILE_SCE_VP_RSX;
|
|
case CG_GL_FRAGMENT:
|
|
return CG_PROFILE_SCE_FP_RSX;
|
|
default:
|
|
break;
|
|
}
|
|
return CG_PROFILE_UNKNOWN;
|
|
}
|
|
|
|
static int rglGcmGenerateProgram (void *data, int profileIndex, const CgProgramHeader *programHeader, const void *ucode, const CgParameterTableHeader *parameterHeader,
|
|
const CgParameterEntry *parameterEntries, const char *stringTable, const float *defaultValues )
|
|
{
|
|
_CGprogram *program = (_CGprogram*)data;
|
|
CGprofile profile = ( CGprofile )programHeader->profile;
|
|
CellGcmContextData *thisContext = (CellGcmContextData*)gCellGcmCurrentContext;
|
|
|
|
int need_swapping = 0;
|
|
|
|
// if can't match a known profile, the data may be in wrong endianness
|
|
if ((( profile != CG_PROFILE_SCE_FP_RSX ) && ( profile != CG_PROFILE_SCE_VP_RSX ) ))
|
|
need_swapping = 1;
|
|
|
|
// check that this program block is of the right revision
|
|
// i.e. that the cgBinary.h header hasn't changed since it was
|
|
// compiled.
|
|
|
|
// validate the profile
|
|
int invalidProfile = 0;
|
|
|
|
switch ( ENDIAN_32( profile, need_swapping ) )
|
|
{
|
|
case CG_PROFILE_SCE_VP_RSX:
|
|
if ( profileIndex != VERTEX_PROFILE_INDEX )
|
|
invalidProfile = 1;
|
|
break;
|
|
case CG_PROFILE_SCE_FP_RSX:
|
|
if ( profileIndex != FRAGMENT_PROFILE_INDEX )
|
|
invalidProfile = 1;
|
|
break;
|
|
default:
|
|
invalidProfile = 1;
|
|
break;
|
|
}
|
|
|
|
if ( invalidProfile )
|
|
{
|
|
rglCgRaiseError( CG_UNKNOWN_PROFILE_ERROR );
|
|
return 0;
|
|
}
|
|
|
|
memcpy( &program->header, programHeader, sizeof( program->header ) );
|
|
|
|
program->ucode = ucode;
|
|
program->loadProgramId = GMM_ERROR;
|
|
program->loadProgramOffset = 0;
|
|
program->inLocalMemory = true;
|
|
|
|
|
|
size_t parameterSize = parameterHeader->entryCount * sizeof( CgRuntimeParameter );
|
|
void *memoryBlock;
|
|
if ( parameterSize )
|
|
memoryBlock = memalign( 16, parameterSize );
|
|
else
|
|
memoryBlock = NULL;
|
|
|
|
program->rtParametersCount = parameterHeader->entryCount;
|
|
program->runtimeParameters = ( CgRuntimeParameter* )memoryBlock;
|
|
|
|
if (!parameterEntries) // the param entry can be supplied if not right after parameterHeader in memory, it happens when there's a program copy
|
|
parameterEntries = ( CgParameterEntry* )( parameterHeader + 1 );
|
|
|
|
program->parametersEntries = parameterEntries;
|
|
program->parameterResources = ( char* )( program->parametersEntries + program->rtParametersCount );
|
|
program->resources = ( unsigned short* )(( char* )program->parametersEntries + ( parameterHeader->resourceTableOffset - sizeof( CgParameterTableHeader ) ) );
|
|
program->defaultValuesIndexCount = parameterHeader->defaultValueIndexCount;
|
|
program->defaultValuesIndices = ( CgParameterDefaultValue* )(( char* )program->parametersEntries + ( parameterHeader->defaultValueIndexTableOffset - sizeof( CgParameterTableHeader ) ) );
|
|
program->semanticCount = parameterHeader->semanticIndexCount;
|
|
program->semanticIndices = ( CgParameterSemantic* )( program->defaultValuesIndices + program->defaultValuesIndexCount );
|
|
|
|
program->defaultValues = NULL;
|
|
|
|
memset( program->runtimeParameters, 0, parameterHeader->entryCount*sizeof( CgRuntimeParameter ) );
|
|
|
|
//string table
|
|
program->stringTable = stringTable;
|
|
//default values
|
|
program->defaultValues = defaultValues;
|
|
|
|
rglCreatePushBuffer( program );
|
|
int count = program->defaultValuesIndexCount;
|
|
|
|
if ( profileIndex != FRAGMENT_PROFILE_INDEX )
|
|
{
|
|
/* modifies the push buffer */
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
int index = ( int )program->defaultValuesIndices[i].entryIndex;
|
|
CgRuntimeParameter *rtParameter = program->runtimeParameters + index;
|
|
|
|
int arrayCount = 1;
|
|
const CgParameterEntry *parameterEntry = rtParameter->parameterEntry;
|
|
bool isArray = false;
|
|
if ( parameterEntry->flags & CGP_ARRAY )
|
|
{
|
|
isArray = true;
|
|
const CgParameterArray *parameterArray = rglGetParameterArray( program, parameterEntry );
|
|
arrayCount = rglGetSizeofSubArray( parameterArray->dimensions, parameterArray->dimensionCount );
|
|
parameterEntry++;
|
|
rtParameter++;
|
|
}
|
|
|
|
if ( rtParameter->pushBufferPointer ) //unreferenced might have default values
|
|
{
|
|
const CgParameterResource *parameterResource = rglGetParameterResource( program, parameterEntry );
|
|
const float *itemDefaultValues = program->defaultValues + program->defaultValuesIndices[i].defaultValueIndex;
|
|
int registerStride = isMatrix(( CGtype )parameterResource->type ) ? rglGetTypeRowCount(( CGtype )parameterResource->type ) : 1;
|
|
if ( parameterEntry->flags & CGP_CONTIGUOUS )
|
|
memcpy( rtParameter->pushBufferPointer, itemDefaultValues, arrayCount * registerStride *4*sizeof( float ) );
|
|
else
|
|
{
|
|
unsigned int *pushBufferPointer = (( unsigned int * )rtParameter->pushBufferPointer );
|
|
for ( int j = 0;j < arrayCount;j++ )
|
|
{
|
|
unsigned int *pushBufferAddress = isArray ? ( *( unsigned int** )pushBufferPointer ) : pushBufferPointer;
|
|
memcpy( pushBufferAddress, itemDefaultValues, registerStride*4*sizeof( float ) );
|
|
pushBufferPointer += isArray ? 1 : 3 + registerStride * 4;
|
|
itemDefaultValues += 4 * registerStride;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// not loaded yet
|
|
program->loadProgramId = GMM_ERROR;
|
|
program->loadProgramOffset = 0;
|
|
|
|
if ( profileIndex == FRAGMENT_PROFILE_INDEX )
|
|
{
|
|
// always load fragment shaders.
|
|
// uploads the given fp shader to gpu memory. Allocates if needed.
|
|
// This also builds the shared constants push buffer if needed, since it depends on the load address
|
|
unsigned int ucodeSize = program->header.instructionCount * 16;
|
|
|
|
if ( program->loadProgramId == GMM_ERROR )
|
|
{
|
|
program->loadProgramId = gmmAlloc(ucodeSize);
|
|
program->loadProgramOffset = 0;
|
|
}
|
|
|
|
rglGcmSend(thisContext, program->loadProgramId, program->loadProgramOffset, 0, ( char* )program->ucode, ucodeSize );
|
|
}
|
|
|
|
program->programGroup = NULL;
|
|
program->programIndexInGroup = -1;
|
|
|
|
return 1;
|
|
}
|
|
|
|
CGprogram rglpCgUpdateProgramAtIndex( CGprogramGroup group, int index, int refcount )
|
|
{
|
|
if (index < ( int )group->programCount)
|
|
{
|
|
//index can be < 0 , in that case refcount update on the group only, used when destroying a copied program
|
|
if (index >= 0)
|
|
{
|
|
//if it has already been referenced duplicate instead of returning the same index, until the API offer a native support for
|
|
//group of programs ( //fixed bug 13007 )
|
|
if (refcount == 1 && group->programs[index].refCount == 1)
|
|
{
|
|
//it will handle the refcounting
|
|
CGprogram res = cgCopyProgram( group->programs[index].program );
|
|
return res;
|
|
}
|
|
group->programs[index].refCount += refcount;
|
|
}
|
|
|
|
group->refCount += refcount;
|
|
if (refcount < 0)
|
|
{
|
|
if (group->refCount == 0 && !group->userCreated)
|
|
rglCgDestroyProgramGroup( group );
|
|
return NULL;
|
|
}
|
|
else
|
|
return group->programs[index].program;
|
|
}
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
static CGprogramGroup rglCgCreateProgramGroupFromFile( CGcontext ctx, const char *group_file )
|
|
{
|
|
// check that file exists
|
|
FILE* fp = fopen( group_file, "rb" );
|
|
|
|
if (!fp)
|
|
return ( CGprogramGroup )NULL;
|
|
|
|
// find the file length
|
|
size_t file_size = 0;
|
|
fseek( fp, 0, SEEK_END );
|
|
file_size = ftell( fp );
|
|
rewind( fp );
|
|
|
|
// alloc memory for new binary program and read the data
|
|
char* ptr = ( char* )malloc( file_size + 1 );
|
|
if ( NULL == ptr )
|
|
{
|
|
rglCgRaiseError( CG_MEMORY_ALLOC_ERROR );
|
|
fclose(fp);
|
|
return ( CGprogramGroup )NULL;
|
|
}
|
|
|
|
// read the entire file into memory then close the file
|
|
// TODO ********* just loading the file is a bit lame really. We can do better.
|
|
fread( ptr, file_size, 1, fp );
|
|
fclose( fp );
|
|
|
|
CGprogramGroup group = rglCgCreateProgramGroup( ctx, group_file, ptr, file_size );
|
|
if ( !group )
|
|
free( ptr );
|
|
|
|
return group;
|
|
}
|
|
|
|
CGprogramGroup rglCgCreateProgramGroup( CGcontext ctx, const char *name, void *ptr, int size )
|
|
{
|
|
_CGprogramGroup *group = NULL;
|
|
CGELFBinary elfBinary;
|
|
elfBinary.elfFile = NULL;
|
|
|
|
while ( 1 )
|
|
{
|
|
bool res = cgOpenElf( ptr, size, &elfBinary );
|
|
if ( !res )
|
|
break;
|
|
|
|
size_t elfConstTableSize = ( size_t )elfBinary.consttabSize;
|
|
size_t elfStringTableSize = ( size_t )elfBinary.strtabSize;
|
|
|
|
//first pass to get the size of each item ( could be faster if the embedded constants index table size was in the header
|
|
int programCount = elfBinary.shadertabSize / sizeof( CgProgramHeader );
|
|
int i;
|
|
|
|
//structure of the memory buffer storing the group
|
|
size_t nvProgramNamesOffset = rglPad( sizeof( _CGprogramGroup ), sizeof( _CGnamedProgram ) ); //program name offset
|
|
size_t nvDefaultValuesTableOffset = rglPad( nvProgramNamesOffset + programCount * sizeof( _CGnamedProgram ), 16 );//shared default value table
|
|
|
|
size_t nvStringTableOffset = nvDefaultValuesTableOffset + elfConstTableSize; //shared string table
|
|
size_t structureSize = nvStringTableOffset + elfStringTableSize;//total structure size
|
|
|
|
//create the program group
|
|
group = ( CGprogramGroup )malloc( structureSize );
|
|
if ( !group ) //out of memory
|
|
break;
|
|
|
|
//fill the group structure
|
|
group->ctx = ctx;
|
|
group->next = NULL;
|
|
group->programCount = ( unsigned int )programCount;
|
|
group->constantTable = ( unsigned int * )(( char* )group + nvDefaultValuesTableOffset );
|
|
group->stringTable = ( unsigned int * )(( char* )group + nvStringTableOffset );
|
|
group->programs = ( _CGnamedProgram * )(( char* )group + nvProgramNamesOffset );
|
|
group->userCreated = true;
|
|
group->refCount = 0;
|
|
group->filedata = ( char* )ptr;
|
|
if ( name )
|
|
{
|
|
int len = strlen( name );
|
|
group->name = ( char* )malloc( len + 1 );
|
|
if ( !group->name )//out of memory
|
|
break;
|
|
strcpy( group->name, name );
|
|
}
|
|
else
|
|
group->name = NULL;
|
|
|
|
//copy the default values
|
|
if ( elfConstTableSize )
|
|
memcpy(( char* )group + nvDefaultValuesTableOffset, elfBinary.consttab, elfConstTableSize );
|
|
//copy the string table
|
|
if ( elfStringTableSize )
|
|
memcpy(( char* )group + nvStringTableOffset, elfBinary.strtab, elfStringTableSize );
|
|
|
|
//add the group to the context:
|
|
_CGcontext *context = _cgGetContextPtr(ctx);
|
|
if ( !context->groupList )
|
|
context->groupList = group;
|
|
else
|
|
{
|
|
_CGprogramGroup *current = context->groupList;
|
|
while ( current->next )
|
|
current = current->next;
|
|
current->next = group;
|
|
}
|
|
|
|
//create all the shaders contained in the package and add them to the group
|
|
for ( i = 0;i < ( int )group->programCount;i++ )
|
|
{
|
|
CgProgramHeader *cgShader = ( CgProgramHeader* )elfBinary.shadertab + i;
|
|
|
|
//hack to counter removal of TypeC during beta
|
|
if ( cgShader->profile == ( CGprofile )7005 )
|
|
cgShader->profile = CG_PROFILE_SCE_VP_RSX;
|
|
if ( cgShader->profile == ( CGprofile )7006 )
|
|
cgShader->profile = CG_PROFILE_SCE_FP_RSX;
|
|
|
|
CGELFProgram elfProgram;
|
|
bool res = cgGetElfProgramByIndex( &elfBinary, i, &elfProgram );
|
|
if ( !res )
|
|
return false;
|
|
|
|
//I reference the buffer passed as parameter here, so it will have to stay around
|
|
CgProgramHeader *programHeader = cgShader;
|
|
char *ucode = ( char * )elfProgram.texttab;
|
|
CgParameterTableHeader *parameterHeader = ( CgParameterTableHeader * )elfProgram.paramtab;
|
|
|
|
const char *programName = getSymbolByIndexInPlace( elfBinary.symtab, elfBinary.symbolSize, elfBinary.symbolCount, elfBinary.symbolstrtab, i + 1 );
|
|
group->programs[i].name = programName;
|
|
group->programs[i].program = rglCgCreateProgram( ctx, ( CGprofile )cgShader->profile, programHeader, ucode, parameterHeader, ( const char* )group->stringTable, ( const float* )group->constantTable );
|
|
_CGprogram *cgProgram = _cgGetProgPtr( group->programs[i].program );
|
|
cgProgram->programGroup = group;
|
|
cgProgram->programIndexInGroup = i;
|
|
group->programs[i].refCount = 0;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return group;
|
|
}
|
|
|
|
void rglCgDestroyProgramGroup( CGprogramGroup group )
|
|
{
|
|
_CGprogramGroup *_group = ( _CGprogramGroup * )group;
|
|
for ( int i = 0;i < ( int )_group->programCount;i++ )
|
|
{
|
|
//unlink the program
|
|
_CGprogram *cgProgram = _cgGetProgPtr( group->programs[i].program );
|
|
cgProgram->programGroup = NULL;
|
|
cgDestroyProgram( _group->programs[i].program );
|
|
}
|
|
free( _group->filedata );
|
|
if ( _group->name )
|
|
free( _group->name );
|
|
|
|
//remove the group from the group list
|
|
_CGcontext *context = _cgGetContextPtr( group->ctx );
|
|
_CGprogramGroup *current = context->groupList;
|
|
_CGprogramGroup *previous = NULL;
|
|
while ( current && current != group )
|
|
{
|
|
previous = current;
|
|
current = current->next;
|
|
}
|
|
if ( current )
|
|
{
|
|
if ( !previous )
|
|
context->groupList = current->next;
|
|
else
|
|
previous->next = current->next;
|
|
}
|
|
free( _group );
|
|
}
|
|
|
|
const char *rglCgGetProgramGroupName (CGprogramGroup group)
|
|
{
|
|
_CGprogramGroup *_group = ( _CGprogramGroup * )group;
|
|
return _group->name;
|
|
}
|
|
|
|
int rglCgGetProgramIndex (CGprogramGroup group, const char *name)
|
|
{
|
|
int i;
|
|
for ( i = 0;i < ( int )group->programCount;i++ )
|
|
if ( !strcmp( name, group->programs[i].name ) )
|
|
return i;
|
|
|
|
return -1;
|
|
}
|
|
|
|
void rglpProgramErase (void *data)
|
|
{
|
|
_CGprogram* platformProgram = (_CGprogram*)data;
|
|
_CGprogram* program = (_CGprogram*)platformProgram;
|
|
|
|
if ( program->loadProgramId != GMM_ERROR )
|
|
{
|
|
gmmFree( program->loadProgramId );
|
|
program->loadProgramId = GMM_ERROR;
|
|
program->loadProgramOffset = 0;
|
|
}
|
|
|
|
//free the runtime parameters
|
|
if ( program->runtimeParameters )
|
|
{
|
|
//need to erase all the program parameter "names"
|
|
int i;
|
|
int count = ( int )program->rtParametersCount;
|
|
|
|
for ( i = 0; i < count;i++ )
|
|
rglEraseName( &_CurrentContext->cgParameterNameSpace, (unsigned int)program->runtimeParameters[i].id );
|
|
|
|
free( program->runtimeParameters );
|
|
}
|
|
|
|
//free the push buffer block
|
|
if ( program->memoryBlock )
|
|
free( program->memoryBlock );
|
|
|
|
//free the samplers lookup tables
|
|
if ( program->samplerIndices )
|
|
{
|
|
free( program->samplerValuesLocation );
|
|
free( program->samplerIndices );
|
|
free( program->samplerUnits );
|
|
}
|
|
|
|
//free the "pointers" on the push buffer used for fast access
|
|
if ( program->constantPushBufferPointers )
|
|
free( program->constantPushBufferPointers );
|
|
}
|
|
|
|
//TODO: use a ref mechanism for the string table or duplicate it !
|
|
int rglpCopyProgram (void *src_data, void *dst_data)
|
|
{
|
|
_CGprogram *source = (_CGprogram*)src_data;
|
|
_CGprogram *destination = (_CGprogram*)dst_data;
|
|
//extract the layout of the parameter buffers from the source
|
|
CgParameterTableHeader parameterHeader;
|
|
parameterHeader.entryCount = source->rtParametersCount;
|
|
parameterHeader.resourceTableOffset = ( uintptr_t )(( char* )source->resources - ( char* )source->parametersEntries + sizeof( CgParameterTableHeader ) );
|
|
parameterHeader.defaultValueIndexCount = source->defaultValuesIndexCount;
|
|
parameterHeader.defaultValueIndexTableOffset = ( uintptr_t )(( char* )source->defaultValuesIndices - ( char* )source->parametersEntries + sizeof( CgParameterTableHeader ) );
|
|
parameterHeader.semanticIndexCount = source->semanticCount;
|
|
parameterHeader.semanticIndexTableOffset = ( uintptr_t )(( char* )source->defaultValuesIndices - ( char* )source->parametersEntries + sizeof( CgParameterTableHeader ) );
|
|
|
|
int profileIndex;
|
|
|
|
//allocate the copy of the program
|
|
switch ( source->header.profile )
|
|
{
|
|
case CG_PROFILE_SCE_VP_RSX:
|
|
profileIndex = VERTEX_PROFILE_INDEX;
|
|
break;
|
|
case CG_PROFILE_SCE_FP_RSX:
|
|
profileIndex = FRAGMENT_PROFILE_INDEX;
|
|
break;
|
|
default:
|
|
return 0;
|
|
}
|
|
return rglGcmGenerateProgram( destination, profileIndex, &source->header, source->ucode, ¶meterHeader, source->parametersEntries, source->stringTable, source->defaultValues );
|
|
}
|
|
|
|
int rglpGenerateVertexProgram (void *data, const CgProgramHeader *programHeader,
|
|
const void *ucode, const CgParameterTableHeader *parameterHeader, const char *stringTable,
|
|
const float *defaultValues )
|
|
{
|
|
return rglGcmGenerateProgram( (_CGprogram*)data, VERTEX_PROFILE_INDEX, programHeader,
|
|
ucode, parameterHeader, NULL, stringTable, defaultValues );
|
|
|
|
}
|
|
|
|
int rglpGenerateFragmentProgram (void *data, const CgProgramHeader *programHeader, const void *ucode,
|
|
const CgParameterTableHeader *parameterHeader, const char *stringTable, const float *defaultValues )
|
|
{
|
|
return rglGcmGenerateProgram( (_CGprogram*)data, FRAGMENT_PROFILE_INDEX, programHeader, ucode, parameterHeader, NULL, stringTable, defaultValues );
|
|
|
|
}
|
|
|
|
/*============================================================
|
|
RTC CGC
|
|
============================================================ */
|
|
|
|
void cgRTCgcInit( void )
|
|
{
|
|
_cgRTCgcCompileProgramHook = &compile_program_from_string;
|
|
_cgRTCgcFreeCompiledProgramHook = &free_compiled_program;
|
|
}
|
|
|
|
void cgRTCgcFree( void )
|
|
{
|
|
_cgRTCgcCompileProgramHook = 0;
|
|
_cgRTCgcFreeCompiledProgramHook = 0;
|
|
}
|
|
|
|
/*============================================================
|
|
CG COMMON
|
|
============================================================ */
|
|
|
|
void rglCgRaiseError( CGerror error )
|
|
{
|
|
_CurrentContext->RGLcgLastError = error;
|
|
|
|
//_RGL_REPORT_EXTRA( RGL_REPORT_CG_ERROR, "Cg error:%s", cgGetErrorString( error ) );
|
|
|
|
if ( _CurrentContext->RGLcgErrorCallbackFunction )
|
|
_CurrentContext->RGLcgErrorCallbackFunction();
|
|
}
|
|
|
|
unsigned int rglCountFloatsInCgType( CGtype type )
|
|
{
|
|
int size = 0;
|
|
switch ( type )
|
|
{
|
|
case CG_FLOAT:
|
|
case CG_FLOAT1:
|
|
case CG_FLOAT1x1:
|
|
case CG_INT:
|
|
case CG_INT1:
|
|
case CG_INT1x1:
|
|
case CG_SAMPLER1D:
|
|
case CG_SAMPLER2D:
|
|
case CG_SAMPLER3D:
|
|
case CG_SAMPLERRECT:
|
|
case CG_SAMPLERCUBE:
|
|
case CG_BOOL:
|
|
case CG_HALF:
|
|
case CG_HALF1:
|
|
case CG_HALF1x1:
|
|
case CG_FIXED:
|
|
case CG_FIXED1:
|
|
case CG_FIXED1x1:
|
|
case CG_BOOL1:
|
|
case CG_BOOL1x1:
|
|
size = 1;
|
|
break;
|
|
case CG_FLOAT2:
|
|
case CG_FLOAT2x1:
|
|
case CG_FLOAT1x2:
|
|
case CG_HALF2:
|
|
case CG_HALF2x1:
|
|
case CG_HALF1x2:
|
|
case CG_INT2:
|
|
case CG_INT2x1:
|
|
case CG_INT1x2:
|
|
case CG_BOOL2:
|
|
case CG_BOOL2x1:
|
|
case CG_BOOL1x2:
|
|
case CG_FIXED2:
|
|
case CG_FIXED2x1:
|
|
case CG_FIXED1x2:
|
|
size = 2;
|
|
break;
|
|
case CG_FLOAT3:
|
|
case CG_FLOAT3x1:
|
|
case CG_FLOAT1x3:
|
|
case CG_HALF3:
|
|
case CG_HALF3x1:
|
|
case CG_HALF1x3:
|
|
case CG_INT3:
|
|
case CG_INT3x1:
|
|
case CG_INT1x3:
|
|
case CG_BOOL3:
|
|
case CG_BOOL3x1:
|
|
case CG_BOOL1x3:
|
|
case CG_FIXED3:
|
|
case CG_FIXED3x1:
|
|
case CG_FIXED1x3:
|
|
size = 3;
|
|
break;
|
|
case CG_FLOAT4:
|
|
case CG_FLOAT4x1:
|
|
case CG_FLOAT1x4:
|
|
case CG_FLOAT2x2:
|
|
case CG_HALF4:
|
|
case CG_HALF4x1:
|
|
case CG_HALF1x4:
|
|
case CG_HALF2x2:
|
|
case CG_INT4:
|
|
case CG_INT4x1:
|
|
case CG_INT1x4:
|
|
case CG_INT2x2:
|
|
case CG_BOOL4:
|
|
case CG_BOOL4x1:
|
|
case CG_BOOL1x4:
|
|
case CG_BOOL2x2:
|
|
case CG_FIXED4:
|
|
case CG_FIXED4x1:
|
|
case CG_FIXED1x4:
|
|
case CG_FIXED2x2:
|
|
size = 4;
|
|
break;
|
|
case CG_FLOAT2x3:
|
|
case CG_FLOAT3x2:
|
|
case CG_HALF2x3:
|
|
case CG_HALF3x2:
|
|
case CG_INT2x3:
|
|
case CG_INT3x2:
|
|
case CG_BOOL2x3:
|
|
case CG_BOOL3x2:
|
|
case CG_FIXED2x3:
|
|
case CG_FIXED3x2:
|
|
size = 6;
|
|
break;
|
|
case CG_FLOAT2x4:
|
|
case CG_FLOAT4x2:
|
|
case CG_HALF2x4:
|
|
case CG_HALF4x2:
|
|
case CG_INT2x4:
|
|
case CG_INT4x2:
|
|
case CG_BOOL2x4:
|
|
case CG_BOOL4x2:
|
|
case CG_FIXED2x4:
|
|
case CG_FIXED4x2:
|
|
size = 8;
|
|
break;
|
|
case CG_FLOAT3x3:
|
|
case CG_HALF3x3:
|
|
case CG_INT3x3:
|
|
case CG_BOOL3x3:
|
|
case CG_FIXED3x3:
|
|
size = 9;
|
|
break;
|
|
case CG_FLOAT3x4:
|
|
case CG_FLOAT4x3:
|
|
case CG_HALF3x4:
|
|
case CG_HALF4x3:
|
|
case CG_INT3x4:
|
|
case CG_INT4x3:
|
|
case CG_BOOL3x4:
|
|
case CG_BOOL4x3:
|
|
case CG_FIXED3x4:
|
|
case CG_FIXED4x3:
|
|
size = 12;
|
|
break;
|
|
case CG_FLOAT4x4:
|
|
case CG_HALF4x4:
|
|
case CG_INT4x4:
|
|
case CG_BOOL4x4:
|
|
case CG_FIXED4x4:
|
|
size = 16;
|
|
break;
|
|
default:
|
|
size = 0;
|
|
break;
|
|
}
|
|
return size;
|
|
}
|
|
|
|
void _cgRaiseInvalidParam (void *data, const void*v )
|
|
{
|
|
(void)data;
|
|
}
|
|
|
|
void _cgRaiseNotMatrixParam (void *data, const void*v )
|
|
{
|
|
(void)data;
|
|
}
|
|
|
|
void _cgIgnoreParamIndex (void *data, const void*v, const int index )
|
|
{
|
|
(void)data;
|
|
// nothing
|
|
}
|
|
|
|
CgRuntimeParameter* _cgGLTestTextureParameter( CGparameter param )
|
|
{
|
|
CgRuntimeParameter* ptr = rglCgGLTestParameter( param );
|
|
return ptr;
|
|
}
|
|
|
|
|
|
#define CG_DATATYPE_MACRO(name, compiler_name, enum_name, base_enum, nrows, ncols,classname) \
|
|
nrows ,
|
|
static int _typesRowCount[] =
|
|
{
|
|
#include "Cg/cg_datatypes.h"
|
|
};
|
|
|
|
#define CG_DATATYPE_MACRO(name, compiler_name, enum_name, base_enum, nrows, ncols,classname) \
|
|
ncols ,
|
|
static int _typesColCount[] =
|
|
{
|
|
#include "Cg/cg_datatypes.h"
|
|
};
|
|
|
|
unsigned int rglGetTypeRowCount( CGtype parameterType )
|
|
{
|
|
int typeIndex = parameterType - 1 - CG_TYPE_START_ENUM;
|
|
return _typesRowCount[typeIndex];
|
|
}
|
|
|
|
unsigned int rglGetTypeColCount( CGtype parameterType )
|
|
{
|
|
int typeIndex = parameterType - 1 - CG_TYPE_START_ENUM;
|
|
return _typesColCount[typeIndex];
|
|
}
|
|
|
|
/*============================================================
|
|
CG PARAMETER
|
|
============================================================ */
|
|
|
|
static const CGenum var_table[] = {CG_VARYING, CG_UNIFORM, CG_CONSTANT, CG_MIXED};
|
|
static const CGenum dir_table[] = {CG_IN, CG_OUT, CG_INOUT, CG_ERROR};
|
|
|
|
RGL_EXPORT CgparameterHookFunction _cgParameterCreateHook = NULL;
|
|
RGL_EXPORT CgparameterHookFunction _cgParameterDestroyHook = NULL;
|
|
|
|
static CGparameter rglAdvanceParameter( CGparameter param, int distance )
|
|
{
|
|
CgRuntimeParameter *rtParameter = ( CgRuntimeParameter* )rglCgGLTestParameter( param );
|
|
if ( !rtParameter )
|
|
return NULL;
|
|
|
|
if ( distance == 0 )
|
|
return param;
|
|
|
|
if ( rtParameter > rtParameter->program->runtimeParameters )
|
|
{
|
|
CgRuntimeParameter *previousParameter = rtParameter - 1;
|
|
if (( previousParameter->parameterEntry->flags & CGP_ARRAY ) &&
|
|
!( previousParameter->parameterEntry->flags & CGP_UNROLLED ) )
|
|
{
|
|
int arrayIndex = CG_GETINDEX( param );
|
|
arrayIndex += distance;
|
|
const CgParameterArray *parameterArray = rglGetParameterArray( previousParameter->program, previousParameter->parameterEntry );
|
|
int arraySize = rglGetSizeofSubArray( parameterArray->dimensions, parameterArray->dimensionCount );
|
|
if ( arrayIndex < arraySize )
|
|
{
|
|
int ret = ( int )rtParameter->id;
|
|
ret |= ( arrayIndex << CG_PARAMETERSIZE );
|
|
return ( CGparameter )ret;
|
|
}
|
|
else
|
|
{
|
|
return ( CGparameter )NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
//stop when the distance is 0
|
|
const CgParameterEntry *endEntry = rtParameter->program->parametersEntries + rtParameter->program->rtParametersCount;
|
|
const CgParameterEntry *paramEntry = rtParameter->parameterEntry;
|
|
|
|
while ( distance && paramEntry < endEntry )
|
|
{
|
|
switch ( paramEntry->flags & CGP_TYPE_MASK )
|
|
{
|
|
case CGP_ARRAY:
|
|
{
|
|
if ( paramEntry->flags & CGP_UNROLLED )
|
|
{
|
|
const CgParameterArray *parameterArray = rglGetParameterArray( rtParameter->program, paramEntry );
|
|
int arraySize = ( int )rglGetSizeofSubArray( parameterArray->dimensions, parameterArray->dimensionCount );
|
|
|
|
paramEntry++;
|
|
distance--;
|
|
|
|
paramEntry++;
|
|
distance += arraySize;
|
|
}
|
|
else
|
|
{
|
|
paramEntry++;
|
|
distance--;
|
|
paramEntry++;
|
|
}
|
|
break;
|
|
}
|
|
case CGP_STRUCTURE:
|
|
{
|
|
const CgParameterStructure *parameterStructure = rglGetParameterStructure( rtParameter->program, paramEntry );
|
|
paramEntry++;
|
|
distance--;
|
|
distance += parameterStructure->memberCount;
|
|
break;
|
|
}
|
|
case CGP_INTRINSIC:
|
|
paramEntry++;
|
|
distance--;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( paramEntry < endEntry )
|
|
{
|
|
size_t offset = ( paramEntry - rtParameter->parameterEntry );
|
|
CgRuntimeParameter *nextParameter = rtParameter + offset;
|
|
return nextParameter->id;
|
|
}
|
|
else
|
|
return ( CGparameter )NULL;
|
|
}
|
|
|
|
void rglCgDestroyContextParam( CgRuntimeParameter* ptr )
|
|
{
|
|
if (_cgParameterDestroyHook)
|
|
_cgParameterDestroyHook( ptr );
|
|
|
|
rglEraseName( &_CurrentContext->cgParameterNameSpace, (unsigned int)( ptr->id ) );
|
|
|
|
free( ptr );
|
|
}
|
|
|
|
static int rglGetSizeofSubArray( const short *dimensions, int count )
|
|
{
|
|
int res = 1;
|
|
for ( int i = 0;i < count;i++ )
|
|
res *= ( int )( *( dimensions++ ) );
|
|
return res;
|
|
}
|
|
|
|
|
|
static _CGparameter *_cgGetNamedParameter( _CGprogram* progPtr, const char* name, CGenum name_space, int *arrayIndex, const CgParameterEntry *_startEntry = NULL, int _entryCount = -1 )
|
|
{
|
|
if (!name)
|
|
return NULL;
|
|
|
|
*arrayIndex = -1;
|
|
int done = 0;
|
|
const char *structureEnd;
|
|
const char *structureStart = name;
|
|
int itemIndex = -1;
|
|
_CGprogram *program = progPtr;
|
|
|
|
const CgParameterEntry *currentEntry;
|
|
const CgParameterEntry *lastEntry;
|
|
|
|
int containerCount = -2;
|
|
if ( _startEntry && _entryCount != -1 )
|
|
{
|
|
currentEntry = _startEntry;
|
|
containerCount = _entryCount;
|
|
}
|
|
else
|
|
currentEntry = program->parametersEntries;
|
|
|
|
lastEntry = program->parametersEntries + program->rtParametersCount;
|
|
|
|
int isInArray = 0;
|
|
bool bWasUnrolled = false;
|
|
const char *prevStructureStart = structureStart; //for unrolled
|
|
|
|
while (( !done ) && ( *structureStart ) && ( containerCount != -1 ) )
|
|
{
|
|
structureEnd = strpbrk( structureStart, ".[" );
|
|
if (!structureEnd)
|
|
{
|
|
structureEnd = structureStart + strlen( structureStart );
|
|
done = 1;
|
|
}
|
|
|
|
if ( bWasUnrolled )
|
|
{
|
|
bWasUnrolled = false;
|
|
structureStart = prevStructureStart;
|
|
}
|
|
char structName[256];
|
|
int length = ( int )( structureEnd - structureStart );
|
|
strncpy( structName, structureStart, length );
|
|
structName[length] = '\0';
|
|
prevStructureStart = structureStart; //for unrolled
|
|
structureStart = structureEnd + 1;
|
|
|
|
bool found = false;
|
|
while ( !found && currentEntry < lastEntry && ( containerCount == -2 || containerCount > 0 ) )
|
|
{
|
|
if ( !strncmp( structName, program->stringTable + currentEntry->nameOffset, length )
|
|
&& ( name_space == 0 || ( name_space == CG_GLOBAL && ( currentEntry->flags & CGPF_GLOBAL ) )
|
|
|| ( name_space == CG_PROGRAM && !( currentEntry->flags & CGPF_GLOBAL ) ) ) )
|
|
{
|
|
if (( int )strlen( program->stringTable + currentEntry->nameOffset ) != length )
|
|
{
|
|
if ( !strcmp( name, program->stringTable + currentEntry->nameOffset ) )
|
|
{
|
|
found = true;
|
|
done = 1;
|
|
}
|
|
|
|
if ( !strncmp( name, program->stringTable + currentEntry->nameOffset, length ) &&
|
|
!strcmp( "[0]", program->stringTable + currentEntry->nameOffset + length ) )
|
|
{
|
|
found = true;
|
|
done = 1;
|
|
}
|
|
}
|
|
else
|
|
found = true;
|
|
}
|
|
|
|
if ( !found )
|
|
{
|
|
//we are skipping entries here, the search stays at the same level
|
|
int skipCount = 1;
|
|
while ( skipCount && currentEntry < lastEntry )
|
|
{
|
|
//skip as many entry as necessary
|
|
if ( currentEntry->flags & CGP_STRUCTURE )
|
|
{
|
|
const CgParameterStructure *parameterStructure = (const CgParameterStructure*)rglGetParameterStructure( program, currentEntry );
|
|
skipCount += parameterStructure->memberCount;
|
|
}
|
|
else if ( currentEntry->flags & CGP_ARRAY )
|
|
{
|
|
if ( currentEntry->flags & CGP_UNROLLED )
|
|
{
|
|
const CgParameterArray *parameterArray = (const CgParameterArray*)rglGetParameterArray( program, currentEntry );
|
|
skipCount += rglGetSizeofSubArray(( short* )parameterArray->dimensions, parameterArray->dimensionCount );
|
|
}
|
|
else
|
|
skipCount++; //the following item will be the type ( can't be a structure as they are always enrolled at the moment )
|
|
}
|
|
currentEntry++;
|
|
skipCount--;
|
|
}
|
|
}
|
|
if ( containerCount != -2 ) //denotes that we are in a structure or in an array and that we shouldn't look beyond
|
|
containerCount--;
|
|
}
|
|
//at that point we failed or we succeeded to find the entry at that level.
|
|
//if we have succeed we continue in the lower level if needed. if we have failed, we return not found.
|
|
|
|
if ( found )
|
|
{
|
|
switch ( currentEntry->flags & CGP_TYPE_MASK ) {
|
|
case 0:
|
|
itemIndex = ( int )( currentEntry - program->parametersEntries );
|
|
break;
|
|
case CGP_ARRAY:
|
|
{
|
|
|
|
const CgParameterEntry *arrayEntry = currentEntry;
|
|
const CgParameterArray *parameterArray = rglGetParameterArray( program, arrayEntry );
|
|
|
|
if ( *structureEnd == '\0' ) //if we are asked for the array parameter itself and not an array item:
|
|
{
|
|
itemIndex = ( int )( currentEntry - program->parametersEntries );
|
|
break;
|
|
}
|
|
|
|
//go inside:
|
|
currentEntry++;
|
|
if ( currentEntry->flags &CGP_STRUCTURE )
|
|
{
|
|
//continue to look into the list, but we should stop before the end of the array
|
|
bWasUnrolled = true;
|
|
containerCount = rglGetSizeofSubArray(( short* )parameterArray->dimensions, parameterArray->dimensionCount );
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
//the array contains base types
|
|
isInArray = 1;
|
|
const char *arrayStart = structureEnd;
|
|
const char *arrayEnd = structureEnd;
|
|
|
|
int dimensionCount = 0;
|
|
int arrayCellIndex = 0;
|
|
while ( *arrayStart == '[' && dimensionCount < parameterArray->dimensionCount )
|
|
{
|
|
arrayEnd = strchr( arrayStart + 1, ']' );
|
|
int length = ( int )( arrayEnd - arrayStart - 1 );
|
|
char indexString[16];
|
|
strncpy( indexString, arrayStart + 1, length );
|
|
indexString[length] = '\0';
|
|
int index = atoi( indexString );
|
|
int rowSize = parameterArray->dimensions[dimensionCount];
|
|
if ( index >= rowSize )
|
|
{
|
|
//index out of range: not found
|
|
return NULL;
|
|
}
|
|
arrayCellIndex += index * rglGetSizeofSubArray(( short* )parameterArray->dimensions + dimensionCount, parameterArray->dimensionCount - dimensionCount - 1 );
|
|
|
|
arrayStart = arrayEnd + 1;
|
|
dimensionCount++;
|
|
}
|
|
structureEnd = arrayStart;
|
|
if ( *structureEnd == '\0' )
|
|
done = 1;
|
|
|
|
if ( done )
|
|
{
|
|
//found the item in the array
|
|
( *arrayIndex ) = arrayCellIndex;
|
|
itemIndex = ( int )( currentEntry - program->parametersEntries );
|
|
}
|
|
//else... don't know what to do, it's a array of structure not unrolled
|
|
}
|
|
}
|
|
break;
|
|
case CGP_STRUCTURE:
|
|
if ( done )
|
|
{
|
|
//the user is getting back a strut... not sure that all the checks are in place for such a return value
|
|
itemIndex = ( int )( currentEntry - program->parametersEntries );
|
|
}
|
|
else
|
|
{
|
|
const CgParameterStructure *parameterStructure = rglGetParameterStructure( program, currentEntry );
|
|
containerCount = parameterStructure->memberCount;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
if ( found )
|
|
{
|
|
if ( !bWasUnrolled )
|
|
currentEntry++;
|
|
}
|
|
else
|
|
break;//not found
|
|
}
|
|
|
|
//have we found it ?
|
|
if ( itemIndex != -1 )
|
|
return ( _CGparameter* )( program->runtimeParameters + itemIndex );
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
// API functions ----------------------------------------
|
|
|
|
CG_API CGparameter cgGetNamedParameter( CGprogram prog, const char* name )
|
|
{
|
|
// check program handle
|
|
if ( !CG_IS_PROGRAM( prog ) )
|
|
{
|
|
rglCgRaiseError( CG_INVALID_PROGRAM_HANDLE_ERROR );
|
|
return ( CGparameter )NULL;
|
|
}
|
|
|
|
_CGprogram* progPtr = _cgGetProgPtr( prog );
|
|
// 0 means don't care
|
|
int arrayIndex = -1;
|
|
CgRuntimeParameter *param = ( CgRuntimeParameter * )_cgGetNamedParameter( progPtr, name, ( CGenum )0, &arrayIndex );
|
|
if ( param )
|
|
{
|
|
int ret = ( int )param->id;
|
|
if ( arrayIndex != -1 )
|
|
ret |= ( arrayIndex << CG_PARAMETERSIZE );
|
|
return ( CGparameter )ret;
|
|
}
|
|
else
|
|
return ( CGparameter )NULL;
|
|
}
|
|
|
|
CG_API CGparameter cgGetFirstParameter( CGprogram prog, CGenum name_space )
|
|
{
|
|
// check program handle
|
|
if ( !CG_IS_PROGRAM( prog ) )
|
|
{
|
|
rglCgRaiseError( CG_INVALID_PROGRAM_HANDLE_ERROR );
|
|
return ( CGparameter )NULL;
|
|
}
|
|
|
|
_CGprogram* progPtr = _cgGetProgPtr( prog );
|
|
|
|
CgRuntimeParameter *rtParameter = ( CgRuntimeParameter* )progPtr->runtimeParameters;
|
|
|
|
// find the first param of the requested namespace
|
|
for ( int i = 0; i < progPtr->rtParametersCount; ++i )
|
|
{
|
|
// check parameter handle
|
|
bool isGlobal = ( rtParameter->parameterEntry->flags & CGPF_GLOBAL ) == CGPF_GLOBAL;
|
|
if ( isGlobal && name_space == CG_GLOBAL )
|
|
{
|
|
return ( CGparameter )rtParameter->id;
|
|
}
|
|
if ( !isGlobal && name_space == CG_PROGRAM )
|
|
{
|
|
return ( CGparameter )rtParameter->id;
|
|
}
|
|
rtParameter++;
|
|
}
|
|
return ( CGparameter )NULL;
|
|
}
|
|
|
|
CG_API CGparameter cgGetNextParameter( CGparameter param )
|
|
{
|
|
//check parameter handle
|
|
CgRuntimeParameter *rtParameter = ( CgRuntimeParameter* )rglCgGLTestParameter( param );
|
|
if ( !rtParameter )
|
|
return ( CGparameter )NULL;
|
|
|
|
// the case of the array element of a compact array is easy to solve
|
|
int arrayIndex = -1;
|
|
if ( rtParameter > rtParameter->program->runtimeParameters )
|
|
{
|
|
CgRuntimeParameter *previousParameter = rtParameter - 1;
|
|
if (( previousParameter->parameterEntry->flags & CGP_ARRAY ) &&
|
|
!( previousParameter->parameterEntry->flags & CGP_UNROLLED ) )
|
|
{
|
|
//we have an array item
|
|
arrayIndex = CG_GETINDEX( param );
|
|
const CgParameterArray *parameterArray = rglGetParameterArray( previousParameter->program, previousParameter->parameterEntry );
|
|
int arraySize = rglGetSizeofSubArray(( short* )parameterArray->dimensions, parameterArray->dimensionCount );
|
|
arrayIndex++;
|
|
if ( arrayIndex < arraySize )
|
|
{
|
|
int ret = ( int )rtParameter->id;
|
|
ret |= ( arrayIndex << CG_PARAMETERSIZE );
|
|
return ( CGparameter )ret;
|
|
}
|
|
else
|
|
return ( CGparameter )NULL;
|
|
}
|
|
}
|
|
|
|
//get the parent of the current as well as its location
|
|
const CgParameterEntry *paramEntry = rtParameter->parameterEntry;
|
|
const CgParameterEntry *firstEntry = rtParameter->program->parametersEntries;
|
|
|
|
int distance = 1;
|
|
paramEntry--;
|
|
|
|
bool bNextExists = false;
|
|
while ( paramEntry >= firstEntry && !bNextExists )
|
|
{
|
|
switch ( paramEntry->flags & CGP_TYPE_MASK )
|
|
{
|
|
case CGP_ARRAY:
|
|
distance--; // the array has one extra item, whether it's a structure or if it's an intrinsic type
|
|
//Ced: not it's not true, if it's unrolled there is no extra item
|
|
break;
|
|
case CGP_STRUCTURE:
|
|
{
|
|
const CgParameterStructure *parameterStructure = rglGetParameterStructure( rtParameter->program, paramEntry );
|
|
//+1 because of the structure element, there's structure
|
|
if ( distance >= ( parameterStructure->memberCount + 1 ) )
|
|
{
|
|
//the parameter is not in this structure, so I need to remove from the distance all the structure item
|
|
//so this structure will count for a distance of just one ( the distance is the level distance )
|
|
distance -= parameterStructure->memberCount;
|
|
}
|
|
else
|
|
{
|
|
//We are going to exit here
|
|
//ok so we were in this structure, so check if we have more item in the structure after the current one
|
|
if ( distance < parameterStructure->memberCount )
|
|
{
|
|
//we still have some items in the structure, take the next item
|
|
bNextExists = true;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
//no more items at this level return null
|
|
return ( CGparameter )NULL;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case CGP_INTRINSIC:
|
|
break;
|
|
}
|
|
distance++;
|
|
paramEntry--;
|
|
}
|
|
//we have now elimated the case where we were in a struct and there were no more items, now if the item has a successor,
|
|
//this is what we are looking for
|
|
|
|
//we have already treated the current entry at that point, the loop starts on the previous one, the distance is 1
|
|
CGparameter nextParam = rglAdvanceParameter( rtParameter->id, 1 );
|
|
|
|
if ( nextParam )
|
|
{
|
|
CgRuntimeParameter *nextParameter = ( CgRuntimeParameter* )rglCgGLTestParameter( nextParam );
|
|
|
|
//check that next param is still in the same namespace as param
|
|
bool isCurrentGlobal = ( rtParameter->parameterEntry->flags & CGPF_GLOBAL ) == CGPF_GLOBAL;
|
|
bool isNextGlobal = ( nextParameter->parameterEntry->flags & CGPF_GLOBAL ) == CGPF_GLOBAL;
|
|
if ( isNextGlobal != isCurrentGlobal )
|
|
{
|
|
//the next item doesn't have the same global flag... since they are grouped, it means we have quitted the current struct
|
|
return ( CGparameter )NULL;
|
|
}
|
|
else
|
|
return nextParam;
|
|
}
|
|
else
|
|
{
|
|
//case where we were at the root and there is no more items
|
|
return ( CGparameter )NULL;
|
|
}
|
|
}
|
|
|
|
CG_API const char* cgGetParameterSemantic( CGparameter param )
|
|
{
|
|
// check parameter handle
|
|
CgRuntimeParameter *rtParameter = ( CgRuntimeParameter* )rglCgGLTestParameter( param );
|
|
if ( !rtParameter )
|
|
return NULL;
|
|
|
|
const CgParameterEntry *parameterEntry = rtParameter->parameterEntry;
|
|
|
|
unsigned short type = parameterEntry->flags & CGP_TYPE_MASK;
|
|
if ( type == CGP_STRUCTURE || CGP_STRUCTURE == CGP_ARRAY )
|
|
{
|
|
rglCgRaiseError( CG_INVALID_PARAMETER_ERROR );
|
|
return NULL;
|
|
}
|
|
|
|
size_t entryIndex = ( parameterEntry - rtParameter->program->parametersEntries );
|
|
|
|
//look for the parameter semantic in the semantic table for semantics set in the compiled source
|
|
int count = rtParameter->program->semanticCount;
|
|
int i;
|
|
for ( i = 0;i < count;i++ )
|
|
{
|
|
const CgParameterSemantic *semantic = rtParameter->program->semanticIndices + i;
|
|
|
|
if ( semantic->entryIndex == ( unsigned short )entryIndex )
|
|
return rtParameter->program->stringTable + semantic->semanticOffset; // found
|
|
}
|
|
|
|
//not found, we don't have the semantic for this parameter, returns empty strings
|
|
return "";
|
|
}
|
|
|
|
static bool rglPrependString( char *dst, const char *src, size_t size )
|
|
{
|
|
int len = strlen(src);
|
|
int previousLen = strlen(dst);
|
|
int spaceLeft = size - (previousLen + 1); //+1 for white space
|
|
if (spaceLeft < len)
|
|
return false;
|
|
memmove(dst + len, dst, previousLen + 1);
|
|
strncpy(dst, src, len);
|
|
return true;
|
|
}
|
|
|
|
CG_API CGenum cgGetParameterVariability( CGparameter param )
|
|
{
|
|
// check parameter handle
|
|
CgRuntimeParameter *rtParameter = ( CgRuntimeParameter* )rglCgGLTestParameter( param );
|
|
if ( !rtParameter )
|
|
return ( CGenum )0;
|
|
else
|
|
{
|
|
unsigned int variability = rtParameter->parameterEntry->flags & CGPV_MASK;
|
|
if ( variability == CGPV_UNIFORM )
|
|
return CG_UNIFORM;
|
|
else if ( variability == CGPV_VARYING )
|
|
return CG_VARYING;
|
|
else if ( variability == CGPV_CONSTANT )
|
|
return CG_CONSTANT;
|
|
else if ( variability == CGPV_MIXED )
|
|
return CG_MIXED;
|
|
else
|
|
return ( CGenum )0;
|
|
}
|
|
}
|
|
|
|
CG_API CGenum cgGetParameterDirection( CGparameter param )
|
|
{
|
|
// check parameter handle
|
|
CgRuntimeParameter *rtParameter = ( CgRuntimeParameter* )rglCgGLTestParameter( param );
|
|
if ( !rtParameter )
|
|
return CG_ERROR;
|
|
else
|
|
{
|
|
unsigned int direction = rtParameter->parameterEntry->flags & CGPD_MASK;
|
|
if ( direction == CGPD_IN )
|
|
return CG_IN;
|
|
else if ( direction == CGPD_OUT )
|
|
return CG_OUT;
|
|
else if ( direction == CGPD_INOUT )
|
|
return CG_INOUT;
|
|
else
|
|
return CG_ERROR;
|
|
}
|
|
}
|
|
|
|
/*============================================================
|
|
CG TOKENS
|
|
============================================================ */
|
|
|
|
// ErrorFunctions ----------------------------
|
|
CG_API CGerror cgGetError( void )
|
|
{
|
|
CGerror err = _CurrentContext->RGLcgLastError;
|
|
_CurrentContext->RGLcgLastError = CG_NO_ERROR;
|
|
return err;
|
|
}
|
|
|
|
CG_API const char* cgGetErrorString( CGerror error )
|
|
{
|
|
return "cgGetErrorString not implemented.\n";
|
|
}
|
|
|
|
CG_API void cgSetErrorCallback( CGerrorCallbackFunc func )
|
|
{
|
|
_CurrentContext->RGLcgErrorCallbackFunction = func;
|
|
}
|
|
|
|
CG_API CGerrorCallbackFunc cgGetErrorCallback( void )
|
|
{
|
|
return _CurrentContext->RGLcgErrorCallbackFunction;
|
|
}
|
|
|
|
|
|
// Misc Functions -----------------------------
|
|
|
|
CG_API const char* cgGetString( CGenum sname )
|
|
{
|
|
if ( sname == CG_VERSION )
|
|
{
|
|
// this should return the version of the runtime or perhaps more meaninfully, the runtime compiler
|
|
static char versionstring[8];
|
|
sprintf( versionstring, "%d", CG_VERSION_NUM );
|
|
return versionstring;
|
|
}
|
|
|
|
rglCgRaiseError( CG_INVALID_ENUMERANT_ERROR );
|
|
return NULL;
|
|
}
|
|
|
|
/*============================================================
|
|
CG CONTEXT
|
|
============================================================ */
|
|
|
|
RGL_EXPORT CgcontextHookFunction _cgContextCreateHook = NULL;
|
|
RGL_EXPORT CgcontextHookFunction _cgContextDestroyHook = NULL;
|
|
|
|
void rglCgContextPushFront( _CGcontext* ctx )
|
|
{
|
|
if ( _CurrentContext->RGLcgContextHead )
|
|
{
|
|
_CGcontext* head = _cgGetContextPtr( _CurrentContext->RGLcgContextHead );
|
|
// insert this context at the head of the list
|
|
ctx->next = head;
|
|
}
|
|
_CurrentContext->RGLcgContextHead = ctx->id;
|
|
}
|
|
|
|
static void destroy_context( _CGcontext*ctx )
|
|
{
|
|
if ( _cgContextDestroyHook ) _cgContextDestroyHook( ctx );
|
|
// free the id
|
|
rglEraseName( &_CurrentContext->cgContextNameSpace, (unsigned int)ctx->id );
|
|
// zero the memory
|
|
memset(ctx, 0, sizeof( *ctx));
|
|
ctx->compileType = CG_UNKNOWN;
|
|
// return context to free store
|
|
free( ctx );
|
|
}
|
|
|
|
// API functions ----------------------------------------
|
|
|
|
CG_API CGcontext cgCreateContext( void )
|
|
{
|
|
// create a context out of thin air and add it to the hidden global list.
|
|
|
|
_CGcontext* ptr = (_CGcontext*)malloc(sizeof(_CGcontext));
|
|
if ( NULL == ptr )
|
|
{
|
|
rglCgRaiseError( CG_MEMORY_ALLOC_ERROR );
|
|
return ( CGcontext )NULL;
|
|
}
|
|
|
|
// initialise member variables
|
|
memset(ptr, 0, sizeof( *ptr));
|
|
ptr->compileType = CG_UNKNOWN;
|
|
|
|
// get a new id for the object
|
|
CGcontext result = ( CGcontext )rglCreateName( &_CurrentContext->cgContextNameSpace, ptr );
|
|
if ( !result ) { free( ptr ); return NULL; }
|
|
|
|
ptr->id = result;
|
|
ptr->defaultProgram.parentContext = ptr;
|
|
|
|
// insert context at head of global list
|
|
rglCgContextPushFront( ptr );
|
|
|
|
if ( _cgContextCreateHook ) _cgContextCreateHook( ptr );
|
|
|
|
return result;
|
|
}
|
|
|
|
CG_API void cgDestroyContext( CGcontext c )
|
|
{
|
|
// check if context is valid
|
|
if ( !CG_IS_CONTEXT( c ) )
|
|
{
|
|
rglCgRaiseError( CG_INVALID_CONTEXT_HANDLE_ERROR );
|
|
return;
|
|
}
|
|
|
|
_CGcontext* ctx = _cgGetContextPtr( c );
|
|
|
|
rglCgProgramErase( &ctx->defaultProgram );
|
|
|
|
// destroy all programs
|
|
rglCgProgramDestroyAll( ctx );
|
|
|
|
// unlink from global CGContext list
|
|
_CGcontext * const head = _cgGetContextPtr( _CurrentContext->RGLcgContextHead );
|
|
if ( head != ctx )
|
|
{
|
|
// node is not the head, find and erase it
|
|
|
|
// find the context that occurs before this one
|
|
_CGcontext* ptr = head;
|
|
while ( ptr->next != ctx )
|
|
ptr = ptr->next;
|
|
// relink
|
|
ptr->next = ctx->next;
|
|
destroy_context( ctx );
|
|
}
|
|
else
|
|
{
|
|
|
|
// node is the head, erase it
|
|
_CGcontext* second = head->next;
|
|
destroy_context( head );
|
|
|
|
// link to second element
|
|
if ( second )
|
|
_CurrentContext->RGLcgContextHead = second->id;
|
|
// nothing left
|
|
else
|
|
_CurrentContext->RGLcgContextHead = 0;
|
|
}
|
|
}
|
|
|
|
CG_API const char* cgGetLastListing( CGcontext c )
|
|
{
|
|
// check to see if context is a valid one
|
|
// NOTE: Cg API Reference docs omit this test for this API function.
|
|
if ( !CG_IS_CONTEXT( c ) )
|
|
{
|
|
rglCgRaiseError( CG_INVALID_CONTEXT_HANDLE_ERROR );
|
|
return NULL;
|
|
}
|
|
|
|
// currently does nothing
|
|
// TODO ****************************
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/*============================================================
|
|
CG PROGRAM
|
|
============================================================ */
|
|
|
|
RGL_EXPORT CgprogramHookFunction _cgProgramCreateHook = NULL;
|
|
RGL_EXPORT CgprogramHookFunction _cgProgramDestroyHook = NULL;
|
|
RGL_EXPORT CgprogramCopyHookFunction _cgProgramCopyHook = NULL;
|
|
|
|
RGL_EXPORT cgRTCgcCompileHookFunction _cgRTCgcCompileProgramHook = NULL;
|
|
RGL_EXPORT cgRTCgcFreeHookFunction _cgRTCgcFreeCompiledProgramHook;
|
|
|
|
// Program list functions
|
|
// The context can contain many programs, but each one is a variable sized
|
|
// chunk of data produced by the CGC compiler and loaded at runtime. We cannot
|
|
// include intrusive "next" pointers in this data block so instead we'll use
|
|
// a non-intrusive list. The list is walked using cgGetFirstProgram() and
|
|
// cgGetNextProgram()
|
|
|
|
void rglCgProgramPushFront( _CGcontext* ctx, _CGprogram* prog )
|
|
{
|
|
// push the program to the context.
|
|
// updates the linked list and program count
|
|
|
|
// link the node into the head of the list
|
|
prog->next = ctx->programList;
|
|
ctx->programList = prog;
|
|
|
|
// update the parent context
|
|
prog->parentContext = ctx;
|
|
|
|
// update the program count
|
|
ctx->programCount++;
|
|
}
|
|
|
|
_CGprogram* rglCgProgramFindPrev( _CGcontext* ctx, _CGprogram* prog )
|
|
{
|
|
// get a pointer the the list element *before* prog in the list
|
|
// this allows us to unlink it safely.
|
|
|
|
_CGprogram* ptr = ctx->programList;
|
|
|
|
while (ptr && prog != ptr->next )
|
|
ptr = ptr->next;
|
|
|
|
return ptr;
|
|
}
|
|
|
|
inline void rglCgProgramEraseAndFree( _CGprogram* prog )
|
|
{
|
|
rglCgProgramErase( prog );
|
|
free( prog );
|
|
}
|
|
|
|
void rglCgProgramErase( _CGprogram* prog )
|
|
{
|
|
// remove the program from the linked list and deallocate it's storage.
|
|
|
|
if ( _cgProgramDestroyHook ) _cgProgramDestroyHook( prog );
|
|
|
|
switch ( prog->header.profile )
|
|
{
|
|
case CG_PROFILE_SCE_VP_RSX:
|
|
case CG_PROFILE_SCE_FP_RSX:
|
|
rglpProgramErase( prog );
|
|
break;
|
|
default:
|
|
// default program
|
|
break;
|
|
}
|
|
|
|
// return program and node to free store
|
|
if ( prog->id ) rglEraseName( &_CurrentContext->cgProgramNameSpace, (unsigned int)prog->id );
|
|
|
|
//free ELF data obtained from the runtime converter
|
|
if ( prog->runtimeElf )
|
|
free( prog->runtimeElf );
|
|
|
|
// zero out all pointers
|
|
memset( prog, 0, sizeof( _CGprogram ) );
|
|
}
|
|
|
|
void rglCgProgramEraseAfter( _CGprogram* prog )
|
|
{
|
|
// delete the list entry after the current pointer.
|
|
// (use in conjunction with find_prev for full effect!)
|
|
|
|
_CGprogram* next = prog->next;
|
|
if ( next )
|
|
{
|
|
prog->next = next->next;
|
|
rglCgProgramEraseAndFree( next );
|
|
}
|
|
}
|
|
|
|
void rglCgProgramDestroyAll( _CGcontext* ctx )
|
|
{
|
|
// destroy all programs in this context
|
|
while ( ctx->programList )
|
|
{
|
|
_CGprogram * p = ctx->programList;
|
|
ctx->programList = p->next;
|
|
// erase the program
|
|
rglCgProgramEraseAndFree( p );
|
|
}
|
|
}
|
|
|
|
|
|
static inline unsigned int getMatrixRowCount( CGtype type )
|
|
{
|
|
unsigned int rc = 0;
|
|
switch ( type )
|
|
{
|
|
case CG_FLOAT1x1:
|
|
case CG_FLOAT1x2:
|
|
case CG_FLOAT1x3:
|
|
case CG_FLOAT1x4:
|
|
case CG_HALF1x1:
|
|
case CG_HALF1x2:
|
|
case CG_HALF1x3:
|
|
case CG_HALF1x4:
|
|
case CG_INT1x1:
|
|
case CG_INT1x2:
|
|
case CG_INT1x3:
|
|
case CG_INT1x4:
|
|
case CG_BOOL1x1:
|
|
case CG_BOOL1x2:
|
|
case CG_BOOL1x3:
|
|
case CG_BOOL1x4:
|
|
case CG_FIXED1x1:
|
|
case CG_FIXED1x2:
|
|
case CG_FIXED1x3:
|
|
case CG_FIXED1x4:
|
|
rc = 1;
|
|
break;
|
|
case CG_FLOAT2x1:
|
|
case CG_FLOAT2x2:
|
|
case CG_FLOAT2x3:
|
|
case CG_FLOAT2x4:
|
|
case CG_HALF2x1:
|
|
case CG_HALF2x2:
|
|
case CG_HALF2x3:
|
|
case CG_HALF2x4:
|
|
case CG_INT2x1:
|
|
case CG_INT2x2:
|
|
case CG_INT2x3:
|
|
case CG_INT2x4:
|
|
case CG_BOOL2x1:
|
|
case CG_BOOL2x2:
|
|
case CG_BOOL2x3:
|
|
case CG_BOOL2x4:
|
|
case CG_FIXED2x1:
|
|
case CG_FIXED2x2:
|
|
case CG_FIXED2x3:
|
|
case CG_FIXED2x4:
|
|
rc = 2;
|
|
break;
|
|
case CG_FLOAT3x1:
|
|
case CG_FLOAT3x2:
|
|
case CG_FLOAT3x3:
|
|
case CG_FLOAT3x4:
|
|
case CG_HALF3x1:
|
|
case CG_HALF3x2:
|
|
case CG_HALF3x3:
|
|
case CG_HALF3x4:
|
|
case CG_INT3x1:
|
|
case CG_INT3x2:
|
|
case CG_INT3x3:
|
|
case CG_INT3x4:
|
|
case CG_BOOL3x1:
|
|
case CG_BOOL3x2:
|
|
case CG_BOOL3x3:
|
|
case CG_BOOL3x4:
|
|
case CG_FIXED3x1:
|
|
case CG_FIXED3x2:
|
|
case CG_FIXED3x3:
|
|
case CG_FIXED3x4:
|
|
rc = 3;
|
|
break;
|
|
case CG_FLOAT4x1:
|
|
case CG_FLOAT4x2:
|
|
case CG_FLOAT4x3:
|
|
case CG_FLOAT4x4:
|
|
case CG_HALF4x1:
|
|
case CG_HALF4x2:
|
|
case CG_HALF4x3:
|
|
case CG_HALF4x4:
|
|
case CG_INT4x1:
|
|
case CG_INT4x2:
|
|
case CG_INT4x3:
|
|
case CG_INT4x4:
|
|
case CG_BOOL4x1:
|
|
case CG_BOOL4x2:
|
|
case CG_BOOL4x3:
|
|
case CG_BOOL4x4:
|
|
case CG_FIXED4x1:
|
|
case CG_FIXED4x2:
|
|
case CG_FIXED4x3:
|
|
case CG_FIXED4x4:
|
|
rc = 4;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
CGtype getMatrixRowType( CGtype type )
|
|
{
|
|
CGtype rt = ( CGtype )0;
|
|
switch ( type )
|
|
{
|
|
case CG_FLOAT1x1:
|
|
case CG_FLOAT2x1:
|
|
case CG_FLOAT3x1:
|
|
case CG_FLOAT4x1:
|
|
rt = CG_FLOAT1;
|
|
break;
|
|
case CG_FLOAT1x2:
|
|
case CG_FLOAT2x2:
|
|
case CG_FLOAT3x2:
|
|
case CG_FLOAT4x2:
|
|
rt = CG_FLOAT2;
|
|
break;
|
|
case CG_FLOAT1x3:
|
|
case CG_FLOAT2x3:
|
|
case CG_FLOAT3x3:
|
|
case CG_FLOAT4x3:
|
|
rt = CG_FLOAT3;
|
|
break;
|
|
case CG_FLOAT1x4:
|
|
case CG_FLOAT2x4:
|
|
case CG_FLOAT3x4:
|
|
case CG_FLOAT4x4:
|
|
rt = CG_FLOAT4;
|
|
break;
|
|
case CG_HALF1x1:
|
|
case CG_HALF2x1:
|
|
case CG_HALF3x1:
|
|
case CG_HALF4x1:
|
|
rt = CG_HALF1;
|
|
break;
|
|
case CG_HALF1x2:
|
|
case CG_HALF2x2:
|
|
case CG_HALF3x2:
|
|
case CG_HALF4x2:
|
|
rt = CG_HALF2;
|
|
break;
|
|
case CG_HALF1x3:
|
|
case CG_HALF2x3:
|
|
case CG_HALF3x3:
|
|
case CG_HALF4x3:
|
|
rt = CG_HALF3;
|
|
break;
|
|
case CG_HALF1x4:
|
|
case CG_HALF2x4:
|
|
case CG_HALF3x4:
|
|
case CG_HALF4x4:
|
|
rt = CG_HALF4;
|
|
break;
|
|
case CG_INT1x1:
|
|
case CG_INT2x1:
|
|
case CG_INT3x1:
|
|
case CG_INT4x1:
|
|
rt = CG_INT1;
|
|
break;
|
|
case CG_INT1x2:
|
|
case CG_INT2x2:
|
|
case CG_INT3x2:
|
|
case CG_INT4x2:
|
|
rt = CG_INT2;
|
|
break;
|
|
case CG_INT1x3:
|
|
case CG_INT2x3:
|
|
case CG_INT3x3:
|
|
case CG_INT4x3:
|
|
rt = CG_INT3;
|
|
break;
|
|
case CG_INT1x4:
|
|
case CG_INT2x4:
|
|
case CG_INT3x4:
|
|
case CG_INT4x4:
|
|
rt = CG_INT4;
|
|
break;
|
|
case CG_BOOL1x1:
|
|
case CG_BOOL2x1:
|
|
case CG_BOOL3x1:
|
|
case CG_BOOL4x1:
|
|
rt = CG_BOOL1;
|
|
break;
|
|
case CG_BOOL1x2:
|
|
case CG_BOOL2x2:
|
|
case CG_BOOL3x2:
|
|
case CG_BOOL4x2:
|
|
rt = CG_BOOL2;
|
|
break;
|
|
case CG_BOOL1x3:
|
|
case CG_BOOL2x3:
|
|
case CG_BOOL3x3:
|
|
case CG_BOOL4x3:
|
|
rt = CG_BOOL3;
|
|
break;
|
|
case CG_BOOL1x4:
|
|
case CG_BOOL2x4:
|
|
case CG_BOOL3x4:
|
|
case CG_BOOL4x4:
|
|
rt = CG_BOOL4;
|
|
break;
|
|
case CG_FIXED1x1:
|
|
case CG_FIXED2x1:
|
|
case CG_FIXED3x1:
|
|
case CG_FIXED4x1:
|
|
rt = CG_FIXED1;
|
|
break;
|
|
case CG_FIXED1x2:
|
|
case CG_FIXED2x2:
|
|
case CG_FIXED3x2:
|
|
case CG_FIXED4x2:
|
|
rt = CG_FIXED2;
|
|
break;
|
|
case CG_FIXED1x3:
|
|
case CG_FIXED2x3:
|
|
case CG_FIXED3x3:
|
|
case CG_FIXED4x3:
|
|
rt = CG_FIXED3;
|
|
break;
|
|
case CG_FIXED1x4:
|
|
case CG_FIXED2x4:
|
|
case CG_FIXED3x4:
|
|
case CG_FIXED4x4:
|
|
rt = CG_FIXED4;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return rt;
|
|
}
|
|
|
|
|
|
// forward declaration for recursion
|
|
void AccumulateSizeForParams( CgParameterEntry* paramEntry, CgParameterEntry* paramEntries, unsigned int paramEntriesCount,
|
|
unsigned short* paramResourceTable, ELF_section_t* strtab, CgParameterEntry** nextEntry,
|
|
unsigned int prefixLength, int elementResourceIndex,
|
|
size_t* nvParamSize, size_t* nvParamStringsSize, size_t* nvParamOffsetsSize,
|
|
CgParameterSemantic* semanticIndexTable, unsigned int semanticIndexCount,
|
|
CgParameterDefaultValue* defaultIndexTable, unsigned int defaultIndexCount, size_t* nvParamDefaultsSize,
|
|
ELF_section_t* consttab );
|
|
|
|
void AccumulateSizeForParamResource( CgParameterEntry* paramEntry, CgParameterEntry* paramEntries, unsigned int paramEntriesCount,
|
|
unsigned short* paramResourceTable, ELF_section_t* strtab, CgParameterEntry** nextEntry,
|
|
unsigned int prefixLength, int elementResourceIndex,
|
|
size_t* nvParamSize, size_t* nvParamStringsSize, size_t* nvParamOffsetsSize,
|
|
CgParameterSemantic* semanticIndexTable, unsigned int semanticIndexCount,
|
|
CgParameterDefaultValue* defaultIndexTable, unsigned int defaultIndexCount, size_t* nvParamDefaultsSize,
|
|
ELF_section_t* consttab )
|
|
{
|
|
// type index is actually the offset into the block of memory following the entries
|
|
CgParameterResource* paramResource = ( CgParameterResource* )(( char* )( paramEntries + paramEntriesCount ) + paramEntry->typeIndex );
|
|
|
|
unsigned int rowCount = getMatrixRowCount(( CGtype )paramResource->type );
|
|
|
|
// param
|
|
*nvParamSize += sizeof( CgBinaryParameter );
|
|
// and for the row params of a matrix
|
|
*nvParamSize += rowCount * sizeof( CgBinaryParameter );
|
|
|
|
// name
|
|
*nvParamStringsSize += ( prefixLength + strlen( strtab->data + paramEntry->nameOffset ) + 1 );
|
|
// and for each row of a matrix which assumes just an extra 3 characters for [i]
|
|
*nvParamStringsSize += ( rowCount * ( prefixLength + strlen( strtab->data + paramEntry->nameOffset ) + 3 + 1 ) );
|
|
|
|
|
|
// semantic
|
|
|
|
// totally inefficient, but easiest implementation for now is to do the On^2 search
|
|
// in the semantic and default tables for the data associated with this parameter
|
|
unsigned int entryIndex = paramEntry - paramEntries;
|
|
|
|
// semantic
|
|
char* semantic = NULL;
|
|
for ( unsigned int sem = 0; sem < semanticIndexCount; sem++ )
|
|
{
|
|
CgParameterSemantic* semanticIndex = semanticIndexTable + sem;
|
|
if ( semanticIndex->entryIndex == entryIndex )
|
|
{
|
|
// found the semantic for this parameter
|
|
semantic = strtab->data + semanticIndex->semanticOffset;
|
|
break;
|
|
}
|
|
}
|
|
if ( semantic )
|
|
{
|
|
// increment the names size buffer
|
|
*nvParamStringsSize += strlen( semantic ) + 1;
|
|
}
|
|
|
|
// default
|
|
float* defaults = NULL;
|
|
for ( unsigned int def = 0; def < defaultIndexCount; def++ )
|
|
{
|
|
CgParameterDefaultValue* defaultIndex = defaultIndexTable + def;
|
|
if ( defaultIndex->entryIndex == entryIndex )
|
|
{
|
|
// found the default for this parameter
|
|
defaults = ( float* )consttab->data + defaultIndex->defaultValueIndex;
|
|
}
|
|
}
|
|
if (defaults)
|
|
{
|
|
// defaults are always padded to 4 floats per param
|
|
unsigned int defaultsCount = ( rowCount ? rowCount : 1 ) * 4;
|
|
*nvParamDefaultsSize += sizeof( float ) * defaultsCount;
|
|
}
|
|
|
|
// offsets
|
|
// fragment programs
|
|
// do we want this referenced param test???
|
|
if (nvParamOffsetsSize && paramEntry->flags & CGPF_REFERENCED )
|
|
{
|
|
// non varying params
|
|
if ( paramEntry->flags & CGPV_CONSTANT || paramEntry->flags & CGPV_UNIFORM )
|
|
{
|
|
// non sampler types
|
|
if ( !isSampler(( CGtype )paramResource->type ) )
|
|
{
|
|
unsigned short* resPtr = paramResourceTable + paramResource->resource;
|
|
|
|
if ( elementResourceIndex >= 0 )
|
|
{
|
|
//advance resPtr to the arrayIndex
|
|
int skipCount = elementResourceIndex;
|
|
while ( skipCount )
|
|
{
|
|
resPtr++;
|
|
int embeddedCount = *( resPtr++ );
|
|
resPtr += embeddedCount;
|
|
// if an array of matrices, must skip row parameter resources too
|
|
for ( int row = 1; row <= ( int )rowCount; row++ )
|
|
{
|
|
resPtr++;
|
|
int embeddedCount = *( resPtr++ );
|
|
resPtr += embeddedCount;
|
|
}
|
|
skipCount--;
|
|
}
|
|
//resPtr points to the resource of the arrayIndex
|
|
}
|
|
|
|
if ( !isMatrix(( CGtype )( paramResource->type ) ) )
|
|
{
|
|
// advance past register to second field that contains embedded count
|
|
resPtr++;
|
|
unsigned int embeddedConstantCount = *( resPtr++ );
|
|
*nvParamOffsetsSize += sizeof( CgBinaryEmbeddedConstant ) + sizeof( unsigned int ) * ( embeddedConstantCount - 1 );
|
|
}
|
|
else
|
|
{
|
|
for ( int row = 1; row <= ( int )rowCount; row++ )
|
|
{
|
|
// advance past register to second field that contains embedded count
|
|
resPtr++;
|
|
unsigned int embeddedConstantCount = *( resPtr++ );
|
|
*nvParamOffsetsSize += sizeof( CgBinaryEmbeddedConstant ) + sizeof( unsigned int ) * ( embeddedConstantCount - 1 );
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
// entry cursor
|
|
*nextEntry = paramEntry + 1;
|
|
}
|
|
|
|
void AccumulateSizeForParamArray( CgParameterEntry* paramEntry, CgParameterEntry* paramEntries, unsigned int paramEntriesCount,
|
|
unsigned short* paramResourceTable, ELF_section_t* strtab, CgParameterEntry** nextEntry,
|
|
unsigned int prefixLength, int elementResourceIndex,
|
|
size_t* nvParamSize, size_t* nvParamStringsSize, size_t* nvParamOffsetsSize,
|
|
CgParameterSemantic* semanticIndexTable, unsigned int semanticIndexCount,
|
|
CgParameterDefaultValue* defaultIndexTable, unsigned int defaultIndexCount, size_t* nvParamDefaultsSize,
|
|
ELF_section_t* consttab )
|
|
{
|
|
// type index is actually the offset into the block of memory following the entries
|
|
CgParameterArray* paramArray = ( CgParameterArray* )(( char* )( paramEntries + paramEntriesCount ) + paramEntry->typeIndex );
|
|
|
|
// this parameter's entry says it's an array
|
|
// this parameter's entry says its packing in the flags
|
|
// the next entry specifies its type...
|
|
// ... either a list of every element in the array
|
|
// ... or a single element in the array to represent all because they are the same
|
|
// ... or a single element to specify the layout of the parameter, but not every element has a resource
|
|
|
|
// this would give the number of intrinsics OR structs, but if base type is struct
|
|
// to get the number of parameters, must recurse over struct fields
|
|
unsigned int numElements = 1;
|
|
for ( unsigned int dim = 0; dim < paramArray->dimensionCount; dim++ )
|
|
numElements *= paramArray->dimensions[dim];
|
|
|
|
unsigned int prefixLengthIn = prefixLength;
|
|
|
|
// next entry will always be either an intrinsic or a struct
|
|
|
|
if ( !( paramEntry->flags & CGP_UNROLLED ) ) // one bit is not enough cause there are 3 representations!
|
|
{
|
|
// all elements are the same so have one entry to represent all of them
|
|
CgParameterEntry* elementEntry = paramEntry + 1;
|
|
|
|
// entries are same type, and packed, so just repeat same param
|
|
for ( unsigned int element = 0; element < numElements; element++ )
|
|
{
|
|
// name length for prefixIn + rest of array name for array + 16 bytes generously for [index]
|
|
prefixLength = prefixLengthIn + strlen( strtab->data + paramEntry->nameOffset ) + 16;
|
|
|
|
// right now i think this is always intrinsics for the not unrolled case, current limitation
|
|
AccumulateSizeForParamResource( elementEntry, paramEntries, paramEntriesCount,
|
|
paramResourceTable, strtab, nextEntry,
|
|
prefixLength, element,
|
|
nvParamSize, nvParamStringsSize, nvParamOffsetsSize,
|
|
semanticIndexTable, semanticIndexCount,
|
|
defaultIndexTable, defaultIndexCount, nvParamDefaultsSize,
|
|
consttab );
|
|
|
|
*nextEntry = *nextEntry - 1; // undo the increment on the next entry for this special case of shared entries
|
|
}
|
|
*nextEntry = *nextEntry + 1; // redo the increment upon exiting the loop, could be smarter, whatever
|
|
}
|
|
else if ( paramEntry->flags & CGP_UNROLLED )
|
|
{
|
|
// here everything is unrolled
|
|
|
|
CgParameterEntry* elementEntry = paramEntry + 1;
|
|
|
|
for ( unsigned int element = 0; element < numElements; element++ )
|
|
{
|
|
// name length for prefixIn + rest of array name for array + 16 bytes generously for [index]
|
|
prefixLength = prefixLengthIn + strlen( strtab->data + paramEntry->nameOffset ) + 16;
|
|
|
|
AccumulateSizeForParams( elementEntry, paramEntries, paramEntriesCount,
|
|
paramResourceTable, strtab, nextEntry,
|
|
prefixLength, -1,
|
|
nvParamSize, nvParamStringsSize, nvParamOffsetsSize,
|
|
semanticIndexTable, semanticIndexCount,
|
|
defaultIndexTable, defaultIndexCount, nvParamDefaultsSize,
|
|
consttab );
|
|
|
|
elementEntry = *nextEntry;
|
|
}
|
|
}
|
|
}
|
|
|
|
void AccumulateSizeForParamStruct( CgParameterEntry* paramEntry, CgParameterEntry* paramEntries, unsigned int paramEntriesCount,
|
|
unsigned short* paramResourceTable, ELF_section_t* strtab, CgParameterEntry** nextEntry,
|
|
unsigned int prefixLength, int elementResourceIndex,
|
|
size_t* nvParamSize, size_t* nvParamStringsSize, size_t* nvParamOffsetsSize,
|
|
CgParameterSemantic* semanticIndexTable, unsigned int semanticIndexCount,
|
|
CgParameterDefaultValue* defaultIndexTable, unsigned int defaultIndexCount, size_t* nvParamDefaultsSize,
|
|
ELF_section_t* consttab )
|
|
{
|
|
// type index is actually the offset into the block of memory following the entries
|
|
CgParameterStructure* paramStruct = ( CgParameterStructure* )(( char* )( paramEntries + paramEntriesCount ) + paramEntry->typeIndex );
|
|
|
|
// add prefix of struct name and .
|
|
// !!! but what about if we are inside an array??? then no struct name
|
|
if ( paramEntry->nameOffset > 0 ) // is this the right test???
|
|
{
|
|
prefixLength += strlen( strtab->data + paramEntry->nameOffset );
|
|
}
|
|
prefixLength += 1; // allow for the dot
|
|
|
|
unsigned short memberCount = paramStruct->memberCount;
|
|
CgParameterEntry* memberEntry = paramEntry + 1;
|
|
|
|
for ( unsigned int member = 0; member < memberCount; member++ )
|
|
{
|
|
AccumulateSizeForParams( memberEntry, paramEntries, paramEntriesCount,
|
|
paramResourceTable, strtab, nextEntry,
|
|
prefixLength, -1,
|
|
nvParamSize, nvParamStringsSize, nvParamOffsetsSize,
|
|
semanticIndexTable, semanticIndexCount,
|
|
defaultIndexTable, defaultIndexCount, nvParamDefaultsSize,
|
|
consttab );
|
|
|
|
memberEntry = *nextEntry;
|
|
}
|
|
}
|
|
|
|
void AccumulateSizeForParams( CgParameterEntry* paramEntry, CgParameterEntry* paramEntries, unsigned int paramEntriesCount,
|
|
unsigned short* paramResourceTable, ELF_section_t* strtab, CgParameterEntry** nextEntry,
|
|
unsigned int prefixLength, int elementResourceIndex,
|
|
size_t* nvParamSize, size_t* nvParamStringsSize, size_t* nvParamOffsetsSize,
|
|
CgParameterSemantic* semanticIndexTable, unsigned int semanticIndexCount,
|
|
CgParameterDefaultValue* defaultIndexTable, unsigned int defaultIndexCount, size_t* nvParamDefaultsSize,
|
|
ELF_section_t* consttab )
|
|
{
|
|
// expand for intrinsics, arrays, and structs
|
|
// flags hold which type of parameter it is (along with other information)
|
|
switch ( paramEntry->flags & CGP_TYPE_MASK )
|
|
{
|
|
case CGP_INTRINSIC:
|
|
{
|
|
//printf("resource --- %p\n", paramEntry);
|
|
AccumulateSizeForParamResource( paramEntry, paramEntries, paramEntriesCount,
|
|
paramResourceTable, strtab, nextEntry,
|
|
prefixLength, elementResourceIndex,
|
|
nvParamSize, nvParamStringsSize, nvParamOffsetsSize,
|
|
semanticIndexTable, semanticIndexCount,
|
|
defaultIndexTable, defaultIndexCount, nvParamDefaultsSize,
|
|
consttab );
|
|
break;
|
|
}
|
|
case CGP_ARRAY:
|
|
{
|
|
//printf("array --- %p\n", paramEntry);
|
|
AccumulateSizeForParamArray( paramEntry, paramEntries, paramEntriesCount,
|
|
paramResourceTable, strtab, nextEntry,
|
|
prefixLength, elementResourceIndex,
|
|
nvParamSize, nvParamStringsSize, nvParamOffsetsSize,
|
|
semanticIndexTable, semanticIndexCount,
|
|
defaultIndexTable, defaultIndexCount, nvParamDefaultsSize,
|
|
consttab );
|
|
break;
|
|
}
|
|
case CGP_STRUCTURE:
|
|
{
|
|
//printf("structure --- %p\n", paramEntry);
|
|
AccumulateSizeForParamStruct( paramEntry, paramEntries, paramEntriesCount,
|
|
paramResourceTable, strtab, nextEntry,
|
|
prefixLength, elementResourceIndex,
|
|
nvParamSize, nvParamStringsSize, nvParamOffsetsSize,
|
|
semanticIndexTable, semanticIndexCount,
|
|
defaultIndexTable, defaultIndexCount, nvParamDefaultsSize,
|
|
consttab );
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// forward declaration for recursion
|
|
void PopulateDataForParams( CgParameterEntry* paramEntry, CgParameterEntry* paramEntries, unsigned int paramEntriesCount,
|
|
unsigned short* paramResourceTable, ELF_section_t* strtab, CgParameterEntry** nextEntry,
|
|
int elementResourceIndex, unsigned int* localParamNo, char* nvBinary,
|
|
CgBinaryParameter** nvParams, char** nvParamStrings,
|
|
CgBinaryEmbeddedConstant** nvParamOffsets, float** nvParamDefaults,
|
|
char* prefix, unsigned int prefixLength,
|
|
CgParameterSemantic* semanticIndexTable, unsigned int semanticIndexCount,
|
|
CgParameterDefaultValue* defaultIndexTable, unsigned int defaultIndexCount,
|
|
ELF_section_t* consttab );
|
|
|
|
void PopulateDataForParamResource( CgParameterEntry* paramEntry, CgParameterEntry* paramEntries, unsigned int paramEntriesCount,
|
|
unsigned short* paramResourceTable, ELF_section_t* strtab, CgParameterEntry** nextEntry,
|
|
int elementResourceIndex, unsigned int* localParamNo, char* nvBinary,
|
|
CgBinaryParameter** nvParams, char** nvParamStrings,
|
|
CgBinaryEmbeddedConstant** nvParamOffsets, float** nvParamDefaults,
|
|
char* prefix, unsigned int prefixLength,
|
|
CgParameterSemantic* semanticIndexTable, unsigned int semanticIndexCount,
|
|
CgParameterDefaultValue* defaultIndexTable, unsigned int defaultIndexCount,
|
|
ELF_section_t* consttab )
|
|
{
|
|
// type index is actually the offset into the block of memory following the entries
|
|
CgParameterResource* paramResource = ( CgParameterResource* )(( char* )( paramEntries + paramEntriesCount ) + paramEntry->typeIndex );
|
|
|
|
unsigned int rowCount = getMatrixRowCount(( CGtype )paramResource->type );
|
|
|
|
// type
|
|
( *nvParams )->type = ( CGtype )( paramResource->type );
|
|
// sub type for row params of matrix
|
|
for ( int row = 1; row <= ( int )rowCount; row++ )
|
|
( *nvParams + row )->type = getMatrixRowType(( CGtype )paramResource->type );
|
|
|
|
// varying parameters
|
|
if (( paramEntry->flags & CGPV_MASK ) == CGPV_VARYING )
|
|
{
|
|
( *nvParams )->res = ( CGresource )paramResource->resource;
|
|
( *nvParams )->resIndex = -1;
|
|
}
|
|
else if ((( paramEntry->flags & CGPV_MASK ) & CGPV_CONSTANT ) || (( paramEntry->flags & CGPV_MASK ) & CGPV_UNIFORM ) )
|
|
{
|
|
// sampler types
|
|
if ( isSampler(( CGtype )paramResource->type ) )
|
|
{
|
|
( *nvParams )->res = ( CGresource )paramResource->resource; //should be CG_TEXUNIT0 .. 15
|
|
( *nvParams )->resIndex = 0;
|
|
}
|
|
// nonsampler types
|
|
else
|
|
{
|
|
// CG_B requires support too
|
|
for ( int row = 0; row <= ( int )rowCount; row++ )
|
|
{
|
|
if ( paramResource->type == CGP_SCF_BOOL ) //(paramEntry->flags & CGP_SCFBOOL)
|
|
{
|
|
( *nvParams + row )->res = CG_B;
|
|
( *nvParams )->type = CG_BOOL;
|
|
}
|
|
else
|
|
( *nvParams + row )->res = CG_C;
|
|
}
|
|
|
|
// vertex programs
|
|
if (!nvParamOffsets)
|
|
{
|
|
// element of an array
|
|
if ( elementResourceIndex >= 0 )
|
|
{
|
|
if ( !isMatrix(( CGtype )( paramResource->type ) ) )
|
|
{
|
|
unsigned short tempResIndex = *( paramResourceTable + paramResource->resource + elementResourceIndex );
|
|
( *nvParams )->resIndex = ( tempResIndex == 0xFFFF ) ? -1 : ( int )tempResIndex;
|
|
}
|
|
else if ( paramEntry->flags & CGP_CONTIGUOUS )
|
|
{
|
|
unsigned short tempResIndex = *( paramResourceTable + paramResource->resource + elementResourceIndex );
|
|
( *nvParams )->resIndex = ( tempResIndex == 0xFFFF ) ? -1 : ( int )tempResIndex;
|
|
for ( int row = 1; row <= ( int )rowCount; row++ )
|
|
{
|
|
unsigned short tempResIndex = *( paramResourceTable + paramResource->resource + elementResourceIndex ) + row - 1;
|
|
( *nvParams + row )->resIndex = ( tempResIndex == 0xFFFF ) ? -1 : ( int )tempResIndex;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
unsigned short tempResIndex = *( paramResourceTable + paramResource->resource + elementResourceIndex * rowCount );
|
|
( *nvParams )->resIndex = ( tempResIndex == 0xFFFF ) ? -1 : ( int )tempResIndex;
|
|
for ( int row = 1; row <= ( int )rowCount; row++ )
|
|
{
|
|
unsigned short tempResIndex = *( paramResourceTable + paramResource->resource + elementResourceIndex * rowCount + row - 1 );
|
|
( *nvParams + row )->resIndex = ( tempResIndex == 0xFFFF ) ? -1 : ( int )tempResIndex;
|
|
}
|
|
}
|
|
}
|
|
// not array
|
|
else
|
|
{
|
|
if ( !isMatrix(( CGtype )( paramResource->type ) ) )
|
|
{
|
|
unsigned short tempResIndex = paramResource->resource;
|
|
( *nvParams )->resIndex = ( tempResIndex == 0xFFFF ) ? -1 : ( int )tempResIndex;
|
|
}
|
|
else
|
|
{
|
|
if ( paramEntry->flags & CGP_CONTIGUOUS )
|
|
{
|
|
unsigned short tempResIndex = paramResource->resource;
|
|
( *nvParams )->resIndex = ( tempResIndex == 0xFFFF ) ? -1 : ( int )tempResIndex;
|
|
for ( int row = 1; row <= ( int )rowCount; row++ )
|
|
{
|
|
unsigned short tempResIndex = paramResource->resource + row - 1;
|
|
( *nvParams + row )->resIndex = ( tempResIndex == 0xFFFF ) ? -1 : ( int )tempResIndex;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
unsigned short tempResIndex = *( paramResourceTable + paramResource->resource );
|
|
( *nvParams )->resIndex = ( tempResIndex == 0xFFFF ) ? -1 : ( int )tempResIndex;
|
|
for ( int row = 1; row <= ( int )rowCount; row++ )
|
|
{
|
|
unsigned short tempResIndex = *( paramResourceTable + paramResource->resource + row - 1 );
|
|
( *nvParams + row )->resIndex = ( tempResIndex == 0xFFFF ) ? -1 : ( int )tempResIndex;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// fragment programs
|
|
else
|
|
{
|
|
unsigned short* resPtr = paramResourceTable + paramResource->resource;
|
|
|
|
if ( elementResourceIndex >= 0 )
|
|
{
|
|
// !!! matrices should be handled here too, i think
|
|
//advance resPtr to the arrayIndex
|
|
int skipCount = elementResourceIndex;
|
|
while ( skipCount )
|
|
{
|
|
resPtr++;
|
|
int embeddedCount = *( resPtr++ );
|
|
resPtr += embeddedCount;
|
|
// if an array of matrices, must skip row parameter resources too
|
|
for ( int row = 1; row <= ( int )rowCount; row++ )
|
|
{
|
|
resPtr++;
|
|
int embeddedCount = *( resPtr++ );
|
|
resPtr += embeddedCount;
|
|
}
|
|
skipCount--;
|
|
}
|
|
//resPtr points to the resource of the arrayIndex
|
|
}
|
|
|
|
if ( !isMatrix(( CGtype )( paramResource->type ) ) )
|
|
{
|
|
unsigned short tempResIndex = *( resPtr++ );
|
|
( *nvParams )->resIndex = ( tempResIndex == 0xFFFF ) ? -1 : ( int )tempResIndex;
|
|
unsigned int embeddedConstantCount = *( resPtr++ );
|
|
( *nvParamOffsets )->ucodeCount = embeddedConstantCount;
|
|
unsigned int ec = 0;
|
|
for ( ec = 0; ec < embeddedConstantCount; ec++ )
|
|
( *nvParamOffsets )->ucodeOffset[ec] = *( resPtr++ );
|
|
// set the field in the nv param
|
|
( *nvParams )->embeddedConst = ( char* )( *nvParamOffsets ) - nvBinary;
|
|
// forward pointer to nvParamOffsets
|
|
*nvParamOffsets = ( CgBinaryEmbeddedConstant* )( &(( *nvParamOffsets )->ucodeOffset[ec] ) );
|
|
}
|
|
else
|
|
{
|
|
for ( int row = 1; row <= ( int )rowCount; row++ )
|
|
{
|
|
unsigned short tempResIndex = *( resPtr++ );
|
|
( *nvParams + row )->resIndex = ( tempResIndex == 0xFFFF ) ? -1 : ( int )tempResIndex;
|
|
unsigned int embeddedConstantCount = *( resPtr++ );
|
|
( *nvParamOffsets )->ucodeCount = embeddedConstantCount;
|
|
unsigned int ec = 0;
|
|
for ( ec = 0; ec < embeddedConstantCount; ec++ )
|
|
( *nvParamOffsets )->ucodeOffset[ec] = *( resPtr++ );
|
|
// set the field in the nv param
|
|
( *nvParams + row )->embeddedConst = ( char* )( *nvParamOffsets ) - nvBinary;
|
|
// forward pointer to nvParamOffsets
|
|
*nvParamOffsets = ( CgBinaryEmbeddedConstant* )( &(( *nvParamOffsets )->ucodeOffset[ec] ) );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
// RESOURCE DECODING ALGORTITHM END
|
|
|
|
|
|
// name
|
|
if ( paramEntry->nameOffset )
|
|
{
|
|
// copy the name and store its offset in the param
|
|
// i think prefix is already handled for this base case
|
|
strcpy( *nvParamStrings, strtab->data + paramEntry->nameOffset );
|
|
}
|
|
// set the name offset in the param, starting from the prefix
|
|
char* namebase = NULL;
|
|
if ( prefix )
|
|
{
|
|
( *nvParams )->name = prefix - nvBinary;
|
|
namebase = prefix;
|
|
}
|
|
else
|
|
{
|
|
( *nvParams )->name = *nvParamStrings - nvBinary;
|
|
namebase = *nvParamStrings;
|
|
}
|
|
|
|
|
|
// increment the names cursor
|
|
*nvParamStrings += strlen( *nvParamStrings ) + 1;
|
|
|
|
// and now handle the matrix rows
|
|
for ( int row = 1; row <= ( int )rowCount; row++ )
|
|
{
|
|
// copy the name and store its offset in the param
|
|
sprintf( *nvParamStrings, "%s[%d]", namebase, row - 1 );
|
|
// set the name offset in the param
|
|
( *nvParams + row )->name = *nvParamStrings - nvBinary;
|
|
// increment the names cursor
|
|
*nvParamStrings += strlen( *nvParamStrings ) + 1;
|
|
}
|
|
|
|
// totally inefficient, but easiest implementation for now is to do the On^2 search
|
|
// in the semantic and default tables for the data associated with this parameter
|
|
unsigned int entryIndex = paramEntry - paramEntries;
|
|
|
|
// semantic
|
|
char* semantic = NULL;
|
|
for ( unsigned int sem = 0; sem < semanticIndexCount; sem++ )
|
|
{
|
|
CgParameterSemantic* semanticIndex = semanticIndexTable + sem;
|
|
if ( semanticIndex->entryIndex == entryIndex )
|
|
{
|
|
// found the semantic for this parameter
|
|
semantic = strtab->data + semanticIndex->semanticOffset;
|
|
break;
|
|
}
|
|
}
|
|
if ( semantic )
|
|
{
|
|
// copy the name and store its offset in the param
|
|
strcpy( *nvParamStrings, semantic );
|
|
// set the name offset in the param (or params if a matrix)
|
|
for ( int row = 0; row <= ( int )rowCount; row++ )
|
|
( *nvParams )->semantic = *nvParamStrings - nvBinary;
|
|
// increment the names cursor
|
|
*nvParamStrings += strlen( semantic ) + 1;
|
|
}
|
|
|
|
// default
|
|
float* defaults = NULL;
|
|
for ( unsigned int def = 0; def < defaultIndexCount; def++ )
|
|
{
|
|
CgParameterDefaultValue* defaultIndex = defaultIndexTable + def;
|
|
if ( defaultIndex->entryIndex == entryIndex ) // found the default for this parameter
|
|
defaults = ( float* )consttab->data + defaultIndex->defaultValueIndex;
|
|
}
|
|
if ( defaults )
|
|
{
|
|
// defaults are always padded to 4 floats per param
|
|
unsigned int defaultsCount = ( rowCount ? rowCount : 1 ) * 4;
|
|
// copy the values into the right place in the buffer
|
|
memcpy( *nvParamDefaults, defaults, defaultsCount * sizeof( float ) );
|
|
// set the field in the param to point to them
|
|
if ( rowCount == 0 )
|
|
( *nvParams )->defaultValue = ( char* )( *nvParamDefaults ) - nvBinary;
|
|
else
|
|
{
|
|
for ( int row = 1; row <= ( int )rowCount; row++ )
|
|
( *nvParams + row )->defaultValue = ( char* )( *nvParamDefaults + 4 * ( row - 1 ) ) - nvBinary;
|
|
}
|
|
|
|
// forward the buffer pointer
|
|
*nvParamDefaults += defaultsCount;
|
|
}
|
|
|
|
|
|
// fill other fields, once for the matrix and once for every row
|
|
for ( int row = 0; row <= ( int )rowCount; row++ )
|
|
{
|
|
// var
|
|
unsigned int variability = paramEntry->flags & CGPV_MASK;
|
|
if ( variability == CGPV_VARYING )
|
|
( *nvParams )->var = CG_VARYING;
|
|
else if ( variability == CGPV_UNIFORM )
|
|
( *nvParams )->var = CG_UNIFORM;
|
|
else if ( variability == CGPV_CONSTANT )
|
|
( *nvParams )->var = CG_CONSTANT;
|
|
else if ( variability == CGPV_MIXED )
|
|
( *nvParams )->var = CG_MIXED;
|
|
else
|
|
( *nvParams )->var = ( CGenum )0;
|
|
|
|
//direction
|
|
unsigned int direction = paramEntry->flags & CGPD_MASK;
|
|
if ( direction == CGPD_IN )
|
|
( *nvParams )->direction = CG_IN;
|
|
else if ( direction == CGPD_OUT )
|
|
( *nvParams )->direction = CG_OUT;
|
|
else if ( direction == CGPD_INOUT )
|
|
( *nvParams )->direction = CG_INOUT;
|
|
else
|
|
( *nvParams )->direction = ( CGenum )0;
|
|
|
|
// paramno
|
|
if ( paramEntry->flags & CGPF_GLOBAL )
|
|
( *nvParams )->paramno = -1;
|
|
else if ( paramEntry->flags & CGP_INTERNAL )
|
|
( *nvParams )->paramno = -2;
|
|
else
|
|
{
|
|
( *nvParams )->paramno = *localParamNo;
|
|
if ( row == 0 )
|
|
*localParamNo += 1;
|
|
}
|
|
|
|
// isReferenced
|
|
( *nvParams )->isReferenced = (( paramEntry->flags & CGPF_REFERENCED ) != 0 );
|
|
|
|
// isShared
|
|
( *nvParams )->isShared = false;
|
|
|
|
|
|
// increment param cursor
|
|
*nvParams += 1;
|
|
|
|
|
|
}
|
|
|
|
// entry cursor
|
|
*nextEntry = paramEntry + 1;
|
|
|
|
}
|
|
|
|
void PopulateDataForParamArray( CgParameterEntry* paramEntry, CgParameterEntry* paramEntries, unsigned int paramEntriesCount,
|
|
unsigned short* paramResourceTable, ELF_section_t* strtab, CgParameterEntry** nextEntry,
|
|
int elementResourceIndex, unsigned int* localParamNo, char* nvBinary,
|
|
CgBinaryParameter** nvParams, char** nvParamStrings,
|
|
CgBinaryEmbeddedConstant** nvParamOffsets, float** nvParamDefaults,
|
|
char* prefix, unsigned int prefixLength,
|
|
CgParameterSemantic* semanticIndexTable, unsigned int semanticIndexCount,
|
|
CgParameterDefaultValue* defaultIndexTable, unsigned int defaultIndexCount,
|
|
ELF_section_t* consttab )
|
|
{
|
|
// type index is actually the offset into the block of memory following the entries
|
|
CgParameterArray* paramArray = ( CgParameterArray* )(( char* )( paramEntries + paramEntriesCount ) + paramEntry->typeIndex );
|
|
|
|
// this would give the number of intrinsics OR structs, but if base type is struct
|
|
// to get the number of parameters, must recurse over struct fields
|
|
unsigned int numElements = 1;
|
|
for ( unsigned int dim = 0; dim < paramArray->dimensionCount; dim++ )
|
|
numElements *= paramArray->dimensions[dim];
|
|
|
|
// for name handling
|
|
char* prefixIn = prefix;
|
|
unsigned int prefixLengthIn = prefixLength;
|
|
|
|
if ( !( paramEntry->flags & CGP_UNROLLED ) ) // one bit is not enough cause there are 3 representations!
|
|
{
|
|
// all elements are the same so have one entry to represent all of them
|
|
CgParameterEntry* elementEntry = paramEntry + 1;
|
|
|
|
// entries are same type, and packed, so just repeat same param
|
|
for ( unsigned int element = 0; element < numElements; element++ )
|
|
{
|
|
// where is the array name??? in paramEntry or elementEntry???
|
|
|
|
// name
|
|
// copy prefix if it's not the first element whose prefix is already in place
|
|
if ( element > 0 )
|
|
{
|
|
strncpy( *nvParamStrings, prefixIn, prefixLengthIn );
|
|
prefix = *nvParamStrings;
|
|
*nvParamStrings += prefixLengthIn;
|
|
}
|
|
// rest of array name for array and index
|
|
sprintf( *nvParamStrings, "%s[%d]", ( strtab->data + paramEntry->nameOffset ), element );
|
|
|
|
if (!prefix)
|
|
prefix = *nvParamStrings;
|
|
|
|
*nvParamStrings += strlen( *nvParamStrings );
|
|
|
|
prefixLength = strlen( prefix );
|
|
|
|
PopulateDataForParamResource( elementEntry, paramEntries, paramEntriesCount,
|
|
paramResourceTable, strtab, nextEntry,
|
|
element, localParamNo, nvBinary,
|
|
nvParams, nvParamStrings, nvParamOffsets, nvParamDefaults,
|
|
prefix, prefixLength,
|
|
semanticIndexTable, semanticIndexCount,
|
|
defaultIndexTable, defaultIndexCount,
|
|
consttab );
|
|
|
|
*nextEntry = *nextEntry - 1; // undo the increment on the next entry for this special case of shared entries
|
|
}
|
|
*nextEntry = *nextEntry + 1; // redo the increment on the next entry upon leaving the loop
|
|
}
|
|
else if ( paramEntry->flags & CGP_UNROLLED )
|
|
{
|
|
// here everything is unrolled
|
|
|
|
CgParameterEntry* elementEntry = paramEntry + 1;
|
|
|
|
for ( unsigned int element = 0; element < numElements; element++ )
|
|
{
|
|
// where is the array name??? in paramEntry or elementEntry???
|
|
|
|
// name
|
|
// copy prefix if it's not the first element whose prefix is already in place
|
|
if ( element > 0 )
|
|
{
|
|
strncpy( *nvParamStrings, prefixIn, prefixLengthIn );
|
|
prefix = *nvParamStrings;
|
|
*nvParamStrings += prefixLengthIn;
|
|
}
|
|
// rest of array name for array and index
|
|
sprintf( *nvParamStrings, "%s[%d]", ( strtab->data + paramEntry->nameOffset ), element );
|
|
*nvParamStrings += strlen( *nvParamStrings );
|
|
prefixLength = strlen( prefix );
|
|
|
|
PopulateDataForParams( elementEntry, paramEntries, paramEntriesCount,
|
|
paramResourceTable, strtab, nextEntry,
|
|
-1, localParamNo, nvBinary,
|
|
nvParams, nvParamStrings, nvParamOffsets, nvParamDefaults,
|
|
prefix, prefixLength,
|
|
semanticIndexTable, semanticIndexCount,
|
|
defaultIndexTable, defaultIndexCount,
|
|
consttab );
|
|
|
|
elementEntry = *nextEntry;
|
|
}
|
|
}
|
|
}
|
|
|
|
void PopulateDataForParamStruct( CgParameterEntry* paramEntry, CgParameterEntry* paramEntries, unsigned int paramEntriesCount,
|
|
unsigned short* paramResourceTable, ELF_section_t* strtab, CgParameterEntry** nextEntry,
|
|
int elementResourceIndex, unsigned int* localParamNo, char* nvBinary,
|
|
CgBinaryParameter** nvParams, char** nvParamStrings,
|
|
CgBinaryEmbeddedConstant** nvParamOffsets, float** nvParamDefaults,
|
|
char* prefix, unsigned int prefixLength,
|
|
CgParameterSemantic* semanticIndexTable, unsigned int semanticIndexCount,
|
|
CgParameterDefaultValue* defaultIndexTable, unsigned int defaultIndexCount,
|
|
ELF_section_t* consttab )
|
|
{
|
|
// type index is actually the offset into the block of memory following the entries
|
|
CgParameterStructure* paramStruct = ( CgParameterStructure* )(( char* )( paramEntries + paramEntriesCount ) + paramEntry->typeIndex );
|
|
|
|
unsigned short memberCount = paramStruct->memberCount;
|
|
CgParameterEntry* memberEntry = paramEntry + 1;
|
|
|
|
// set the prefix pointer if it is not already set
|
|
if (!prefix)
|
|
prefix = *nvParamStrings;
|
|
|
|
// add prefix of struct name and .
|
|
// !!! but what about if we are inside an array??? then no struct name? or is . built in?
|
|
if ( paramEntry->nameOffset > 0 ) // is this the right test???
|
|
{
|
|
// name
|
|
unsigned int nameLength = strlen( strtab->data + paramEntry->nameOffset );
|
|
// copy the name and store its offset in the param
|
|
strcpy( *nvParamStrings, strtab->data + paramEntry->nameOffset );
|
|
|
|
// increment the names cursor but don't include null term
|
|
*nvParamStrings += nameLength;
|
|
prefixLength += nameLength;
|
|
}
|
|
|
|
// add the dot
|
|
strcpy( *nvParamStrings, "." );
|
|
*nvParamStrings += 1;
|
|
prefixLength += 1;
|
|
|
|
for ( unsigned int member = 0; member < memberCount; member++ )
|
|
{
|
|
// put the prefix in place for each subsequent member
|
|
if ( member > 0 )
|
|
{
|
|
strncpy( *nvParamStrings, prefix, prefixLength );
|
|
prefix = *nvParamStrings;
|
|
*nvParamStrings += prefixLength;
|
|
}
|
|
|
|
PopulateDataForParams( memberEntry, paramEntries, paramEntriesCount,
|
|
paramResourceTable, strtab, nextEntry,
|
|
-1, localParamNo, nvBinary,
|
|
nvParams, nvParamStrings, nvParamOffsets, nvParamDefaults,
|
|
prefix, prefixLength,
|
|
semanticIndexTable, semanticIndexCount,
|
|
defaultIndexTable, defaultIndexCount,
|
|
consttab );
|
|
|
|
memberEntry = *nextEntry;
|
|
}
|
|
}
|
|
|
|
void PopulateDataForParams( CgParameterEntry* paramEntry, CgParameterEntry* paramEntries, unsigned int paramEntriesCount,
|
|
unsigned short* paramResourceTable, ELF_section_t* strtab, CgParameterEntry** nextEntry,
|
|
int elementResourceIndex, unsigned int* localParamNo, char* nvBinary,
|
|
CgBinaryParameter** nvParams, char** nvParamStrings,
|
|
CgBinaryEmbeddedConstant** nvParamOffsets, float** nvParamDefaults,
|
|
char* prefix, unsigned int prefixLength,
|
|
CgParameterSemantic* semanticIndexTable, unsigned int semanticIndexCount,
|
|
CgParameterDefaultValue* defaultIndexTable, unsigned int defaultIndexCount,
|
|
ELF_section_t* consttab )
|
|
{
|
|
|
|
// expand for intrinsics, arrays, and structs
|
|
// flags hold which type of parameter it is (along with other information)
|
|
switch ( paramEntry->flags & CGP_TYPE_MASK )
|
|
{
|
|
case CGP_INTRINSIC:
|
|
{
|
|
//printf("resource --- %p\n", paramEntry);
|
|
PopulateDataForParamResource( paramEntry, paramEntries, paramEntriesCount,
|
|
paramResourceTable, strtab, nextEntry,
|
|
elementResourceIndex, localParamNo, nvBinary,
|
|
nvParams, nvParamStrings, nvParamOffsets, nvParamDefaults,
|
|
prefix, prefixLength,
|
|
semanticIndexTable, semanticIndexCount,
|
|
defaultIndexTable, defaultIndexCount,
|
|
consttab );
|
|
break;
|
|
}
|
|
case CGP_ARRAY:
|
|
{
|
|
//printf("array --- %p\n", paramEntry);
|
|
PopulateDataForParamArray( paramEntry, paramEntries, paramEntriesCount,
|
|
paramResourceTable, strtab, nextEntry,
|
|
elementResourceIndex, localParamNo, nvBinary,
|
|
nvParams, nvParamStrings, nvParamOffsets, nvParamDefaults,
|
|
prefix, prefixLength,
|
|
semanticIndexTable, semanticIndexCount,
|
|
defaultIndexTable, defaultIndexCount,
|
|
consttab );
|
|
break;
|
|
}
|
|
case CGP_STRUCTURE:
|
|
{
|
|
//printf("structure --- %p\n", paramEntry);
|
|
PopulateDataForParamStruct( paramEntry, paramEntries, paramEntriesCount,
|
|
paramResourceTable, strtab, nextEntry,
|
|
elementResourceIndex, localParamNo, nvBinary,
|
|
nvParams, nvParamStrings, nvParamOffsets, nvParamDefaults,
|
|
prefix, prefixLength,
|
|
semanticIndexTable, semanticIndexCount,
|
|
defaultIndexTable, defaultIndexCount,
|
|
consttab );
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
break;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
bool rglCgCreateProgramChecks( CGcontext ctx, CGprofile profile, CGenum program_type )
|
|
{
|
|
// check context
|
|
if ( !CG_IS_CONTEXT( ctx ) )
|
|
{
|
|
rglCgRaiseError( CG_INVALID_CONTEXT_HANDLE_ERROR );
|
|
return false;
|
|
}
|
|
|
|
// check the profile.
|
|
switch ( profile )
|
|
{
|
|
case CG_PROFILE_SCE_VP_RSX:
|
|
case CG_PROFILE_SCE_FP_RSX:
|
|
break;
|
|
default:
|
|
rglCgRaiseError( CG_UNKNOWN_PROFILE_ERROR );
|
|
return false;
|
|
}
|
|
|
|
// check the program_type
|
|
switch ( program_type )
|
|
{
|
|
case CG_BINARY:
|
|
case CG_SOURCE:
|
|
break;
|
|
default: // currently reject CG_OBJECT (assembly code in ASCII) and CG_UNDEFINED
|
|
rglCgRaiseError( CG_INVALID_ENUMERANT_ERROR );
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool cgOpenElf( const void *ptr, size_t size, CGELFBinary *elfBinary )
|
|
{
|
|
while ( 1 )
|
|
{
|
|
size_t symbolSize;
|
|
size_t symbolCount;
|
|
const char *symbolstrtab;
|
|
const char *symtab = findSymbolSectionInPlace((const char *)ptr, &symbolSize, &symbolCount, &symbolstrtab );
|
|
if ( !symtab )
|
|
break;
|
|
|
|
size_t shadertabSize;
|
|
const char *shadertab = findSectionInPlace((const char*)ptr, ".shadertab", &shadertabSize );
|
|
if ( !shadertab )
|
|
break;
|
|
size_t strtabSize;
|
|
const char *strtab = findSectionInPlace((const char*)ptr, ".strtab", &strtabSize );
|
|
if ( !strtab )
|
|
break;
|
|
size_t consttabSize;
|
|
const char *consttab = findSectionInPlace((const char* )ptr, ".const", &consttabSize );
|
|
if ( !consttab )
|
|
break;
|
|
|
|
elfBinary->elfFile = ( const char* )ptr;
|
|
elfBinary->elfFileSize = size;
|
|
elfBinary->symtab = symtab;
|
|
elfBinary->symbolSize = symbolSize;
|
|
elfBinary->symbolCount = symbolCount;
|
|
elfBinary->symbolstrtab = symbolstrtab;
|
|
|
|
elfBinary->shadertab = shadertab;
|
|
elfBinary->shadertabSize = shadertabSize;
|
|
elfBinary->strtab = strtab;
|
|
elfBinary->strtabSize = strtabSize;
|
|
|
|
elfBinary->consttab = consttab;
|
|
elfBinary->consttabSize = consttabSize;
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool cgGetElfProgramByIndex( CGELFBinary *elfBinary, int index, CGELFProgram *elfProgram )
|
|
{
|
|
while ( true )
|
|
{
|
|
char sectionName[64];
|
|
sprintf( sectionName, ".text%04i", index );
|
|
size_t texttabSize;
|
|
const char *texttab = findSectionInPlace( elfBinary->elfFile, sectionName, &texttabSize );
|
|
if ( !texttab )
|
|
break;
|
|
sprintf( sectionName, ".paramtab%04i", index );
|
|
size_t paramtabSize;
|
|
const char *paramtab = findSectionInPlace( elfBinary->elfFile, sectionName, ¶mtabSize );
|
|
if ( !paramtab )
|
|
break;
|
|
|
|
elfProgram->texttab = texttab;
|
|
elfProgram->texttabSize = texttabSize;
|
|
elfProgram->paramtab = paramtab;
|
|
elfProgram->paramtabSize = paramtabSize;
|
|
elfProgram->index = index;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static bool cgGetElfProgramByName( CGELFBinary *elfBinary, const char *name, CGELFProgram *elfProgram )
|
|
{
|
|
//if no name try to return the first program
|
|
int res;
|
|
if (!name || name[0] == '\0' )
|
|
res = 0;
|
|
else
|
|
res = lookupSymbolValueInPlace( elfBinary->symtab, elfBinary->symbolSize, elfBinary->symbolCount, elfBinary->symbolstrtab, name );
|
|
|
|
if ( res != -1 )
|
|
return cgGetElfProgramByIndex( elfBinary, res, elfProgram );
|
|
else
|
|
return false;
|
|
}
|
|
|
|
CGprogram rglCgCreateProgram( CGcontext ctx, CGprofile profile, const CgProgramHeader *programHeader, const void *ucode, const CgParameterTableHeader *parameterHeader, const char *stringTable, const float *defaultValues )
|
|
{
|
|
// Create the program structure.
|
|
// all the structural data is filled in here,
|
|
// as well as the profile.
|
|
// The parameters and the actual program are generated from the ABI specific calls.
|
|
|
|
_CGprogram* prog = ( _CGprogram* )malloc( sizeof( _CGprogram ) );
|
|
if ( NULL == prog )
|
|
{
|
|
rglCgRaiseError( CG_MEMORY_ALLOC_ERROR );
|
|
return NULL;
|
|
}
|
|
|
|
// zero out the fields
|
|
memset( prog, 0, sizeof( _CGprogram ) );
|
|
|
|
// fill in the fields we know
|
|
prog->parentContext = _cgGetContextPtr( ctx );
|
|
prog->header.profile = profile;
|
|
|
|
int success = 0;
|
|
|
|
// create a name for the program and record it in the object
|
|
CGprogram id = ( CGprogram )rglCreateName( &_CurrentContext->cgProgramNameSpace, prog );
|
|
if ( !id )
|
|
{
|
|
free( prog );
|
|
rglCgRaiseError( CG_MEMORY_ALLOC_ERROR );
|
|
return NULL;
|
|
}
|
|
prog->id = id;
|
|
|
|
//hack to counter removal of TypeC during beta
|
|
if ( profile == ( CGprofile )7005 )
|
|
profile = CG_PROFILE_SCE_VP_RSX;
|
|
if ( profile == ( CGprofile )7006 )
|
|
profile = CG_PROFILE_SCE_FP_RSX;
|
|
|
|
// load the binary into the program object
|
|
switch ( profile )
|
|
{
|
|
case CG_PROFILE_SCE_VP_RSX:
|
|
// TODO ************** need to include the entry symbol too
|
|
success = rglpGenerateVertexProgram( prog, programHeader, ucode, parameterHeader, stringTable, defaultValues );
|
|
break;
|
|
case CG_PROFILE_SCE_FP_RSX:
|
|
success = rglpGenerateFragmentProgram( prog, programHeader, ucode, parameterHeader, stringTable, defaultValues );
|
|
break;
|
|
default:
|
|
// should never reach here
|
|
break;
|
|
}
|
|
|
|
// if the creation failed, free all resources.
|
|
// the error was raised when the error was encoutered.
|
|
if ( success == 0 )
|
|
{
|
|
// free the program object
|
|
free( prog );
|
|
// release the id too
|
|
rglEraseName( &_CurrentContext->cgProgramNameSpace, (unsigned int)id );
|
|
return NULL;
|
|
}
|
|
|
|
// success! add the program to the program list in the context.
|
|
rglCgProgramPushFront( prog->parentContext, prog );
|
|
if ( _cgProgramCreateHook ) _cgProgramCreateHook( prog );
|
|
|
|
// everything worked.
|
|
return id;
|
|
}
|
|
|
|
CG_API CGprogram cgCreateProgram( CGcontext ctx,
|
|
CGenum program_type,
|
|
const char* program,
|
|
CGprofile profile,
|
|
const char* entry,
|
|
const char** args )
|
|
{
|
|
// Load a program from a memory pointer.
|
|
// NOTE: in our API all programs are pre-compiled binaries
|
|
// so entry point and compiler arguments are ignored.
|
|
|
|
//hack to counter removal of TypeC during beta
|
|
if ( profile == ( CGprofile )7005 )
|
|
profile = CG_PROFILE_SCE_VP_RSX;
|
|
if ( profile == ( CGprofile )7006 )
|
|
profile = CG_PROFILE_SCE_FP_RSX;
|
|
|
|
//hack to counter change of defines for program_type at r5294
|
|
// previously CG_BINARY was defined the same as CG_ROW_MAJOR
|
|
// if those values are passed in here, move them to the new values and remove this hack after we have
|
|
// an sdk that incorporates these changes so that prebuild libs (aka debugfont) can be used meanwhile
|
|
if ( program_type == CG_ROW_MAJOR )
|
|
program_type = CG_BINARY;
|
|
|
|
if ( !rglCgCreateProgramChecks( ctx, profile, program_type ) )
|
|
return NULL;
|
|
|
|
//data to extract from the buffer passed:
|
|
CgProgramHeader *programHeader = NULL;
|
|
const void *ucode = NULL;
|
|
CgParameterTableHeader *parameterHeader = NULL;
|
|
const char *stringTable = NULL;
|
|
const float *defaultValues = NULL;
|
|
|
|
//first step, compile any source file
|
|
const char *binaryBuffer = NULL;
|
|
char* compiled_program = NULL;
|
|
if ( program_type == CG_SOURCE )
|
|
{
|
|
if ( _cgRTCgcCompileProgramHook )
|
|
{
|
|
_cgRTCgcCompileProgramHook( program, (profile == CG_PROFILE_SCE_FP_RSX) ? "sce_fp_rsx" : "sce_vp_rsx", entry, args, &compiled_program );
|
|
if ( !compiled_program )
|
|
{
|
|
rglCgRaiseError( CG_COMPILER_ERROR );
|
|
return NULL;
|
|
}
|
|
binaryBuffer = compiled_program;
|
|
}
|
|
else
|
|
{
|
|
//_RGL_REPORT_EXTRA( RGL_REPORT_CG_ERROR, "The CG runtime compiler hasn't been setup. cgRTCgcInit() should be called prior to this function." );
|
|
rglCgRaiseError( CG_INVALID_ENUMERANT_ERROR );
|
|
return NULL;
|
|
}
|
|
}
|
|
else
|
|
binaryBuffer = program;
|
|
|
|
bool bConvertedToElf = false;
|
|
|
|
//At that point we have a binary file which is either any ELF or an NV format file
|
|
const unsigned int ElfTag = 0x7F454C46; // == MAKEFOURCC(0x7F,'E','L','F');
|
|
if ( !( *( unsigned int* )binaryBuffer == ElfTag ) )
|
|
{
|
|
//we have an NV file, convert it to the runtime format
|
|
|
|
// if it was initially binary, throw warning about old format and recommend conversion to new with cgnv2elf
|
|
// don't throw the warning if it was source, cause clearly that would have been on purpose.
|
|
if ( program_type == CG_BINARY )
|
|
{
|
|
//_RGL_REPORT_EXTRA( RGL_REPORT_CG_ERROR, "A binary shader is being loaded using a deprecated binary format. Please use the cgnv2elf tool to convert to the new, memory-saving, faster-loading format." );
|
|
}
|
|
|
|
//convert from NV format to the runtime format
|
|
int compiled_program_size = 0;
|
|
std::vector<char> stringTableArray;
|
|
std::vector<float> defaultValuesArray;
|
|
CgBinaryProgram* nvProgram = ( CgBinaryProgram* )binaryBuffer;
|
|
char *runtimeElfShader = NULL;
|
|
//check the endianness
|
|
int totalSize;
|
|
|
|
if (( nvProgram->profile != ( CGprofile )7006 ) && ( nvProgram->profile != ( CGprofile )7005 ) &&
|
|
( nvProgram->profile != CG_PROFILE_SCE_FP_RSX ) && ( nvProgram->profile != CG_PROFILE_SCE_VP_RSX ) )
|
|
totalSize = endianSwapWord( nvProgram->totalSize );
|
|
else
|
|
totalSize = nvProgram->totalSize;
|
|
|
|
int res = convertNvToElfFromMemory( binaryBuffer, totalSize, 2, 0, ( void** ) & runtimeElfShader, &compiled_program_size, stringTableArray, defaultValuesArray );
|
|
if (res != 0)
|
|
{
|
|
//_RGL_REPORT_EXTRA( RGL_REPORT_CG_ERROR, "invalid CG binary program" );
|
|
rglCgRaiseError( CG_COMPILER_ERROR );
|
|
if ( compiled_program )
|
|
_cgRTCgcFreeCompiledProgramHook( compiled_program );
|
|
return NULL;
|
|
}
|
|
|
|
if ( compiled_program )
|
|
_cgRTCgcFreeCompiledProgramHook( compiled_program );
|
|
|
|
//TODO: remove all the unnecessary data shuffling, when this gets included in the compiler
|
|
//prepare the same buffer as the one that would be extracted from the binary file
|
|
size_t stringTableSize = stringTableArray.size() * sizeof( stringTable[0] );
|
|
size_t defaultTableSize = defaultValuesArray.size() * sizeof( defaultValues[0] );
|
|
int paddedSize = rglPad( compiled_program_size, 4 );
|
|
//the following pointer will be remembered in the _CGprogram structure to be freed when the
|
|
//program will be deleted, the ucode and the param info are used in place at runtime
|
|
char *runtimeElf = ( char* )memalign( 16, paddedSize + stringTableSize + defaultTableSize );
|
|
if ( !runtimeElf )
|
|
{
|
|
rglCgRaiseError( CG_MEMORY_ALLOC_ERROR );
|
|
return NULL;
|
|
}
|
|
bConvertedToElf = true; //to free the memalign
|
|
//program header, ucode and parameters
|
|
memcpy( runtimeElf, runtimeElfShader, compiled_program_size );
|
|
|
|
//we can free the intermediate buffer used to receive the converted program //may be we should keep it rather than reallocating ?
|
|
convertNvToElfFreeBinaryShader( runtimeElfShader );
|
|
|
|
//default values
|
|
//the pointer is stored right after the program data ( padded to 4 ) and after the string table pointer
|
|
float* pDefaultValues = ( float* )(( char* )runtimeElf + paddedSize );
|
|
defaultValues = pDefaultValues;
|
|
|
|
if ( defaultTableSize )
|
|
memcpy( pDefaultValues, &defaultValuesArray[0], defaultTableSize );
|
|
|
|
//string table
|
|
//the pointer is stored right after the program data ( padded to 4 )
|
|
char *pStringTable = ( char* )runtimeElf + paddedSize + defaultTableSize;
|
|
stringTable = pStringTable;
|
|
|
|
if ( stringTableSize )
|
|
memcpy( pStringTable, &stringTableArray[0], stringTableSize );
|
|
|
|
|
|
//success
|
|
programHeader = ( CgProgramHeader* )runtimeElf;
|
|
size_t elfUcodeSize = programHeader->instructionCount * 16;
|
|
size_t ucodeOffset = rglPad( sizeof( CgProgramHeader ), 16 );
|
|
size_t parameterOffset = rglPad( ucodeOffset + elfUcodeSize, 16 );
|
|
ucode = ( char* )runtimeElf + ucodeOffset;
|
|
parameterHeader = ( CgParameterTableHeader* )(( char* )runtimeElf + parameterOffset );
|
|
}
|
|
else
|
|
{
|
|
//we have an ELF file, it will be used in place ( case where the elf file has been passed as a memory pointer )
|
|
CGELFBinary elfBinary;
|
|
CGELFProgram elfProgram;
|
|
|
|
/* CG binary not aligned to 16 bytes, needed for ucode section */
|
|
if ((( intptr_t )binaryBuffer ) & 15 )
|
|
{
|
|
rglCgRaiseError( CG_PROGRAM_LOAD_ERROR );
|
|
return NULL;
|
|
}
|
|
bool res = cgOpenElf( binaryBuffer, 0, &elfBinary );
|
|
|
|
/* Not a valid ELF file */;
|
|
if ( !res )
|
|
{
|
|
rglCgRaiseError( CG_PROGRAM_LOAD_ERROR );
|
|
return NULL;
|
|
}
|
|
|
|
/* Couldn't find the shader entry in the CG binary */
|
|
if ( !cgGetElfProgramByName( &elfBinary, entry, &elfProgram ) )
|
|
return NULL;
|
|
|
|
programHeader = ( CgProgramHeader* )elfBinary.shadertab + elfProgram.index;
|
|
ucode = ( char* )elfProgram.texttab;
|
|
parameterHeader = ( CgParameterTableHeader* )elfProgram.paramtab;
|
|
stringTable = elfBinary.strtab;
|
|
defaultValues = ( float* )elfBinary.consttab;
|
|
}
|
|
|
|
CGprogram prog = rglCgCreateProgram( ctx, profile, programHeader, ucode, parameterHeader, stringTable, defaultValues );
|
|
|
|
//if we used the runtime compiler/converter we need to delete the buffer on exit
|
|
if ( bConvertedToElf )
|
|
{
|
|
_CGprogram* ptr = _cgGetProgPtr( prog );
|
|
ptr->runtimeElf = programHeader;
|
|
}
|
|
|
|
return prog;
|
|
}
|
|
|
|
CG_API CGprogram cgCreateProgramFromFile( CGcontext ctx,
|
|
CGenum program_type,
|
|
const char* program_file,
|
|
CGprofile profile,
|
|
const char* entry,
|
|
const char** args )
|
|
{
|
|
//hack to counter removal of TypeC during beta
|
|
if ( profile == ( CGprofile )7005 )
|
|
profile = CG_PROFILE_SCE_VP_RSX;
|
|
if ( profile == ( CGprofile )7006 )
|
|
profile = CG_PROFILE_SCE_FP_RSX;
|
|
|
|
//hack to counter change of defines for program_type at r5294
|
|
// previously CG_BINARY was defined the same as CG_ROW_MAJOR
|
|
// if those values are passed in here, move them to the new values and remove this hack after we have
|
|
// an sdk that incorporates these changes so that prebuild libs (aka debugfont) can be used meanwhile
|
|
if ( program_type == CG_ROW_MAJOR )
|
|
program_type = CG_BINARY;
|
|
|
|
if ( !rglCgCreateProgramChecks( ctx, profile, program_type ) )
|
|
return NULL;
|
|
|
|
// load a program from a file
|
|
// NOTE: in our API all programs are pre-compiled binaries
|
|
// so profile and compiler arguments are ignored.
|
|
FILE* fp = NULL;
|
|
if ( RGL_LIKELY( program_type == CG_BINARY ) )
|
|
{
|
|
CGprogram ret = NULL;
|
|
|
|
_CGcontext *context = _cgGetContextPtr( ctx );
|
|
CGprogramGroup group = NULL;
|
|
|
|
//can we find it in the groups already loaded ?
|
|
group = context->groupList;
|
|
while ( group )
|
|
{
|
|
//check the group name
|
|
const char *groupName = rglCgGetProgramGroupName( group );
|
|
if ( groupName && !strcmp( groupName, program_file ) )
|
|
{
|
|
int index;
|
|
if (!entry)
|
|
index = 0;
|
|
else
|
|
index = rglCgGetProgramIndex( group, entry );
|
|
if ( index >= 0 )
|
|
{
|
|
ret = rglpCgUpdateProgramAtIndex( group, index, 1 );
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
//we couldn't find the entry in the group which has the right name
|
|
return ( CGprogram )NULL;
|
|
}
|
|
}
|
|
group = group->next;
|
|
}
|
|
|
|
if ( ret )
|
|
return ret;
|
|
else
|
|
{
|
|
//do we have an elf file ?
|
|
//read file tag:
|
|
// check that file exists
|
|
fp = fopen( program_file, "rb" );
|
|
|
|
if (!fp)
|
|
return ( CGprogram )NULL;
|
|
|
|
unsigned int filetag = 0;
|
|
int res = fread( &filetag, sizeof( filetag ), 1, fp );
|
|
if ( !res )
|
|
{
|
|
fclose( fp );
|
|
rglCgRaiseError( CG_FILE_READ_ERROR );
|
|
return ( CGprogram )NULL;
|
|
}
|
|
const unsigned int ElfTag = 0x7F454C46; // == MAKEFOURCC(0x7F,'E','L','F');
|
|
if ( filetag == ElfTag )
|
|
{
|
|
fclose( fp );
|
|
|
|
group = rglCgCreateProgramGroupFromFile( ctx, program_file );
|
|
if ( group )
|
|
{
|
|
_CGprogramGroup *_group = ( _CGprogramGroup * )group;
|
|
_group->userCreated = false;
|
|
if (!entry)
|
|
{
|
|
if ( group->programCount == 1 )
|
|
{
|
|
ret = rglpCgUpdateProgramAtIndex( group, 0, 1 );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int index = rglCgGetProgramIndex( group, entry );
|
|
if ( index == -1 )
|
|
{
|
|
//_RGL_REPORT_EXTRA( RGL_REPORT_CG_ERROR, "couldn't find the shader entry in the CG binary" );
|
|
}
|
|
else
|
|
{
|
|
ret = rglpCgUpdateProgramAtIndex( group, index, 1 );
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
}
|
|
}
|
|
|
|
//we have a NV file or a CG source:
|
|
if ( !fp )
|
|
{
|
|
fp = fopen( program_file, "rb" );
|
|
if (!fp)
|
|
return ( CGprogram )NULL;
|
|
}
|
|
|
|
// find the file length
|
|
size_t file_size = 0;
|
|
fseek( fp, 0, SEEK_END );
|
|
file_size = ftell( fp );
|
|
rewind( fp );
|
|
|
|
// alloc memory for the file
|
|
char* ptr = ( char* )malloc( file_size + 1 );
|
|
if (!ptr)
|
|
{
|
|
fclose(fp);
|
|
return (CGprogram)NULL;
|
|
}
|
|
|
|
// read the entire file into memory then close the file
|
|
// TODO ********* just loading the file is a bit lame really. We can do better.
|
|
fread( ptr, file_size, 1, fp );
|
|
fclose( fp );
|
|
|
|
if ( program_type == CG_SOURCE )
|
|
{
|
|
ptr[file_size] = '\0';
|
|
}
|
|
|
|
// call the CreateProgram API to do the rest of the job.
|
|
CGprogram ret = cgCreateProgram( ctx, program_type, ptr, profile, entry, args );
|
|
|
|
// free the memory for the file, we're done with it
|
|
free( ptr );
|
|
|
|
return ret;
|
|
}
|
|
|
|
CG_API CGprogram cgCopyProgram( CGprogram program )
|
|
{
|
|
// check input parameter
|
|
|
|
if ( !CG_IS_PROGRAM( program ) )
|
|
return NULL;
|
|
|
|
_CGprogram* prog = _cgGetProgPtr( program );
|
|
if (!prog)
|
|
return ( CGprogram )NULL;
|
|
|
|
_CGprogram* newprog;
|
|
size_t paddedProgramSize = 0;
|
|
size_t ucodeSize = 0;
|
|
|
|
if (prog->header.profile == CG_PROFILE_SCE_FP_RSX)
|
|
{
|
|
paddedProgramSize = rglPad( sizeof( _CGprogram ), 16);
|
|
ucodeSize = prog->header.instructionCount * 16;
|
|
newprog = ( _CGprogram* )malloc( paddedProgramSize + ucodeSize );
|
|
}
|
|
else
|
|
{
|
|
newprog = ( _CGprogram* )malloc( sizeof( _CGprogram ) );
|
|
}
|
|
|
|
if ( NULL == newprog )
|
|
{
|
|
rglCgRaiseError( CG_MEMORY_ALLOC_ERROR );
|
|
return ( CGprogram )NULL;
|
|
}
|
|
memset( newprog, 0, sizeof( _CGprogram ) );
|
|
|
|
// copy information from the old program
|
|
newprog->header.profile = prog->header.profile;
|
|
newprog->parentContext = prog->parentContext;
|
|
|
|
// generate a new id
|
|
newprog->id = ( CGprogram )rglCreateName( &_CurrentContext->cgProgramNameSpace, newprog );
|
|
|
|
// copy all the parameter information
|
|
|
|
|
|
// copy the binary program information
|
|
// TODO ******** copy the entire elf here, not just the executable.
|
|
int success = 0;
|
|
switch ( prog->header.profile )
|
|
{
|
|
case CG_PROFILE_SCE_VP_RSX:
|
|
case CG_PROFILE_SCE_FP_RSX:
|
|
success = rglpCopyProgram( prog, newprog );
|
|
break;
|
|
default:
|
|
rglCgRaiseError( CG_UNKNOWN_PROFILE_ERROR );
|
|
success = 0;
|
|
break;
|
|
}
|
|
|
|
if ( success == 0 )
|
|
{
|
|
// we failed to create a new program object, clean up
|
|
free( newprog );
|
|
rglEraseName( &_CurrentContext->cgProgramNameSpace, (unsigned int)newprog->id );
|
|
return ( CGprogram )NULL;
|
|
}
|
|
|
|
if (prog->header.profile == CG_PROFILE_SCE_FP_RSX)
|
|
{
|
|
newprog->ucode = (char*)newprog + paddedProgramSize;
|
|
memcpy((char*)newprog->ucode, (char*)prog->ucode, ucodeSize);
|
|
}
|
|
|
|
//handle refcounting for string table and default values
|
|
if ( prog->programGroup )
|
|
{
|
|
//refcount for the string and the default table
|
|
newprog->programGroup = prog->programGroup;
|
|
newprog->programIndexInGroup = -1;
|
|
rglpCgUpdateProgramAtIndex( newprog->programGroup, -1, 1 );
|
|
}
|
|
|
|
// add the new program object to the program list in the context
|
|
rglCgProgramPushFront( newprog->parentContext, newprog );
|
|
|
|
if ( _cgProgramCopyHook ) _cgProgramCopyHook( newprog, prog );
|
|
|
|
return newprog->id;
|
|
}
|
|
|
|
CG_API void cgDestroyProgram( CGprogram program )
|
|
{
|
|
// remove the program from the program list
|
|
|
|
// check the program input
|
|
if ( !CG_IS_PROGRAM( program ) )
|
|
{
|
|
rglCgRaiseError( CG_INVALID_PROGRAM_HANDLE_ERROR );
|
|
return;
|
|
}
|
|
_CGprogram* ptr = _cgGetProgPtr( program );
|
|
if ( NULL == ptr )
|
|
{
|
|
rglCgRaiseError( CG_INVALID_PROGRAM_HANDLE_ERROR );
|
|
return;
|
|
}
|
|
|
|
if ( ptr->programGroup )
|
|
{
|
|
if ( !ptr->programGroup->userCreated )
|
|
{
|
|
if ( ptr->programIndexInGroup != -1 && ptr->programGroup->programs[ptr->programIndexInGroup].refCount == 0 )
|
|
{
|
|
//not a valid handle, the refcount is 0, this handle has already been freed
|
|
rglCgRaiseError( CG_INVALID_PROGRAM_HANDLE_ERROR );
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
bool isGroupMember = ( ptr->programIndexInGroup != -1 );
|
|
rglpCgUpdateProgramAtIndex( ptr->programGroup, ptr->programIndexInGroup, -1 );
|
|
if ( isGroupMember )
|
|
return;
|
|
//else continue, it needs to be deleted here, the group won't delete it.
|
|
//such program which have a programGroup but are not member of the group are
|
|
//clone of a program coming from a group. but those program still need the group
|
|
//because the group holds their stringtable and their default table.
|
|
}
|
|
}
|
|
}
|
|
|
|
// get the context that this program belongs to.
|
|
_CGcontext* ctx = ptr->parentContext;
|
|
|
|
// find and unlink the program from the program list
|
|
if ( ptr == ctx->programList )
|
|
{
|
|
// node is the head of the list, so unlink it.
|
|
_CGprogram* p = ctx->programList;
|
|
ctx->programList = p->next;
|
|
// erase the program
|
|
rglCgProgramEraseAndFree( p );
|
|
}
|
|
else
|
|
{
|
|
// node not the head, so use find_previous and delete_after
|
|
// NOTE: if the program is not found in the list, returns silently.
|
|
_CGprogram* p = rglCgProgramFindPrev( ctx, ptr );
|
|
rglCgProgramEraseAfter( p );
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
/*============================================================
|
|
CG GL
|
|
============================================================ */
|
|
|
|
/******************************************************************************
|
|
*** Profile Functions
|
|
*****************************************************************************/
|
|
|
|
CGGL_API CGbool cgGLIsProfileSupported( CGprofile profile )
|
|
{
|
|
switch ( profile )
|
|
{
|
|
case CG_PROFILE_SCE_VP_RSX:
|
|
return ( CGbool ) rglpSupportsVertexProgram( profile );
|
|
case CG_PROFILE_SCE_FP_RSX:
|
|
return ( CGbool ) rglpSupportsFragmentProgram( profile );
|
|
default:
|
|
return CG_FALSE;
|
|
}
|
|
}
|
|
|
|
CGGL_API void cgGLEnableProfile( CGprofile profile )
|
|
{
|
|
// this is a logical extension to glEnable
|
|
RGLcontext* LContext = _CurrentContext;
|
|
switch ( profile )
|
|
{
|
|
case CG_PROFILE_SCE_VP_RSX:
|
|
LContext->VertexProgram = GL_TRUE;
|
|
LContext->needValidate |= RGL_VALIDATE_VERTEX_PROGRAM;
|
|
break;
|
|
case CG_PROFILE_SCE_FP_RSX:
|
|
{
|
|
LContext->FragmentProgram = GL_TRUE;
|
|
struct _CGprogram* current = LContext->BoundFragmentProgram;
|
|
if ( current )
|
|
{
|
|
for ( GLuint i = 0; i < current->samplerCount; ++i )
|
|
{
|
|
int unit = current->samplerUnits[i];
|
|
rglTextureImageUnit *unit_ptr = (rglTextureImageUnit*)&_CurrentContext->TextureImageUnits[unit];
|
|
unit_ptr->currentTexture = rglGetCurrentTexture( unit_ptr, unit_ptr->fragmentTarget );
|
|
}
|
|
}
|
|
LContext->needValidate |= PSGL_VALIDATE_FRAGMENT_PROGRAM | PSGL_VALIDATE_TEXTURES_USED;
|
|
}
|
|
break;
|
|
default:
|
|
rglCgRaiseError( CG_INVALID_PROFILE_ERROR );
|
|
break;
|
|
}
|
|
}
|
|
|
|
CGGL_API void cgGLDisableProfile( CGprofile profile )
|
|
{
|
|
// this is a logical extension to glDisable
|
|
RGLcontext* LContext = _CurrentContext;
|
|
switch ( profile )
|
|
{
|
|
case CG_PROFILE_SCE_VP_RSX:
|
|
LContext->VertexProgram = GL_FALSE;
|
|
// no need to invalidate textures because they are only available on programmable pipe.
|
|
LContext->needValidate |= RGL_VALIDATE_VERTEX_PROGRAM ;
|
|
break;
|
|
case CG_PROFILE_SCE_FP_RSX:
|
|
LContext->FragmentProgram = GL_FALSE;
|
|
break;
|
|
default:
|
|
rglCgRaiseError( CG_INVALID_PROFILE_ERROR );
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
CGGL_API CGprofile cgGLGetLatestProfile( CGGLenum profile_type )
|
|
{
|
|
switch ( profile_type )
|
|
{
|
|
case CG_GL_VERTEX:
|
|
case CG_GL_FRAGMENT:
|
|
return rglpGetLatestProfile( profile_type );
|
|
default:
|
|
rglCgRaiseError( CG_INVALID_ENUMERANT_ERROR );
|
|
return CG_PROFILE_UNKNOWN;
|
|
}
|
|
}
|
|
|
|
CGGL_API void cgGLSetOptimalOptions( CGprofile profile )
|
|
{
|
|
// This does nothing because we don't compile at run-time.
|
|
}
|
|
|
|
/******************************************************************************
|
|
*** Program Managment Functions
|
|
*****************************************************************************/
|
|
|
|
CGGL_API void cgGLLoadProgram( CGprogram program )
|
|
{
|
|
// noop since there is integration of cg in js.
|
|
}
|
|
|
|
CGGL_API CGbool cgGLIsProgramLoaded( CGprogram program )
|
|
{
|
|
// TODO: for now a valid program is always loaded.
|
|
return CG_TRUE;
|
|
}
|
|
|
|
|
|
CGGL_API void cgGLBindProgram( CGprogram program )
|
|
{
|
|
_CGprogram* ptr = _cgGetProgPtr( program );
|
|
|
|
// now do the binding.
|
|
switch ( ptr->header.profile )
|
|
{
|
|
case 7005:
|
|
case CG_PROFILE_SCE_VP_RSX:
|
|
// the program is a vertex program, just update the GL state
|
|
_CurrentContext->BoundVertexProgram = ptr;
|
|
|
|
// and inform the GL state to re-upload the vertex program
|
|
_CurrentContext->needValidate |= PSGL_VALIDATE_VERTEX_PROGRAM;
|
|
break;
|
|
|
|
case 7006:
|
|
case CG_PROFILE_SCE_FP_RSX:
|
|
_CurrentContext->BoundFragmentProgram = ptr;
|
|
|
|
// need to revalidate the textures in order to update which targets to fetch from
|
|
_CurrentContext->needValidate |= PSGL_VALIDATE_FRAGMENT_PROGRAM | PSGL_VALIDATE_TEXTURES_USED;
|
|
|
|
// TODO: push texture state
|
|
// Needs to be done per profile. Can't use glPushAttrib.
|
|
|
|
// deal with the texture parameters now.
|
|
for ( GLuint index = 0; index < ptr->samplerCount; ++index )
|
|
{
|
|
// walk the array of sampler parameters
|
|
CgRuntimeParameter *rtParameter = ptr->runtimeParameters + ptr->samplerIndices[index];
|
|
CgParameterResource *parameter = ( CgParameterResource * )( ptr->parameterResources + rtParameter->parameterEntry->typeIndex );
|
|
// find out which texture unit this parameter has been assigned to
|
|
unsigned int unit = parameter->resource - CG_TEXUNIT0;
|
|
_CurrentContext->TextureImageUnits[unit].fragmentTarget = rtParameter->glType;
|
|
rglTextureImageUnit *unit_ptr = (rglTextureImageUnit*)&_CurrentContext->TextureImageUnits[unit];
|
|
unit_ptr->currentTexture = rglGetCurrentTexture( unit_ptr, unit_ptr->fragmentTarget );
|
|
}
|
|
break;
|
|
|
|
default:
|
|
rglCgRaiseError( CG_INVALID_PROFILE_ERROR );
|
|
return;
|
|
}
|
|
|
|
}
|
|
|
|
CGGL_API void cgGLUnbindProgram( CGprofile profile )
|
|
{
|
|
switch ( profile )
|
|
{
|
|
case CG_PROFILE_SCE_VP_RSX:
|
|
_CurrentContext->BoundVertexProgram = NULL;
|
|
_CurrentContext->needValidate |= PSGL_VALIDATE_VERTEX_PROGRAM;
|
|
// no need to invalidate textures because they are only available on programmable pipe.
|
|
break;
|
|
case CG_PROFILE_SCE_FP_RSX:
|
|
_CurrentContext->BoundFragmentProgram = NULL;
|
|
break;
|
|
default:
|
|
rglCgRaiseError( CG_INVALID_PROFILE_ERROR );
|
|
return;
|
|
}
|
|
|
|
}
|
|
|
|
/******************************************************************************
|
|
*** Parameter Managment Functions
|
|
*****************************************************************************/
|
|
|
|
CGGL_API void cgGLSetParameter1f( CGparameter param, float x )
|
|
{
|
|
// check to see if the parameter is a good one
|
|
CgRuntimeParameter *ptr = rglCgGLTestParameter( param );
|
|
|
|
// otherwise apply the values to the parameter
|
|
float v[4] = {x, x, x, x};
|
|
ptr->setterIndex( ptr, v, CG_GETINDEX( param ) );
|
|
}
|
|
|
|
CGGL_API void cgGLSetParameter2f( CGparameter param, float x, float y )
|
|
{
|
|
CgRuntimeParameter *ptr = rglCgGLTestParameter( param );
|
|
|
|
// otherwise apply the values to the parameter
|
|
float v[4] = {x, y, y, y};
|
|
ptr->setterIndex( ptr, v, CG_GETINDEX( param ) );
|
|
}
|
|
|
|
CGGL_API void cgGLSetParameterPointer( CGparameter param,
|
|
GLint fsize,
|
|
GLenum type,
|
|
GLsizei stride,
|
|
const GLvoid *pointer )
|
|
{
|
|
CgRuntimeParameter *_ptr = rglCgGLTestParameter( param );
|
|
|
|
const CgParameterResource *parameterResource = rglGetParameterResource( _ptr->program, _ptr->parameterEntry );
|
|
GLuint index = ( GLuint )( parameterResource->resource - CG_ATTR0 );
|
|
|
|
rglVertexAttribPointerNV(
|
|
index, // attribute index
|
|
fsize, // element size
|
|
type, // GL_FLOAT
|
|
( _ptr->parameterEntry->flags & CGP_NORMALIZE ) ? 1 : 0, // from the semantic of the param
|
|
stride, // element to element in bytes
|
|
pointer ); // data pointer
|
|
}
|
|
|
|
CGGL_API void cgGLEnableClientState( CGparameter param )
|
|
{
|
|
CgRuntimeParameter *_ptr = rglCgGLTestParameter( param );
|
|
|
|
const CgParameterResource *parameterResource = rglGetParameterResource( _ptr->program, _ptr->parameterEntry );
|
|
|
|
GLuint index = ( GLuint )( parameterResource->resource - CG_ATTR0 );
|
|
rglEnableVertexAttribArrayNV( index );
|
|
}
|
|
|
|
CGGL_API void cgGLDisableClientState( CGparameter param )
|
|
{
|
|
CgRuntimeParameter *_ptr = rglCgGLTestParameter( param );
|
|
|
|
const CgParameterResource *parameterResource = rglGetParameterResource( _ptr->program, _ptr->parameterEntry );
|
|
|
|
GLuint index = ( GLuint )( parameterResource->resource - CG_ATTR0 );
|
|
rglDisableVertexAttribArrayNV( index );
|
|
}
|
|
|
|
/******************************************************************************
|
|
*** Matrix Parameter Managment Functions
|
|
*****************************************************************************/
|
|
|
|
CGGL_API void cgGLSetMatrixParameterfc( CGparameter param, const float *matrix )
|
|
{
|
|
|
|
CgRuntimeParameter* ptr = rglCgGLTestParameter( param );
|
|
ptr->settercIndex( ptr, matrix, CG_GETINDEX( param ) );
|
|
}
|
|
|
|
CGGL_API void cgGLSetTextureParameter( CGparameter param, GLuint texobj )
|
|
{
|
|
// According to the cg implementation from nvidia, set just stores the obj.
|
|
// Enable does the actual work.
|
|
CgRuntimeParameter* ptr = _cgGLTestTextureParameter( param );
|
|
|
|
ptr->samplerSetter( ptr, &texobj, 0 );
|
|
}
|
|
|
|
CGGL_API GLuint cgGLGetTextureParameter( CGparameter param )
|
|
{
|
|
CgRuntimeParameter* ptr = _cgGLTestTextureParameter( param );
|
|
if (!ptr)
|
|
return 0;
|
|
if (!(ptr->parameterEntry->flags & CGPF_REFERENCED))
|
|
{
|
|
rglCgRaiseError( CG_INVALID_PARAMETER_ERROR );
|
|
return 0;
|
|
}
|
|
return *( GLuint* )ptr->pushBufferPointer;
|
|
}
|
|
|
|
CGGL_API void cgGLEnableTextureParameter( CGparameter param )
|
|
{
|
|
CgRuntimeParameter* ptr = _cgGLTestTextureParameter( param );
|
|
ptr->samplerSetter( ptr, NULL, 0 );
|
|
}
|
|
|
|
CGGL_API void cgGLDisableTextureParameter( CGparameter param )
|
|
{
|
|
if ( _cgGLTestTextureParameter( param ) )
|
|
{
|
|
// this does not do anything on nvidia's implementation
|
|
}
|
|
}
|
|
|
|
/*============================================================
|
|
CG NV2ELF
|
|
============================================================ */
|
|
|
|
using namespace cgc::bio;
|
|
|
|
class CgBaseType
|
|
{
|
|
public:
|
|
CgBaseType() {_type = 0;}
|
|
virtual ~CgBaseType() {}
|
|
unsigned short _type; //index of the type in the types array of the program if >= STRUCT, else it's a BASETYPE
|
|
short _resourceIndex; //index of the type in the types array of the program if >= STRUCT, else it's a BASETYPE
|
|
unsigned short _resource; //index of the type in the types array of the program if >= STRUCT, else it's a BASETYPE
|
|
};
|
|
|
|
//array
|
|
class CgArrayType : public CgBaseType
|
|
{
|
|
public:
|
|
CgArrayType():_elementType(NULL) { _type = (unsigned char)(CG_ARRAY + 128); }
|
|
virtual ~CgArrayType()
|
|
{
|
|
if (_elementType)
|
|
free(_elementType);
|
|
}
|
|
CgBaseType *_elementType;
|
|
unsigned char _dimensionCount;
|
|
unsigned short _dimensionItemCountsOffset;
|
|
};
|
|
|
|
//structure
|
|
class CgStructureType : public CgBaseType
|
|
{
|
|
public:
|
|
//definitions
|
|
class CgStructuralElement
|
|
{
|
|
public:
|
|
char _name[256];
|
|
char _semantic[256];
|
|
CgBaseType *_type;
|
|
unsigned short _flags; //in,out,global,varying,const,uniform,shared, hasDefaults(base types only) -> consecutive reg allocation flag
|
|
unsigned short _index; //helper index ?
|
|
};
|
|
|
|
//implementation
|
|
CgStructureType()
|
|
{
|
|
_type = (unsigned char)(CG_STRUCT + 128);
|
|
_root = false;
|
|
}
|
|
|
|
virtual ~CgStructureType()
|
|
{
|
|
int i=0;
|
|
int count = (int)_elements.size();
|
|
for (i = 0;i < count; i++)
|
|
{
|
|
if (_elements[i]._type)
|
|
free(_elements[i]._type);
|
|
}
|
|
}
|
|
|
|
//members
|
|
std::vector<CgStructuralElement> _elements;
|
|
bool _insideArray; //modifies the way the resources are stored, they should be sent directly to the resources,
|
|
//the array is keeping track of the resource offset in that case
|
|
bool _root;
|
|
};
|
|
|
|
typedef struct
|
|
{
|
|
const char *name;
|
|
int resIndex;
|
|
} BINDLOCATION;
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// static arrays containing type information
|
|
|
|
#define CG_DATATYPE_MACRO(name, compiler_name, enum_name, base_enum, nrows, ncols,classname) \
|
|
classname ,
|
|
static int classnames[] = {
|
|
#include "Cg/cg_datatypes.h"
|
|
};
|
|
|
|
#define CG_DATATYPE_MACRO(name, compiler_name, enum_name, base_enum, nrows, ncols,classname) \
|
|
nrows ,
|
|
static int rows[] = {
|
|
#include "Cg/cg_datatypes.h"
|
|
};
|
|
|
|
typedef float _float4[4];
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// static buffers containing the information extracted from the shaders
|
|
|
|
typedef struct
|
|
{
|
|
std::vector<short> _resources;
|
|
std::vector<unsigned short> _defaultValuesIndices;
|
|
std::vector<unsigned short> _elfDefaultsIndices;
|
|
std::vector<short> _dimensions;
|
|
std::vector<CgParameterSemantic> _semanticIndices;
|
|
} _CGNVCONTAINERS;
|
|
|
|
static bool bIsVertexProgram = true;
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// forward declarations
|
|
|
|
static int getStride(CgBaseType *type);
|
|
static int getSizeofSubArray(_CGNVCONTAINERS &containers, int dimensionIndex, int dimensionCount, int endianness);
|
|
|
|
static unsigned int stringTableFind( std::vector<char> &stringTable, const char* str )
|
|
{
|
|
const char* data = &stringTable[0];
|
|
size_t size = stringTable.size();
|
|
const char *end = data + size;
|
|
|
|
size_t length = strlen(str);
|
|
if (length+1 > size)
|
|
return 0;
|
|
data += length;
|
|
|
|
const char *p = (char*)memchr(data,'\0',end-data);
|
|
while (p && (end-data)>0)
|
|
{
|
|
if (!memcmp(p - length, str, length))
|
|
return (unsigned int)(p - length - &stringTable[0]);
|
|
data = p+1;
|
|
p = (char*)memchr(data,'\0',end-data);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static unsigned int stringTableAdd( std::vector<char> &stringTable, const char* str )
|
|
{
|
|
unsigned int ret = (unsigned int)stringTable.size();
|
|
|
|
if ( ret == 0 )
|
|
{
|
|
stringTable.push_back('\0'); //add the empty string
|
|
ret = 1;
|
|
}
|
|
|
|
size_t stringLength = strlen(str) + 1;
|
|
stringTable.resize(ret + stringLength);
|
|
memcpy(&stringTable[0] + ret,str,stringLength);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static unsigned int stringTableAddUnique( std::vector<char> &stringTable, const char* str )
|
|
{
|
|
if ( stringTable.size() == 0 )
|
|
stringTable.push_back('\0'); //add the empty string
|
|
unsigned int ret = stringTableFind(stringTable, str);
|
|
if (ret == 0 && str[0] != '\0')
|
|
ret = stringTableAdd(stringTable, str);
|
|
return ret;
|
|
}
|
|
|
|
static unsigned short getFlags(CGenum var, CGenum dir, int no, bool is_referenced, bool is_shared, int paramIndex);
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// implementation
|
|
|
|
static void fillStructureItems(_CGNVCONTAINERS &containers, CgStructureType *structure,
|
|
int endianness,
|
|
std::vector<CgParameterEntry> ¶meterEntries,
|
|
std::vector<char> ¶meterResources, std::vector<char> &stringTable, unsigned short *arrayResourceIndex,
|
|
unsigned short *arrayDefaultValueIndex);
|
|
|
|
|
|
#define swap16(v) ((v>>16) | (v<<16))
|
|
|
|
int convertNvToElfFromMemory(const void *sourceData, size_t size, int endianness, int constTableOffset, void **binaryShader, int *binarySize,
|
|
std::vector<char> &stringTable, std::vector<float> &defaultValues)
|
|
{
|
|
_CGNVCONTAINERS containers;
|
|
|
|
unsigned char elfEndianness = endianness; //used in the macro CNVEND
|
|
|
|
nvb_reader* nvbr = 0;
|
|
bin_io::instance()->new_nvb_reader( &nvbr );
|
|
CGBIO_ERROR err = nvbr->loadFromString((const char*)sourceData,size);
|
|
if (err != CGBIO_ERROR_NO_ERROR)
|
|
return -1;
|
|
|
|
//flag which tells if we have to swap data coming from nv and going to elf
|
|
bool doSwap = !(nvbr->endianness() == (HOST_ENDIANNESS)elfEndianness);
|
|
|
|
CGprofile NVProfile = nvbr->profile();
|
|
|
|
if (NVProfile == CG_PROFILE_SCE_VP_RSX)
|
|
bIsVertexProgram = true;
|
|
else if (NVProfile == CG_PROFILE_SCE_FP_RSX)
|
|
bIsVertexProgram = false;
|
|
else
|
|
{
|
|
//RGL_ASSERT2(0,("error: unknown shader profile\n"));
|
|
return -1;
|
|
}
|
|
|
|
//Fill the shader header structure and save it into the shadertab
|
|
CgProgramHeader cgShader;
|
|
memset(&cgShader,0,sizeof(CgProgramHeader));
|
|
cgShader.profile = CNV2END((unsigned short) NVProfile); //ok cnv2end here we go from platform endiannes to elf endiannes
|
|
cgShader.compilerVersion = 0;//TODO
|
|
if (bIsVertexProgram)
|
|
{
|
|
const CgBinaryVertexProgram *nvVertex = nvbr->vertex_program();
|
|
if (doSwap) //here we go directly from nv to elf endiannes without going to the platform endianness
|
|
{
|
|
cgShader.instructionCount = ENDSWAP(nvVertex->instructionCount);
|
|
cgShader.attributeInputMask = ENDSWAP(nvVertex->attributeInputMask);
|
|
//vertex program specific
|
|
cgShader.vertexProgram.instructionSlot = ENDSWAP(nvVertex->instructionSlot);
|
|
cgShader.vertexProgram.registerCount = ENDSWAP(nvVertex->registerCount);
|
|
cgShader.vertexProgram.attributeOutputMask = ENDSWAP(nvVertex->attributeOutputMask);
|
|
}
|
|
else
|
|
{
|
|
cgShader.instructionCount = nvVertex->instructionCount;
|
|
cgShader.attributeInputMask = nvVertex->attributeInputMask;
|
|
//vertex program specific
|
|
cgShader.vertexProgram.instructionSlot = nvVertex->instructionSlot;
|
|
cgShader.vertexProgram.registerCount = nvVertex->registerCount;
|
|
cgShader.vertexProgram.attributeOutputMask = nvVertex->attributeOutputMask;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
const CgBinaryFragmentProgram *nvFragment = nvbr->fragment_program();
|
|
unsigned char flags;
|
|
if (doSwap)
|
|
{
|
|
cgShader.instructionCount = ENDSWAP(nvFragment->instructionCount);
|
|
cgShader.attributeInputMask = ENDSWAP(nvFragment->attributeInputMask);
|
|
//fragment program specific
|
|
cgShader.fragmentProgram.partialTexType = ENDSWAP(nvFragment->partialTexType);
|
|
cgShader.fragmentProgram.texcoordInputMask = ENDSWAP(nvFragment->texCoordsInputMask);
|
|
cgShader.fragmentProgram.texcoord2d = ENDSWAP(nvFragment->texCoords2D);
|
|
cgShader.fragmentProgram.texcoordCentroid = ENDSWAP(nvFragment->texCoordsCentroid);
|
|
cgShader.fragmentProgram.registerCount = ENDSWAP(nvFragment->registerCount);
|
|
flags =
|
|
(nvFragment->outputFromH0 ? CGF_OUTPUTFROMH0 : 0) |
|
|
(nvFragment->depthReplace ? CGF_DEPTHREPLACE : 0) |
|
|
(nvFragment->pixelKill ? CGF_PIXELKILL : 0);
|
|
}
|
|
else
|
|
{
|
|
cgShader.instructionCount = nvFragment->instructionCount;
|
|
cgShader.attributeInputMask = nvFragment->attributeInputMask;
|
|
//fragment program specific
|
|
cgShader.fragmentProgram.partialTexType = nvFragment->partialTexType;
|
|
cgShader.fragmentProgram.texcoordInputMask = nvFragment->texCoordsInputMask;
|
|
cgShader.fragmentProgram.texcoord2d = nvFragment->texCoords2D;
|
|
cgShader.fragmentProgram.texcoordCentroid = nvFragment->texCoordsCentroid;
|
|
cgShader.fragmentProgram.registerCount = nvFragment->registerCount;
|
|
flags =
|
|
(nvFragment->outputFromH0 ? CGF_OUTPUTFROMH0 : 0) |
|
|
(nvFragment->depthReplace ? CGF_DEPTHREPLACE : 0) |
|
|
(nvFragment->pixelKill ? CGF_PIXELKILL : 0);
|
|
}
|
|
cgShader.fragmentProgram.flags = CNV2END(flags);
|
|
}
|
|
|
|
//shader specific info ( the shader header is in the shader tab )
|
|
|
|
//ucode
|
|
uint32_t *tmp = (uint32_t *)nvbr->ucode();
|
|
const char *ucode;
|
|
uint32_t *buffer = NULL;
|
|
if (doSwap)
|
|
{
|
|
int size = (int)nvbr->ucode_size()/sizeof(uint32_t);
|
|
buffer = (uint32_t*)malloc(size * sizeof(uint32_t));
|
|
|
|
for (int i = 0; i < size; i++)
|
|
{
|
|
uint32_t val = ENDSWAP(tmp[i]);
|
|
if (!bIsVertexProgram)
|
|
val = swap16(val);
|
|
buffer[i] = val;
|
|
}
|
|
ucode = (const char*)buffer;
|
|
}
|
|
else
|
|
{
|
|
ucode = (const char*)tmp;
|
|
// !!!xxx this is to workaround what appears to be a linux platform specific bug
|
|
// that manifests as a memory overwrite in properly allocated memory during a std::vector resize
|
|
int size = (int)nvbr->ucode_size()/sizeof(uint32_t);
|
|
buffer = (uint32_t*)malloc(size * sizeof(uint32_t));
|
|
|
|
for (int i = 0; i < size; i++)
|
|
buffer[i] = tmp[i];
|
|
ucode = (const char*)buffer;
|
|
// end workaround
|
|
}
|
|
|
|
int ucodeSize = nvbr->ucode_size();
|
|
|
|
//ucode, ucodeSize;
|
|
|
|
//RGL_ASSERT2(CNV2END(cgShader.instructionCount)*16 ==nvbr->ucode_size(),("%i, %i",CNV2END(cgShader.instructionCount)*16,nvbr->ucode_size()));
|
|
|
|
//parameters
|
|
CgStructureType root;
|
|
root._insideArray = false;
|
|
root._root = true;
|
|
|
|
//we don't have the names of the user structures, so to share structures we will have to rely on the
|
|
//layout of the data, we might do mistakes, but it's not important, since what we want to represent is
|
|
//the structure layout.
|
|
//parameters
|
|
//the parameters represents a hierarchical structure, I am reconstructing this structure
|
|
|
|
int paramIndex = -1;
|
|
|
|
//just for sanity check purpose: it's use to detect when there's a change of structural element to reset the embedded constant counter
|
|
CgStructureType::CgStructuralElement *current = NULL;
|
|
int embeddedConstants = 0;
|
|
bool rootChildDefaultValues = false;
|
|
int rootChildIndex = -1;
|
|
|
|
char currentRefStructureName[256];
|
|
currentRefStructureName[0] = '\0';
|
|
|
|
int i;
|
|
for (i = 0; i < (int)nvbr->number_of_params(); i++)
|
|
{
|
|
CGtype type;
|
|
CGresource res;
|
|
CGenum var;
|
|
int rin;
|
|
const char *name;
|
|
std::vector<float> dv;
|
|
std::vector<unsigned int> ec;
|
|
const char *sem;
|
|
CGenum dir;
|
|
int no;
|
|
bool is_referenced;
|
|
bool is_shared;
|
|
nvbr->get_param( i, type, res, var, rin, &name, dv, ec, &sem, dir, no, is_referenced, is_shared );
|
|
|
|
const char *parameterName = name;
|
|
const char *structureEnd = NULL;
|
|
CgStructureType *container = &root;
|
|
int done = 0;
|
|
const char * structureStart = parameterName;
|
|
while (!done && *structureStart)
|
|
{
|
|
// process the next structural element
|
|
structureEnd = strpbrk(structureStart, ".[");
|
|
|
|
if (structureEnd)
|
|
{
|
|
//there's a special case for sampler, we don't support arrays of sampler, so unrolled the array here
|
|
//and don't even register the structure as being an array
|
|
if (*structureEnd == '[' && type >= CG_SAMPLER1D && type <= CG_SAMPLERCUBE)
|
|
{
|
|
//do we have an array of samplers and are we at the end ?
|
|
const char *closed = strchr(structureEnd, ']');
|
|
//RGL_ASSERT2(closed,("name error for parameter %s",parameterName));
|
|
const char *somethingElse = strpbrk(closed, ".[");
|
|
if (!somethingElse)
|
|
structureEnd = NULL; //so we are at the end we are in an array of samplers
|
|
}
|
|
}
|
|
|
|
// test if we are done finding structural information
|
|
if (!structureEnd)
|
|
{
|
|
//set structureEnd correctly so that the rest of the function performs correctly
|
|
structureEnd = structureStart + strlen(structureStart);
|
|
//set the done flag to exit the loop
|
|
done = 1;
|
|
}
|
|
|
|
//extract the current structural element name
|
|
char structName[256];
|
|
int length = (int)(structureEnd - structureStart);
|
|
strncpy(structName, structureStart, length);
|
|
structName[length] = '\0';
|
|
|
|
//do we already have it in the structure ?
|
|
CgStructureType::CgStructuralElement *structuralElement = NULL;
|
|
int j=0;
|
|
int elementCount = (int)container->_elements.size();
|
|
for (j=0;j<elementCount;j++)
|
|
{
|
|
structuralElement = &container->_elements[j];
|
|
if (!strcmp(structuralElement->_name,structName))
|
|
{
|
|
//same name, we need to check that this is the same scope ( program versus global )
|
|
if ( (no == -1 && (structuralElement->_flags & CGPF_GLOBAL)) ||
|
|
(no != -1 && !(structuralElement->_flags & CGPF_GLOBAL)))
|
|
break;
|
|
}
|
|
}
|
|
if (j==elementCount)
|
|
{
|
|
if (container == &root)
|
|
{
|
|
if (rootChildIndex != j)
|
|
{
|
|
rootChildDefaultValues = false;
|
|
rootChildIndex = j;
|
|
}
|
|
}
|
|
|
|
//we don't have it yet, add it
|
|
container->_elements.resize(elementCount+1);
|
|
structuralElement = &container->_elements[elementCount];
|
|
strncpy(structuralElement->_name,structName,sizeof(structuralElement->_name));
|
|
structuralElement->_name[sizeof(structuralElement->_name)-1] = '\0';
|
|
structuralElement->_flags = getFlags(var,dir,no,is_referenced,is_shared,paramIndex);
|
|
int dimensionCount = 0;
|
|
|
|
if (strncmp(sem, "COLOR", 5) == 0 || strncmp(sem, "NORMAL", 6) == 0)
|
|
structuralElement->_flags |= CGP_NORMALIZE;
|
|
|
|
|
|
//check if we have a structure or an array of structure or an array of basetypes
|
|
//then:
|
|
// - create an array type if we have an array
|
|
// - update the container if we have a structure or an array of structure
|
|
int isStructure = (*structureEnd == '.');
|
|
if (*structureEnd == '[')
|
|
{
|
|
dimensionCount++;
|
|
const char *arrayEnd = strchr(structureEnd,']')+1;
|
|
while (*arrayEnd == '[')
|
|
{
|
|
arrayEnd = strchr(arrayEnd,']')+1;
|
|
dimensionCount++;
|
|
}
|
|
if (*arrayEnd == '.')
|
|
isStructure = true;
|
|
}
|
|
|
|
//we have an array, create an array type
|
|
if (dimensionCount)
|
|
{
|
|
CgArrayType *arrayType = new CgArrayType;
|
|
arrayType->_dimensionCount = dimensionCount;
|
|
arrayType->_dimensionItemCountsOffset = (unsigned short)containers._dimensions.size();
|
|
//initialize the dimension count;
|
|
int k;
|
|
for (k=0;k<dimensionCount;k++)
|
|
containers._dimensions.push_back(CNV2END((short)0));
|
|
structuralElement->_type = arrayType;
|
|
if (isStructure)
|
|
{
|
|
//we have a structure inside the array
|
|
container = new CgStructureType;
|
|
container->_insideArray = true;
|
|
arrayType->_elementType = container;
|
|
}
|
|
else
|
|
{
|
|
//we have a base type inside the array
|
|
arrayType->_elementType = new CgBaseType;
|
|
arrayType->_elementType->_type = type - CG_TYPE_START_ENUM;
|
|
}
|
|
arrayType->_elementType->_resource = res;
|
|
arrayType->_elementType->_resourceIndex = -1;
|
|
structuralElement->_type->_resourceIndex = (int)containers._resources.size();
|
|
structuralElement->_type->_resource = res;
|
|
}
|
|
else
|
|
{
|
|
//we have a structure
|
|
if (isStructure)
|
|
{
|
|
bool insideArray = container->_insideArray;
|
|
container = new CgStructureType;
|
|
container->_insideArray = insideArray;
|
|
structuralElement->_type = container;
|
|
}
|
|
else
|
|
{
|
|
//assign the basetype and resource
|
|
structuralElement->_type = new CgBaseType;
|
|
structuralElement->_type->_type = type - CG_TYPE_START_ENUM;
|
|
structuralElement->_type->_resource = res;
|
|
if (classnames[structuralElement->_type->_type-1] == CG_PARAMETERCLASS_MATRIX)
|
|
{
|
|
//TODO, Cedric: for vertexprogram assume the matrices are always fully allocated and that they have consecuttive assignements
|
|
if (bIsVertexProgram)
|
|
{
|
|
structuralElement->_type->_resourceIndex = (short)rin;
|
|
}
|
|
else
|
|
structuralElement->_type->_resourceIndex = (int)containers._resources.size();
|
|
}
|
|
else
|
|
{
|
|
if (!container->_insideArray)
|
|
{
|
|
//vertex program
|
|
if (bIsVertexProgram)
|
|
structuralElement->_type->_resourceIndex = rin;
|
|
else
|
|
{
|
|
//fragment program
|
|
if (structuralElement->_flags & CGPV_VARYING)
|
|
structuralElement->_type->_resourceIndex = -1;
|
|
else
|
|
{
|
|
structuralElement->_type->_resourceIndex = (int)containers._resources.size();
|
|
containers._resources.push_back(CNV2END((unsigned short)rin));
|
|
int size = (int)ec.size();
|
|
containers._resources.push_back(CNV2END((unsigned short)size));
|
|
int k;
|
|
for (k=0;k<size;k++)
|
|
containers._resources.push_back(CNV2END((unsigned short)ec[k]));
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//will be done later
|
|
structuralElement->_type->_resourceIndex = (short)-1;
|
|
structuralElement->_type->_resource = (unsigned short)res;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (structuralElement->_type->_type == CG_STRUCT+128)
|
|
{
|
|
container = (CgStructureType*)structuralElement->_type;
|
|
}
|
|
else if (structuralElement->_type->_type == CG_ARRAY+128)
|
|
{
|
|
CgArrayType *arrayType = (CgArrayType *)structuralElement->_type;
|
|
if (arrayType->_elementType->_type >128 )
|
|
{
|
|
if (arrayType->_elementType->_type != CG_STRUCT+128) //we can't have arrays of arrays
|
|
{
|
|
//RGL_ASSERT2(0,("arrays of arrays not supported"));
|
|
}
|
|
container = (CgStructureType*)arrayType->_elementType;
|
|
}
|
|
}
|
|
}
|
|
|
|
//default values should only be at the root of the hierarchical parameter structure
|
|
//RGL_ASSERT2(!rootChildDefaultValues || dv.size(),("all the parameter below a root child should have a default value"));
|
|
//if (dv.size() && !rootChildDefaultValues)
|
|
if (dv.size())
|
|
{
|
|
int size = (int)containers._defaultValuesIndices.size();
|
|
if (!size || (containers._defaultValuesIndices[size-2] != CNV2END((unsigned short)(rootChildIndex))))
|
|
{
|
|
//assert for default values on structures:
|
|
//now supported:
|
|
/*RGL_ASSERT2(structuralElement->_type->_type != CG_STRUCT + 128,("default values on structure not yet supported"));
|
|
RGL_ASSERT2(structuralElement->_type->_type != CG_ARRAY + 128 ||
|
|
((CgArrayType *)structuralElement->_type)->_elementType->_type != CG_STRUCT + 128,
|
|
("default values on arrays of structures not yet supported"));*/
|
|
|
|
//push the index of the parameter in the global structure
|
|
containers._defaultValuesIndices.push_back(CNV2END((unsigned short)(rootChildIndex)));
|
|
//push the index of the default value ( could add the size if necessary )
|
|
containers._defaultValuesIndices.push_back(CNV2END((unsigned short)defaultValues.size()));
|
|
}
|
|
}
|
|
|
|
//this case is for when we have item within a struct which is in an array, we don't duplicate the struct
|
|
//but we still need to save the resources at the array level, so with this code when we reach the end of the parameter
|
|
//name, we only need to save the resources
|
|
if (container->_insideArray && done)
|
|
{
|
|
//the reason of the reset of the flag is because the first item of the array might unreferenced
|
|
//so it doesn't has the correct resource type
|
|
if (is_referenced)
|
|
{
|
|
structuralElement->_flags = getFlags(var,dir,no,is_referenced,is_shared,paramIndex);
|
|
}
|
|
if (bIsVertexProgram)
|
|
containers._resources.push_back(CNV2END((unsigned short)rin));
|
|
else
|
|
{
|
|
//fragment program
|
|
if (structuralElement->_flags & CGPV_VARYING)
|
|
containers._resources.push_back(CNV2END((unsigned short)rin));
|
|
else
|
|
{
|
|
containers._resources.push_back(CNV2END((unsigned short)rin));
|
|
int size = (int)ec.size();
|
|
containers._resources.push_back(CNV2END((unsigned short)size));
|
|
int k;
|
|
for (k=0;k<size;k++)
|
|
containers._resources.push_back(CNV2END((unsigned short)ec[k]));
|
|
}
|
|
}
|
|
}
|
|
|
|
//if we have an array we need to update the item counts and skip the array for the parsing of the name of the structure
|
|
CgArrayType *arrayType = NULL;
|
|
if (*structureEnd == '[')
|
|
{
|
|
int arrayCellIndex = 0;
|
|
const char *arrayStart = structureEnd;
|
|
const char *arrayEnd = structureEnd;
|
|
CgBaseType *itemType = structuralElement->_type;
|
|
if (itemType->_type >= 128)
|
|
{
|
|
arrayType = (CgArrayType *)itemType;
|
|
int dimensionCount = 0;
|
|
while (*arrayStart == '[' && dimensionCount<arrayType->_dimensionCount)
|
|
{
|
|
arrayEnd = strchr(arrayStart+1,']');
|
|
int length =(int)(arrayEnd - arrayStart - 1);
|
|
char indexString[16];
|
|
strncpy(indexString,arrayStart+1,length);
|
|
indexString[length] = '\0';
|
|
int index = atoi(indexString);
|
|
int dim = CNV2END(containers._dimensions[arrayType->_dimensionItemCountsOffset + dimensionCount]);
|
|
if ((index+1) > dim)
|
|
containers._dimensions[arrayType->_dimensionItemCountsOffset + dimensionCount] = CNV2END((short)(index+1));
|
|
arrayCellIndex += index*getSizeofSubArray(containers,arrayType->_dimensionItemCountsOffset + dimensionCount,arrayType->_dimensionCount - dimensionCount -1,endianness);
|
|
arrayStart = arrayEnd+1;
|
|
dimensionCount++;
|
|
}
|
|
structureEnd = arrayStart;
|
|
|
|
itemType = arrayType->_elementType;
|
|
if (itemType->_type<128)
|
|
{
|
|
int rowCount = rows[itemType->_type-1];
|
|
if (!rowCount) //no matrix here
|
|
{
|
|
containers._resources.push_back(CNV2END((unsigned short)rin));
|
|
|
|
//fragment program
|
|
if (!bIsVertexProgram)
|
|
{
|
|
int size = (int)ec.size();
|
|
containers._resources.push_back(CNV2END((unsigned short)size));
|
|
int k;
|
|
for (k=0;k<size;k++)
|
|
containers._resources.push_back(CNV2END((unsigned short)ec[k]));
|
|
}
|
|
//RGL_ASSERT2(*arrayStart == '\0',("internal error: matrix type expected"));
|
|
done = 1;
|
|
}
|
|
}
|
|
|
|
if (*arrayStart == '\0')
|
|
{
|
|
done = 1;
|
|
}
|
|
}
|
|
|
|
//if we still have some [ , it means we have a matrix
|
|
if (*structureEnd == '[')
|
|
{
|
|
int dimensionCount = 0;
|
|
while (*arrayStart == '[')
|
|
{
|
|
arrayEnd = strchr(arrayStart+1,']');
|
|
if (itemType->_type <128)//matrix
|
|
{
|
|
if (structuralElement != current)
|
|
{
|
|
embeddedConstants = 0;
|
|
current = structuralElement;
|
|
}
|
|
|
|
int length =(int)(arrayEnd - arrayStart - 1);
|
|
char indexString[16];
|
|
strncpy(indexString,arrayStart+1,length);
|
|
indexString[length] = '\0';
|
|
|
|
//TODO: Cedric: for vertex program and matrices not in array, I am not adding any resource:
|
|
if (bIsVertexProgram)
|
|
{
|
|
if (arrayType)
|
|
{
|
|
//add the resource index ... scary
|
|
containers._resources.push_back(CNV2END((unsigned short)rin));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
containers._resources.push_back(CNV2END((unsigned short)rin));
|
|
int size = (int)ec.size();
|
|
containers._resources.push_back(CNV2END((unsigned short)size));
|
|
int k;
|
|
for (k=0;k<size;k++)
|
|
containers._resources.push_back(CNV2END((unsigned short)ec[k]));
|
|
embeddedConstants += k+1;
|
|
}
|
|
//RGL_ASSERT2(*(arrayEnd+1) == '\0',("internal error: matrix type expected, the parameter specifier is longer than expected"));
|
|
done = 1;
|
|
}
|
|
arrayStart = arrayEnd+1;
|
|
dimensionCount++;
|
|
}
|
|
structureEnd = arrayEnd;
|
|
}
|
|
|
|
// matrix single or array or array of matrix: the flags should be the same for all the referenced items
|
|
if (is_referenced)
|
|
{
|
|
unsigned short flag = getFlags(var,dir,no,is_referenced,is_shared,paramIndex);
|
|
structuralElement->_flags = flag;
|
|
structuralElement->_type->_resource = res;
|
|
//if array
|
|
if (arrayType)
|
|
arrayType->_elementType->_resource = res;
|
|
}
|
|
}
|
|
|
|
|
|
if (done && dv.size())
|
|
{
|
|
//very difficult to check that there is no mistake done... should do a diff with
|
|
//containers._defaultValuesIndices[containers._defaultValuesIndices.size()-1] and the current parameter position in
|
|
//the structure
|
|
for ( int jj = 0; jj < (int)dv.size(); ++jj )
|
|
defaultValues.push_back(dv[jj]);
|
|
}
|
|
|
|
if (done)
|
|
{
|
|
if (strlen(sem))
|
|
strncpy(structuralElement->_semantic,sem,sizeof(structuralElement->_semantic));
|
|
else
|
|
structuralElement->_semantic[0] = '\0';
|
|
}
|
|
structureStart = structureEnd+1;
|
|
}
|
|
}
|
|
|
|
//we are done with the reader
|
|
nvbr->release();
|
|
//release singleton
|
|
bin_io::delete_instance();
|
|
|
|
//print the structure that we have extracted
|
|
|
|
//transform the extracted structure into the file format
|
|
std::vector<CgParameterEntry> parameterEntries;
|
|
std::vector<char> parameterResources;
|
|
fillStructureItems(containers,&root,endianness,parameterEntries,parameterResources,stringTable, NULL, NULL);
|
|
|
|
//save it
|
|
CgParameterTableHeader header;
|
|
memset(&header,0,sizeof(CgParameterTableHeader));
|
|
header.entryCount = (unsigned short)parameterEntries.size();
|
|
header.resourceTableOffset = sizeof(CgParameterTableHeader) + (unsigned short)(parameterEntries.size()*sizeof(parameterEntries[0]) + parameterResources.size()*sizeof(parameterResources[0]));
|
|
header.defaultValueIndexTableOffset = header.resourceTableOffset + (unsigned short)containers._resources.size() * sizeof(containers._resources[0]);
|
|
header.defaultValueIndexCount = (unsigned short)containers._elfDefaultsIndices.size()/2;
|
|
header.semanticIndexTableOffset = header.defaultValueIndexTableOffset + (unsigned short)containers._elfDefaultsIndices.size() * sizeof (containers._elfDefaultsIndices[0]);
|
|
header.semanticIndexCount = (unsigned short)containers._semanticIndices.size();
|
|
|
|
header.entryCount = CNV2END(header.entryCount);
|
|
header.resourceTableOffset = CNV2END(header.resourceTableOffset);
|
|
header.defaultValueIndexTableOffset = CNV2END(header.defaultValueIndexTableOffset);
|
|
header.defaultValueIndexCount = CNV2END(header.defaultValueIndexCount);
|
|
header.semanticIndexTableOffset = CNV2END(header.semanticIndexTableOffset);
|
|
header.semanticIndexCount = CNV2END(header.semanticIndexCount);
|
|
|
|
//fill the parameter section
|
|
size_t parameterTableSize = sizeof(CgParameterTableHeader);
|
|
parameterTableSize += (unsigned int)parameterEntries.size() * sizeof(parameterEntries[0]);
|
|
parameterTableSize += (unsigned int)parameterResources.size() * sizeof(parameterResources[0]);
|
|
parameterTableSize += (unsigned int)containers._resources.size() * sizeof(containers._resources[0]);
|
|
//parameterTableSize += (unsigned int)containers._defaultValuesIndices.size() * sizeof(containers._defaultValuesIndices[0]);
|
|
parameterTableSize += (unsigned int)containers._elfDefaultsIndices.size() * sizeof(containers._elfDefaultsIndices[0]);
|
|
parameterTableSize += (unsigned int)containers._semanticIndices.size() * sizeof(containers._semanticIndices[0]);
|
|
|
|
//Allocate the binary file
|
|
int ucodeOffset = (((sizeof(CgProgramHeader)-1)/16)+1)*16;
|
|
size_t programSize = ucodeOffset + ucodeSize + parameterTableSize;
|
|
char *program = (char*)malloc(programSize * sizeof(char));
|
|
|
|
//header
|
|
memcpy(program,&cgShader,sizeof(CgProgramHeader));
|
|
if (ucodeOffset-sizeof(CgProgramHeader))
|
|
memset(program+sizeof(CgProgramHeader),0,ucodeOffset-sizeof(CgProgramHeader));
|
|
|
|
//ucode
|
|
memcpy(program + ucodeOffset,ucode,ucodeSize);
|
|
if (buffer)
|
|
free(buffer);
|
|
|
|
//parameters
|
|
char *parameterOffset = program + ucodeOffset + ucodeSize;
|
|
size_t datasize;
|
|
|
|
memcpy(parameterOffset,&header,sizeof(CgParameterTableHeader));
|
|
parameterOffset += sizeof(CgParameterTableHeader);
|
|
|
|
datasize = parameterEntries.size() * sizeof(parameterEntries[0]);
|
|
memcpy(parameterOffset, ¶meterEntries[0], datasize);
|
|
parameterOffset += datasize;
|
|
|
|
datasize = parameterResources.size() * sizeof(parameterResources[0]);
|
|
memcpy(parameterOffset, ¶meterResources[0], datasize);
|
|
parameterOffset += datasize;
|
|
|
|
datasize = containers._resources.size() * sizeof(containers._resources[0]);
|
|
memcpy(parameterOffset, &containers._resources[0], datasize);
|
|
parameterOffset += datasize;
|
|
|
|
datasize = containers._elfDefaultsIndices.size() * sizeof(containers._elfDefaultsIndices[0]);
|
|
memcpy(parameterOffset, &containers._elfDefaultsIndices[0], datasize);
|
|
parameterOffset += datasize;
|
|
|
|
datasize = containers._semanticIndices.size() * sizeof(containers._semanticIndices[0]);
|
|
memcpy(parameterOffset, &containers._semanticIndices[0], datasize);
|
|
parameterOffset += datasize;
|
|
|
|
//RGL_ASSERT2(parameterOffset == program + programSize,("error\n"));
|
|
//set the return values
|
|
*binarySize = (int)programSize;
|
|
*binaryShader = program;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int convertNvToElfFreeBinaryShader(void *binaryShader)
|
|
{
|
|
char *program = (char *)binaryShader;
|
|
|
|
if (program)
|
|
free(program);
|
|
return 0;
|
|
}
|
|
|
|
static void pushbackUnsignedShort(std::vector<char> ¶meterResources, unsigned short value)
|
|
{
|
|
size_t size = parameterResources.size();
|
|
parameterResources.resize(size + 2);
|
|
*((unsigned short*)¶meterResources[size]) = value;
|
|
}
|
|
|
|
//This function fill the parameter tables that will be written to the files
|
|
static void fillStructureItems(_CGNVCONTAINERS &containers, CgStructureType *structure, int endianness,
|
|
std::vector<CgParameterEntry> ¶meterEntries,std::vector<char> ¶meterResources,
|
|
std::vector<char> &stringTable, unsigned short *arrayResourceIndex, unsigned short *arrayDefaultValueIndex)
|
|
{
|
|
unsigned char elfEndianness = endianness; //used in the macro CNVEND
|
|
|
|
int currentDefaultIndex = 0;
|
|
int count = (int)structure->_elements.size();
|
|
int i;
|
|
for (i=0;i<count;i++)
|
|
{
|
|
CgStructureType::CgStructuralElement *structuralElement = &structure->_elements[i];
|
|
size_t size = parameterEntries.size();
|
|
parameterEntries.resize(size+1);
|
|
CgParameterEntry *parameterEntry = ¶meterEntries[size];
|
|
parameterEntry->nameOffset = CNV2END((int)stringTableAddUnique(stringTable, structuralElement->_name));
|
|
if (structuralElement->_semantic[0])
|
|
{
|
|
CgParameterSemantic semantic;
|
|
semantic.entryIndex = CNV2END((unsigned short)size);
|
|
semantic.reserved = 0;
|
|
semantic.semanticOffset = CNV2END((int)stringTableAddUnique(stringTable, structuralElement->_semantic));
|
|
containers._semanticIndices.push_back(semantic);
|
|
}
|
|
parameterEntry->flags = CNV2END(structuralElement->_flags);
|
|
//prepare the typeIndex
|
|
unsigned short typeIndex = ((unsigned short)parameterResources.size());
|
|
//RGL_ASSERT2((typeIndex&3) == 0,("typeindex must be aligned on 4 bytes"));
|
|
parameterEntry->typeIndex = CNV2END(typeIndex);
|
|
|
|
CgBaseType *itemType = structuralElement->_type;
|
|
unsigned short _resource = itemType->_resource;
|
|
unsigned short _resourceIndex = itemType->_resourceIndex;
|
|
|
|
//will contain the parameterEntry for this item, for simple type arrays the value will be corrected
|
|
//parameterEntry.size() is not parameterEntryIndex in that case.
|
|
int parameterEntryIndex;
|
|
|
|
if (itemType->_type-128 == CG_ARRAY)
|
|
{
|
|
CgArrayType *arrayType = (CgArrayType *)structuralElement->_type;
|
|
int arraySize = getSizeofSubArray(containers,arrayType->_dimensionItemCountsOffset,arrayType->_dimensionCount,endianness);
|
|
itemType = arrayType->_elementType;
|
|
//RGL_ASSERT2(!(itemType->_type +CG_TYPE_START_ENUM >= CG_SAMPLER1D && itemType->_type +CG_TYPE_START_ENUM<= CG_SAMPLERCUBE),("array of samplers not yet supported"));
|
|
unsigned short arrayFlag = CGP_ARRAY;
|
|
parameterEntry->flags |= CNV2END(arrayFlag);
|
|
parameterResources.resize(typeIndex+sizeof(CgParameterArray));
|
|
|
|
CgParameterArray *parameterArray = (CgParameterArray *)(¶meterResources[typeIndex]);
|
|
if (itemType->_type-128 == CG_STRUCT )
|
|
parameterArray->arrayType = CNV2END((unsigned short)CG_STRUCT);
|
|
else
|
|
parameterArray->arrayType = CNV2END(itemType->_type+128);
|
|
parameterArray->dimensionCount = CNV2END((unsigned short)arrayType->_dimensionCount);
|
|
int j;
|
|
for (j=0;j<arrayType->_dimensionCount;j++)
|
|
{
|
|
pushbackUnsignedShort(parameterResources,(unsigned short)containers._dimensions[arrayType->_dimensionItemCountsOffset+j]); //already endian-swapped
|
|
}
|
|
//padding
|
|
if (arrayType->_dimensionCount&1)
|
|
pushbackUnsignedShort(parameterResources,CNV2END((unsigned short)0));
|
|
|
|
//unroll the array of structure here, create one structure for each item of the array
|
|
if (itemType->_type-128 == CG_STRUCT )
|
|
{
|
|
unsigned short unrolledFlag = CGP_UNROLLED;
|
|
parameterEntry->flags |= CNV2END(unrolledFlag);
|
|
CgStructureType *structureType = (CgStructureType*)itemType;
|
|
int k;
|
|
|
|
//those lines won't work for arrays of structures containing arrays
|
|
unsigned short _arrayResourceIndex = (unsigned short)(arrayType->_resourceIndex);
|
|
unsigned short _arrayDefaultValueIndex = 0;
|
|
|
|
bool hasDefaults = false;
|
|
if (structure->_root && containers._defaultValuesIndices.size())
|
|
{
|
|
if (containers._defaultValuesIndices[currentDefaultIndex*2] == CNV2END((unsigned short)i))
|
|
{
|
|
hasDefaults = true;
|
|
_arrayDefaultValueIndex = containers._defaultValuesIndices[currentDefaultIndex*2+1];
|
|
//containers._defaultValuesIndices[currentDefaultIndex*2] = CNV2END((unsigned short)(parameterEntries.size() - 1));
|
|
//currentDefaultIndex++;
|
|
}
|
|
}
|
|
|
|
for (k=0;k<arraySize;k++)
|
|
{
|
|
size_t size = parameterEntries.size();
|
|
parameterEntries.resize(size+1);
|
|
|
|
CgParameterEntry ¶meterArrayEntry = parameterEntries[size];
|
|
|
|
char buffer[256];
|
|
sprintf(buffer,"%s[%i]",structuralElement->_name,k);
|
|
parameterArrayEntry.nameOffset = CNV2END((int)stringTableAddUnique(stringTable, buffer));
|
|
parameterArrayEntry.flags = CNV2END(structuralElement->_flags);
|
|
unsigned short structureFlag = CGP_STRUCTURE;
|
|
parameterArrayEntry.flags |= CNV2END(structureFlag);
|
|
|
|
unsigned short arrayEntryTypeIndex = (unsigned short)parameterResources.size();
|
|
//RGL_ASSERT2((arrayEntryTypeIndex&3) == 0,("typeindex must be aligned on 4 bytes"));
|
|
parameterResources.resize(arrayEntryTypeIndex+sizeof(CgParameterStructure));
|
|
parameterArrayEntry.typeIndex = CNV2END(arrayEntryTypeIndex);
|
|
|
|
CgParameterStructure *parameterStructure = (CgParameterStructure*)(¶meterResources[arrayEntryTypeIndex]);
|
|
parameterStructure->memberCount = CNV2END((unsigned short)structureType->_elements.size());
|
|
parameterStructure->reserved = CNV2END((unsigned short)0);
|
|
|
|
if (hasDefaults)
|
|
fillStructureItems(containers,structureType,endianness,parameterEntries,parameterResources,stringTable,&_arrayResourceIndex,&_arrayDefaultValueIndex);
|
|
else
|
|
fillStructureItems(containers,structureType,endianness,parameterEntries,parameterResources,stringTable,&_arrayResourceIndex, NULL);
|
|
}
|
|
|
|
if (hasDefaults)
|
|
{
|
|
//should check this value, but it's not really easy, need the entire size of the complex structure in registers
|
|
//unsigned short ArrayBaseTypeCount = _arrayDefaultValueIndex -containers._defaultValuesIndices[currentDefaultIndex*2+1];
|
|
currentDefaultIndex++;
|
|
}
|
|
//containers._defaultValuesIndices[currentDefaultIndex*2] = CNV2END((unsigned short)(parameterEntries.size() - 1));
|
|
//currentDefaultIndex++;
|
|
|
|
|
|
//default value expansion: we have an array of struct: we have one default value index for the array
|
|
//since the array is unrolled we don't give any resource to the array, but instead we give the resource to each item of each structure
|
|
//those items can be arrays or structure themselves
|
|
|
|
//we have already output the content of the array continue to the next structure item
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
//create the type item following the array , the type section will fill typeindex value
|
|
size_t size = parameterEntries.size();
|
|
parameterEntries.resize(size+1);
|
|
parameterEntry = ¶meterEntries[size];
|
|
parameterEntry->nameOffset = CNV2END(0);
|
|
parameterEntry->flags = CNV2END(structuralElement->_flags);
|
|
|
|
//prepare a typeIndex for this type
|
|
typeIndex = ((unsigned short)parameterResources.size());
|
|
//RGL_ASSERT2((typeIndex&3) == 0,("typeindex must be aligned on 4 bytes"));
|
|
parameterEntry->typeIndex = CNV2END(typeIndex);
|
|
|
|
//keep the parameterEntryIndex to assign the default values to the proper item
|
|
parameterEntryIndex = (int)size - 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
unsigned short contiguousFlag = CGP_CONTIGUOUS;
|
|
parameterEntry->flags |= CNV2END(contiguousFlag);
|
|
size_t size = parameterEntries.size();
|
|
parameterEntryIndex = (int)size - 1;
|
|
}
|
|
|
|
if (itemType->_type<128)
|
|
{
|
|
parameterResources.resize(typeIndex+sizeof(CgParameterResource));
|
|
CgParameterResource *parameterResource = (CgParameterResource*)(¶meterResources[typeIndex]);
|
|
|
|
if (itemType->_type + CG_TYPE_START_ENUM == CG_BOOL) // checking _resource == CG_B only works if referenced
|
|
{
|
|
parameterResource->type = CNV2END((unsigned short)CGP_SCF_BOOL);
|
|
}
|
|
else
|
|
{
|
|
parameterResource->type = CNV2END((unsigned short)(itemType->_type + CG_TYPE_START_ENUM));
|
|
}
|
|
|
|
if ((structuralElement->_flags & CGPV_MASK) == CGPV_UNIFORM || (structuralElement->_flags & CGPV_MASK) == CGPV_CONSTANT)
|
|
{
|
|
//use the resource index of the array if we are in an array: pbl with arrays containing samplers...
|
|
if (itemType->_type +CG_TYPE_START_ENUM >= CG_SAMPLER1D && itemType->_type +CG_TYPE_START_ENUM<= CG_SAMPLERCUBE)
|
|
parameterResource->resource = CNV2END(_resource); //sampler we need the texture unit
|
|
else
|
|
{
|
|
if (arrayResourceIndex)
|
|
{
|
|
unsigned short tmp = *arrayResourceIndex;
|
|
unsigned short localflags = CNV2END(parameterEntry->flags);
|
|
if (!bIsVertexProgram)
|
|
{
|
|
parameterResource->resource = CNV2END(tmp);
|
|
int embeddedConstantCount = CNV2END(containers._resources[tmp+1]);
|
|
(*arrayResourceIndex) = tmp+1+1+embeddedConstantCount;
|
|
if (embeddedConstantCount == 0 && (CNV2END(containers._resources[tmp]) == 0))
|
|
{
|
|
//we are unrolling an array of struct, so we get individual items
|
|
//we should mark if they are referenced individually
|
|
if (parameterResource->resource == 0xffff)
|
|
localflags &= ~CGPF_REFERENCED;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
parameterResource->resource = containers._resources[tmp];//_resources is already converted
|
|
(*arrayResourceIndex) = tmp+1;
|
|
|
|
//we are unrolling an array of struct, so we get individual items
|
|
//we should mark if they are referenced individually
|
|
if (parameterResource->resource == 0xffff)
|
|
localflags &= ~CGPF_REFERENCED;
|
|
}
|
|
//update the flags
|
|
parameterEntry->flags = CNV2END(localflags);
|
|
}
|
|
else
|
|
parameterResource->resource = CNV2END(_resourceIndex); //uniform not a sampler we need the register
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//RGL_ASSERT2((structuralElement->_flags & CGPV_MASK) == CGPV_VARYING,("assumed varying"));
|
|
//RGL_ASSERT2(arrayResourceIndex == NULL,("varying within array of structures not yet supported"));
|
|
parameterResource->resource = CNV2END(itemType->_resource); //we need the bind location for the varying
|
|
}
|
|
|
|
if (containers._defaultValuesIndices.size())
|
|
{
|
|
if (structure->_root)
|
|
{
|
|
//TODO: what about default values on structures at the root level, the structure will flatten out so the default should go on the individual items
|
|
//but they are not at root so the indices cannot be represented right now I guess.
|
|
//semantics and default values indices need to be updated:
|
|
//we are trying to find the index in the sorted array of default value indices, if we are already at the end of the array we stop here
|
|
if (currentDefaultIndex < (int)(containers._defaultValuesIndices.size()/2) && containers._defaultValuesIndices[currentDefaultIndex*2] == CNV2END((unsigned short)i))
|
|
{
|
|
containers._elfDefaultsIndices.push_back(CNV2END((unsigned short)(parameterEntryIndex)));
|
|
containers._elfDefaultsIndices.push_back(containers._defaultValuesIndices[currentDefaultIndex*2+1]);
|
|
//containers._defaultValuesIndices[currentDefaultIndex*2] = CNV2END((unsigned short)(parameterEntries.size() - 1));
|
|
currentDefaultIndex++;
|
|
}
|
|
}
|
|
else if (arrayDefaultValueIndex)
|
|
{
|
|
//we are in a struct or in an array of struct which has a top level default, each time we have a basic type we need to increase
|
|
//the index
|
|
|
|
containers._elfDefaultsIndices.push_back(CNV2END((unsigned short)(parameterEntryIndex)));
|
|
containers._elfDefaultsIndices.push_back(*arrayDefaultValueIndex);
|
|
//increment the default values index by the number of defaultValues slot used by this type
|
|
|
|
int typeRegisterCount = getStride(itemType);
|
|
*arrayDefaultValueIndex = CNV2END( (unsigned short)((CNV2END((*arrayDefaultValueIndex)))+typeRegisterCount*4));
|
|
|
|
//no handling of the currentDefaultIndex, which is only valid at root.
|
|
}
|
|
}
|
|
}
|
|
else if (itemType->_type == CG_STRUCT + 128)
|
|
{
|
|
//RGL_ASSERT2(arrayResourceIndex == NULL,("struct within array of structures not yet supported"));
|
|
unsigned short structureFlag = CGP_STRUCTURE;
|
|
parameterEntry->flags |= CNV2END(structureFlag);
|
|
|
|
CgStructureType *structureType = (CgStructureType*)itemType;
|
|
parameterResources.resize(typeIndex+sizeof(CgParameterStructure));
|
|
CgParameterStructure *parameterStructure = (CgParameterStructure*)(¶meterResources[typeIndex]);
|
|
parameterStructure->memberCount = CNV2END((unsigned short)structureType->_elements.size());
|
|
parameterStructure->reserved = CNV2END((unsigned short)0);
|
|
|
|
fillStructureItems(containers,structureType,endianness,parameterEntries,parameterResources,stringTable, NULL, NULL);
|
|
|
|
if (containers._defaultValuesIndices.size() && structure->_root)
|
|
{
|
|
if (currentDefaultIndex < (int)(containers._defaultValuesIndices.size()/2) && containers._defaultValuesIndices[currentDefaultIndex*2] == CNV2END((unsigned short)i))
|
|
{
|
|
containers._elfDefaultsIndices.push_back(CNV2END((unsigned short)(parameterEntryIndex)));
|
|
containers._elfDefaultsIndices.push_back(containers._defaultValuesIndices[currentDefaultIndex*2+1]);
|
|
currentDefaultIndex++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//RGL_ASSERT2(!structure->_root || currentDefaultIndex == (int)containers._defaultValuesIndices.size()/2,("error\n"));
|
|
}
|
|
|
|
|
|
static int getStride(CgBaseType *type)
|
|
{
|
|
if (type->_type <128)
|
|
{
|
|
if (classnames[type->_type-1] == CG_PARAMETERCLASS_MATRIX)
|
|
return rows[type->_type-1];
|
|
else
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
if (type->_type == CG_STRUCT + 128)
|
|
{
|
|
CgStructureType *structureType = (CgStructureType *)type;
|
|
int res = 0;
|
|
int i;
|
|
int count = (int)structureType->_elements.size();
|
|
for (i=0;i<count;i++)
|
|
res += getStride(structureType->_elements[i]._type);
|
|
return res;
|
|
}
|
|
else
|
|
{
|
|
//RGL_ASSERT2(0,("arrays of arrays not supported"));
|
|
return -9999999;
|
|
}
|
|
//if array ??
|
|
}
|
|
}
|
|
|
|
static int getSizeofSubArray(_CGNVCONTAINERS &containers, int dimensionIndex, int dimensionCount, int endianness)
|
|
{
|
|
unsigned char elfEndianness = endianness; //used in the macro CNVEND
|
|
int res = 1;
|
|
int i;
|
|
for ( i=0; i < dimensionCount; i++)
|
|
res *= (int)CNV2END(containers._dimensions[dimensionIndex + i]);
|
|
return res;
|
|
}
|
|
|
|
|
|
|
|
unsigned short getFlags(CGenum var, CGenum dir, int no, bool is_referenced, bool is_shared, int paramIndex)
|
|
{
|
|
//the following is error prone, use 2 enum array to do the matching instead
|
|
//variability
|
|
uint16_t flags = 0;
|
|
if (var == CG_VARYING)
|
|
flags |= CGPV_VARYING;
|
|
else if (var == CG_UNIFORM)
|
|
flags |= CGPV_UNIFORM;
|
|
else if (var == CG_CONSTANT)
|
|
flags |= CGPV_CONSTANT;
|
|
else if (var == CG_MIXED)
|
|
flags |= CGPV_MIXED;
|
|
|
|
//direction
|
|
if (dir == CG_IN)
|
|
flags |= CGPD_IN;
|
|
else if (dir == CG_OUT)
|
|
flags |= CGPD_OUT;
|
|
else if (dir == CG_INOUT)
|
|
flags |= CGPD_INOUT;
|
|
|
|
//boolean
|
|
if (is_referenced)
|
|
flags |= CGPF_REFERENCED;
|
|
|
|
//is it a global parameter ?
|
|
if (no == -1)
|
|
flags |= CGPF_GLOBAL;
|
|
else if (no == -2)
|
|
flags |= CGP_INTERNAL;
|
|
else
|
|
{
|
|
//RGL_ASSERT2(no>=0,("error\n"));
|
|
/*if ( no == paramIndex ) //means that a previous parameter already had the same param index, it's an aggregated type
|
|
flags |= CGP_AGGREGATED;*/
|
|
paramIndex = no;
|
|
}
|
|
return flags;
|
|
}
|
|
|
|
/*============================================================
|
|
CGBIO
|
|
============================================================ */
|
|
|
|
namespace cgc {
|
|
namespace bio {
|
|
|
|
bin_io* bin_io::instance_ = 0;
|
|
|
|
bin_io::bin_io()
|
|
{
|
|
}
|
|
|
|
bin_io::bin_io( const bin_io& )
|
|
{
|
|
}
|
|
|
|
const bin_io*
|
|
bin_io::instance()
|
|
{
|
|
if (instance_ == 0)
|
|
instance_ = new bin_io;
|
|
return instance_;
|
|
}
|
|
|
|
void
|
|
bin_io::delete_instance()
|
|
{
|
|
if (instance_ != 0)
|
|
{
|
|
free(instance_);
|
|
instance_ = 0;
|
|
}
|
|
}
|
|
|
|
const char*
|
|
bin_io::error_string( CGBIO_ERROR error ) const
|
|
{
|
|
switch ( error )
|
|
{
|
|
case CGBIO_ERROR_NO_ERROR:
|
|
return "No error";
|
|
case CGBIO_ERROR_LOADED:
|
|
return "Binary file has been loaded earlier";
|
|
case CGBIO_ERROR_FILEIO:
|
|
return "File input output error";
|
|
case CGBIO_ERROR_FORMAT:
|
|
return "File format error";
|
|
case CGBIO_ERROR_INDEX:
|
|
return "Index is out of range";
|
|
case CGBIO_ERROR_MEMORY:
|
|
return "Can't allocate memory";
|
|
case CGBIO_ERROR_RELOC:
|
|
return "Relocation error";
|
|
case CGBIO_ERROR_SYMBOL:
|
|
return "Symbol error";
|
|
case CGBIO_ERROR_UNKNOWN_TYPE:
|
|
return "Uknown type";
|
|
default:
|
|
return "Unknown error";
|
|
}
|
|
return "Unknown error";
|
|
}
|
|
|
|
CGBIO_ERROR
|
|
bin_io::new_nvb_reader( nvb_reader** obj ) const
|
|
{
|
|
CGBIO_ERROR ret = CGBIO_ERROR_NO_ERROR;
|
|
*obj = new nvb_reader_impl;
|
|
if (*obj == 0)
|
|
ret = CGBIO_ERROR_MEMORY;
|
|
return ret;
|
|
}
|
|
} // bio namespace
|
|
} // cgc namespace
|
|
|
|
using std::fill_n;
|
|
|
|
/*============================================================
|
|
NVBI IMPLEMENTATION
|
|
============================================================ */
|
|
|
|
namespace cgc {
|
|
namespace bio {
|
|
|
|
nvb_reader_impl::nvb_reader_impl()
|
|
{
|
|
ref_count_ = 1;
|
|
offset_ = 0;
|
|
image_ = 0;
|
|
owner_ = false;
|
|
loaded_ = false;
|
|
endianness_ = host_endianness();
|
|
std::fill_n( (char*)( &header_ ), sizeof( header_ ), '\0' );
|
|
}
|
|
|
|
nvb_reader_impl::~nvb_reader_impl()
|
|
{
|
|
if (image_ != 0)
|
|
free(image_);
|
|
}
|
|
|
|
ptrdiff_t
|
|
nvb_reader_impl::reference() const
|
|
{
|
|
return ++ref_count_;
|
|
}
|
|
|
|
ptrdiff_t
|
|
nvb_reader_impl::release() const
|
|
{
|
|
ptrdiff_t ret = --ref_count_;
|
|
if (ref_count_ == 0)
|
|
delete this;
|
|
return ret;
|
|
}
|
|
|
|
CGBIO_ERROR
|
|
nvb_reader_impl::loadFromString( const char* source, size_t length)
|
|
{
|
|
if ( loaded_ )
|
|
return CGBIO_ERROR_LOADED;
|
|
|
|
CGBIO_ERROR ret = CGBIO_ERROR_NO_ERROR;
|
|
while (1)
|
|
{
|
|
if (length < sizeof( header_ ))
|
|
{
|
|
ret = CGBIO_ERROR_FORMAT;
|
|
break;
|
|
}
|
|
memcpy(&header_ ,source,sizeof( header_ ));
|
|
if ( CG_BINARY_FORMAT_REVISION != header_.binaryFormatRevision )
|
|
{
|
|
endianness_ = ( CGBIODATALSB == endianness_ ) ? CGBIODATAMSB : CGBIODATALSB;
|
|
int binaryRevision = convert_endianness( header_.binaryFormatRevision, endianness_ );
|
|
if ( CG_BINARY_FORMAT_REVISION != binaryRevision )
|
|
{
|
|
ret = CGBIO_ERROR_FORMAT;
|
|
break;
|
|
}
|
|
}
|
|
image_ = (char*)malloc(length * sizeof(char));
|
|
memcpy(image_, source , length);
|
|
loaded_ = true;
|
|
ret = CGBIO_ERROR_NO_ERROR;
|
|
break;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
bool
|
|
nvb_reader_impl::is_loaded() const
|
|
{
|
|
return loaded_;
|
|
}
|
|
|
|
unsigned char
|
|
nvb_reader_impl::endianness() const
|
|
{
|
|
return endianness_;
|
|
}
|
|
|
|
CGprofile
|
|
nvb_reader_impl::profile() const
|
|
{
|
|
return (CGprofile) convert_endianness( (unsigned int) header_.profile, endianness() );
|
|
}
|
|
|
|
unsigned int
|
|
nvb_reader_impl::revision() const
|
|
{
|
|
return convert_endianness( header_.binaryFormatRevision, endianness() );
|
|
}
|
|
|
|
unsigned int
|
|
nvb_reader_impl::size() const
|
|
{
|
|
return convert_endianness( header_.totalSize, endianness() );
|
|
}
|
|
|
|
unsigned int
|
|
nvb_reader_impl::number_of_params() const
|
|
{
|
|
return convert_endianness( header_.parameterCount, endianness() );
|
|
}
|
|
|
|
unsigned int
|
|
nvb_reader_impl::ucode_size() const
|
|
{
|
|
return convert_endianness( header_.ucodeSize, endianness() );
|
|
}
|
|
|
|
const char*
|
|
nvb_reader_impl::ucode() const
|
|
{
|
|
if (image_ == 0 || ucode_size() == 0)
|
|
return 0;
|
|
return ( image_ + convert_endianness( header_.ucode, endianness() ) );
|
|
}
|
|
|
|
const CgBinaryFragmentProgram*
|
|
nvb_reader_impl::fragment_program() const
|
|
{
|
|
if (image_ == 0)
|
|
return 0;
|
|
return (CgBinaryFragmentProgram*)( &image_[convert_endianness( header_.program, endianness_ )] );
|
|
}
|
|
|
|
const CgBinaryVertexProgram*
|
|
nvb_reader_impl::vertex_program() const
|
|
{
|
|
if (image_ == 0)
|
|
return 0;
|
|
return (CgBinaryVertexProgram*)( &image_[convert_endianness( header_.program, endianness_ )] );
|
|
}
|
|
|
|
CGBIO_ERROR
|
|
nvb_reader_impl::get_param_name( unsigned int index, const char **name, bool& is_referenced ) const
|
|
{
|
|
if (index >= number_of_params())
|
|
return CGBIO_ERROR_INDEX;
|
|
|
|
if (image_ == 0)
|
|
return CGBIO_ERROR_NO_ERROR;
|
|
|
|
const CgBinaryParameter* params = (CgBinaryParameter*)( &image_[convert_endianness( header_.parameterArray, endianness_ )] );
|
|
const CgBinaryParameter& pp = params[index];
|
|
is_referenced = convert_endianness( pp.isReferenced, endianness() ) != 0;
|
|
CgBinaryStringOffset nm_offset = convert_endianness( pp.name,endianness() );
|
|
if (nm_offset != 0)
|
|
*name = &image_[nm_offset];
|
|
else
|
|
*name = "";
|
|
return CGBIO_ERROR_NO_ERROR;
|
|
}
|
|
|
|
CGBIO_ERROR
|
|
nvb_reader_impl::get_param( unsigned int index,
|
|
CGtype& type,
|
|
CGresource& resource,
|
|
CGenum& variability,
|
|
int& resource_index,
|
|
const char ** name,
|
|
std::vector<float>& default_value,
|
|
std::vector<unsigned int>& embedded_constants,
|
|
const char ** semantic,
|
|
CGenum& direction,
|
|
int& paramno,
|
|
bool& is_referenced,
|
|
bool& is_shared ) const
|
|
{
|
|
if (index >= number_of_params())
|
|
return CGBIO_ERROR_INDEX;
|
|
|
|
if (image_ == 0)
|
|
return CGBIO_ERROR_NO_ERROR;
|
|
|
|
const CgBinaryParameter* params = (CgBinaryParameter*)( &image_[convert_endianness( header_.parameterArray, endianness_ )] );
|
|
const CgBinaryParameter& pp = params[index];
|
|
type = static_cast<CGtype>( convert_endianness( static_cast<unsigned int>( pp.type ), endianness() ) );
|
|
resource = static_cast<CGresource>( convert_endianness( static_cast<unsigned int>( pp.res ), endianness() ) );
|
|
variability = static_cast<CGenum>( convert_endianness( static_cast<unsigned int>( pp.var ), endianness() ) );
|
|
resource_index = convert_endianness( pp.resIndex, endianness() );
|
|
direction = static_cast<CGenum>( convert_endianness( static_cast<unsigned int>( pp.direction ), endianness() ) );
|
|
paramno = convert_endianness( pp.paramno, endianness() );
|
|
is_referenced = convert_endianness( pp.isReferenced, endianness() ) != 0;
|
|
is_shared = false;
|
|
CgBinaryStringOffset nm_offset = convert_endianness( pp.name, endianness() );
|
|
CgBinaryFloatOffset dv_offset = convert_endianness( pp.defaultValue, endianness() );
|
|
CgBinaryEmbeddedConstantOffset ec_offset = convert_endianness( pp.embeddedConst, endianness() );
|
|
CgBinaryStringOffset sm_offset = convert_endianness( pp.semantic, endianness() );
|
|
if (nm_offset != 0)
|
|
*name = &image_[nm_offset];
|
|
else
|
|
*name = "";
|
|
|
|
if (sm_offset != 0)
|
|
*semantic = &image_[sm_offset];
|
|
else
|
|
*semantic = "";
|
|
if (dv_offset != 0)
|
|
{
|
|
char *vp = &image_[dv_offset];
|
|
for (int ii = 0; ii < 4; ++ii)
|
|
{
|
|
int tmp;
|
|
memcpy(&tmp,vp+4*ii,4);
|
|
tmp = convert_endianness(tmp,endianness());
|
|
float tmp2;
|
|
memcpy(&tmp2,&tmp,4);
|
|
default_value.push_back( tmp2 );
|
|
}
|
|
}
|
|
if (ec_offset != 0)
|
|
{
|
|
void *vp = &image_[ec_offset];
|
|
CgBinaryEmbeddedConstant& ec = *(static_cast<CgBinaryEmbeddedConstant*>( vp ));
|
|
for (unsigned int ii = 0; ii < convert_endianness( ec.ucodeCount, endianness() ); ++ii)
|
|
{
|
|
unsigned int offset = convert_endianness( ec.ucodeOffset[ii], endianness() );
|
|
embedded_constants.push_back( offset );
|
|
}
|
|
}
|
|
return CGBIO_ERROR_NO_ERROR;
|
|
}
|
|
|
|
|
|
}
|
|
}
|