RetroArch/console/rgl/ps3/rgl.cpp
2012-08-15 13:15:12 +02:00

8184 lines
278 KiB
C++

#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <math.h>
#include <float.h>
#include <cell/gcm.h>
#include <sys/sys_time.h>
#include "rgl.h"
#include "private.h"
#include <ppu_intrinsics.h>
#include "cg.h"
#include <Cg/cgc.h>
#include <Cg/cgGL.h>
#include "readelf.h"
#include "cgnv2rt.h"
#include <cell/sysmodule.h>
#include "../../../compat/strl.h"
#include "../../../general.h"
#define ENDIAN_32(X, F) ((F) ? endianSwapWord(X) : (X))
#define SWAP_IF_BIG_ENDIAN(arg) endianSwapWordByHalf(arg)
#define ROW_MAJOR 0
#define COL_MAJOR 1
#define pad(x, pad) (((x) + (pad) - 1 ) / (pad) * (pad))
#define GL_UNSIGNED_SHORT_8_8 GL_UNSIGNED_SHORT_8_8_SCE
#define GL_UNSIGNED_SHORT_8_8_REV GL_UNSIGNED_SHORT_8_8_REV_SCE
#define GL_UNSIGNED_INT_16_16 GL_UNSIGNED_INT_16_16_SCE
#define GL_UNSIGNED_INT_16_16_REV GL_UNSIGNED_INT_16_16_REV_SCE
#define DECLARE_C_TYPES \
DECLARE_TYPE(GL_BYTE,GLbyte,127.f) \
DECLARE_TYPE(GL_UNSIGNED_BYTE,GLubyte,255.f) \
DECLARE_TYPE(GL_SHORT,GLshort,32767.f) \
DECLARE_TYPE(GL_UNSIGNED_SHORT,GLushort,65535.f) \
DECLARE_TYPE(GL_INT,GLint,2147483647.f) \
DECLARE_TYPE(GL_UNSIGNED_INT,GLuint,4294967295.0) \
DECLARE_TYPE(GL_FIXED,GLfixed,65535.f)
#define DECLARE_UNPACKED_TYPES \
DECLARE_UNPACKED_TYPE(GL_BYTE) \
DECLARE_UNPACKED_TYPE(GL_UNSIGNED_BYTE) \
DECLARE_UNPACKED_TYPE(GL_SHORT) \
DECLARE_UNPACKED_TYPE(GL_UNSIGNED_SHORT) \
DECLARE_UNPACKED_TYPE(GL_INT) \
DECLARE_UNPACKED_TYPE(GL_UNSIGNED_INT) \
DECLARE_UNPACKED_TYPE(GL_HALF_FLOAT_ARB) \
DECLARE_UNPACKED_TYPE(GL_FLOAT) \
DECLARE_UNPACKED_TYPE(GL_FIXED)
#define DECLARE_PACKED_TYPES \
DECLARE_PACKED_TYPE_AND_REV_2(UNSIGNED_BYTE,4,4) \
DECLARE_PACKED_TYPE_AND_REV_2(UNSIGNED_BYTE,6,2) \
DECLARE_PACKED_TYPE_AND_REV_3(UNSIGNED_BYTE,3,3,2) \
DECLARE_PACKED_TYPE_AND_REV_4(UNSIGNED_BYTE,2,2,2,2) \
DECLARE_PACKED_TYPE_AND_REV_2(UNSIGNED_SHORT,12,4) \
DECLARE_PACKED_TYPE_AND_REV_2(UNSIGNED_SHORT,8,8) \
DECLARE_PACKED_TYPE_AND_REV_3(UNSIGNED_SHORT,5,6,5) \
DECLARE_PACKED_TYPE_AND_REV_4(UNSIGNED_SHORT,4,4,4,4) \
DECLARE_PACKED_TYPE_AND_REV_4(UNSIGNED_SHORT,5,5,5,1) \
DECLARE_PACKED_TYPE_AND_REV_2(UNSIGNED_INT,16,16) \
DECLARE_PACKED_TYPE_AND_REV_4(UNSIGNED_INT,8,8,8,8) \
DECLARE_PACKED_TYPE_AND_REV_4(UNSIGNED_INT,10,10,10,2)
#define DECLARE_FORMATS \
DECLARE_FORMAT(GL_RGB,3) \
DECLARE_FORMAT(GL_BGR,3) \
DECLARE_FORMAT(GL_RGBA,4) \
DECLARE_FORMAT(GL_BGRA,4) \
DECLARE_FORMAT(GL_ABGR,4) \
DECLARE_FORMAT(GL_ARGB_SCE,4) \
DECLARE_FORMAT(GL_RED,1) \
DECLARE_FORMAT(GL_GREEN,1) \
DECLARE_FORMAT(GL_BLUE,1) \
DECLARE_FORMAT(GL_ALPHA,1)
static int _RGLInitCompleted = 0;
static char *_RGLVendorString = "Retro Arch";
static char *_RGLRendererString = "RGL";
static char *_RGLExtensionsString = "";
static char *_RGLVersionNumber = "1.0";
PSGLcontext* _CurrentContext = NULL;
RGLcontextHookFunction _RGLContextCreateHook = NULL;
RGLcontextHookFunction _RGLContextDestroyHook = NULL;
GmmAllocator *pGmmLocalAllocator = NULL;
GmmAllocator *pGmmMainAllocator = NULL;
static volatile uint32_t *pLock = NULL;
static uint32_t cachedLockValue = 0;
static GmmFixedAllocData *pGmmFixedAllocData = NULL;
GLuint nvFenceCounter = 0;
#define CAPACITY_INCR 16
#define NAME_INCREMENT 4
#define DECLARE_TYPE(TYPE,CTYPE,MAXVAL) \
typedef CTYPE type_##TYPE; \
static inline type_##TYPE _RGLFloatTo_##TYPE(float v) { return (type_##TYPE)((MAX(MIN(v, 1.f), 0.f)) * MAXVAL); } \
static inline float _RGLFloatFrom_##TYPE(type_##TYPE v) { return ((float)v)/MAXVAL; }
DECLARE_C_TYPES
#undef DECLARE_TYPE
typedef GLfloat type_GL_FLOAT;
static inline type_GL_FLOAT _RGLFloatTo_GL_FLOAT(float v)
{
return v;
}
static inline float _RGLFloatFrom_GL_FLOAT(type_GL_FLOAT v)
{
return v;
}
typedef GLhalfARB type_GL_HALF_FLOAT_ARB;
static const char *findSectionInPlace(const char* memory,unsigned int /*size*/,const char *name, size_t *sectionSize)
{
const Elf32_Ehdr *ehdr = (const Elf32_Ehdr*)memory;
const char *sectionHeaderStart = (const char*)ehdr + ehdr->e_shoff;
const Elf32_Shdr *shstrtabHeader = (const Elf32_Shdr*)sectionHeaderStart + ehdr->e_shstrndx;
const char *shstrtab = (const char*)ehdr + shstrtabHeader->sh_offset;
size_t sectionCount = ehdr->e_shnum;
for(size_t i=0; i < sectionCount; i++)
{
const Elf32_Shdr *sectionHeader = (const Elf32_Shdr *)sectionHeaderStart + i;
const char *sectionName = shstrtab + sectionHeader->sh_name;
if (!strcmp(name,sectionName))
{
*sectionSize = sectionHeader->sh_size;
return (const char*)ehdr + sectionHeader->sh_offset;
}
}
return NULL;
}
static const char *findSymbolSectionInPlace(const char *memory, unsigned int /*size*/, size_t *symbolSize, size_t *symbolCount, const char **symbolstrtab)
{
const Elf32_Ehdr *ehdr = (const Elf32_Ehdr*)memory;
size_t sectionCount = ehdr->e_shnum;
const char *sectionHeaderStart = (const char*)ehdr + ehdr->e_shoff;
for(size_t i = 0; i<sectionCount; i++)
{
const Elf32_Shdr *sectionHeader = (const Elf32_Shdr *)sectionHeaderStart + i;
if (sectionHeader->sh_type == SHT_SYMTAB)
{
*symbolSize = sectionHeader->sh_entsize;
*symbolCount = sectionHeader->sh_size / sectionHeader->sh_entsize;
const Elf32_Shdr *symbolStrHeader = (const Elf32_Shdr *)sectionHeaderStart + sectionHeader->sh_link;
*symbolstrtab = (const char*)ehdr + symbolStrHeader->sh_offset;
return (const char*)ehdr + sectionHeader->sh_offset;
}
}
return NULL;
}
static int lookupSymbolValueInPlace(const char* symbolSection, size_t symbolSize, size_t symbolCount, const char *symbolstrtab, const char *name)
{
for (size_t i = 0; i < symbolCount; i++)
{
Elf32_Sym* elf_sym = (Elf32_Sym*)symbolSection;
if (!strcmp(symbolstrtab + elf_sym->st_name, name))
return elf_sym->st_value;
symbolSection += symbolSize;
}
return -1;
}
static const char *getSymbolByIndexInPlace(const char* symbolSection, size_t symbolSize, size_t symbolCount, const char *symbolstrtab, int index)
{
Elf32_Sym* elf_sym = (Elf32_Sym*)symbolSection + index;
return symbolstrtab + elf_sym->st_name;
}
static inline type_GL_HALF_FLOAT_ARB _RGLFloatTo_GL_HALF_FLOAT_ARB( float x )
{
jsIntAndFloat V = {f: x};
unsigned int S = ( V.i >> 31 ) & 1;
int E = (( V.i >> 23 ) & 0xff ) - 0x7f;
unsigned int M = V.i & 0x007fffff;
if (( E == 0x80 ) && ( M ) ) return 0x7fff;
else if ( E >= 15 ) return( S << 15 ) | 0x7c00;
else if ( E <= -14 ) return( S << 15 ) | (( 0x800000 + M ) >> ( -14 - E ) );
else return( S << 15 ) | ((( E + 15 )&0x1f ) << 10 ) | ( M >> 13 );
}
static inline float _RGLFloatFrom_GL_HALF_FLOAT_ARB( type_GL_HALF_FLOAT_ARB x )
{
unsigned int S = x >> 15;
unsigned int E = ( x & 0x7C00 ) >> 10;
unsigned int M = x & 0x03ff;
float f;
if ( E == 31 )
{
if ( M == 0 ) f = _RGLInfinity.f;
else f = _RGLNan.f;
}
else if ( E == 0 )
{
if ( M == 0 ) f = 0.f;
else f = M * 1.f / ( 1 << 24 );
}
else f = ( 0x400 + M ) * 1.f / ( 1 << 25 ) * ( 1 << E );
return S ? -f : f;
}
#define DECLARE_PACKED_TYPE_AND_REV_2(REALTYPE,S1,S2) \
DECLARE_PACKED_TYPE(GL_##REALTYPE,GL_##REALTYPE##_##S1##_##S2,2,S1,S2,0,0,) \
DECLARE_PACKED_TYPE(GL_##REALTYPE,GL_##REALTYPE##_##S2##_##S1##_REV,2,S2,S1,0,0,_REV)
#define DECLARE_PACKED_TYPE_AND_REV_3(REALTYPE,S1,S2,S3) \
DECLARE_PACKED_TYPE(GL_##REALTYPE,GL_##REALTYPE##_##S1##_##S2##_##S3,3,S1,S2,S3,0,) \
DECLARE_PACKED_TYPE(GL_##REALTYPE,GL_##REALTYPE##_##S3##_##S2##_##S1##_REV,3,S3,S2,S1,0,_REV)
#define DECLARE_PACKED_TYPE_AND_REV_4(REALTYPE,S1,S2,S3,S4) \
DECLARE_PACKED_TYPE(GL_##REALTYPE,GL_##REALTYPE##_##S1##_##S2##_##S3##_##S4,4,S1,S2,S3,S4,) \
DECLARE_PACKED_TYPE(GL_##REALTYPE,GL_##REALTYPE##_##S4##_##S3##_##S2##_##S1##_REV,4,S4,S3,S2,S1,_REV)
#define DECLARE_PACKED_TYPE_AND_REALTYPE(REALTYPE,N,S1,S2,S3,S4,REV) \
DECLARE_PACKED_TYPE(GL_##REALTYPE,PACKED_TYPE(REALTYPE,N,S1,S2,S3,S4,REV),N,S1,S2,S3,S4,REV)
#define INDEX(N,X) (X)
#define INDEX_REV(N,X) (N-1-X)
#define GET_BITS(to,from,first,count) if ((count)>0) to=((GLfloat)(((from)>>(first))&((1<<(count))-1)))/(GLfloat)((1<<((count==0)?1:count))-1)
#define PUT_BITS(from,to,first,count) if ((count)>0) to|=((unsigned int)((from)*((GLfloat)((1<<((count==0)?1:count))-1))))<<(first);
static void _RGLResetAttributeState( jsAttributeState* as )
{
for(int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
{
as->attrib[i].clientSize = 4;
as->attrib[i].clientType = GL_FLOAT;
as->attrib[i].clientStride = 16;
as->attrib[i].clientData = NULL;
as->attrib[i].value[0] = 0.0f;
as->attrib[i].value[1] = 0.0f;
as->attrib[i].value[2] = 0.0f;
as->attrib[i].value[3] = 1.0f;
as->attrib[i].normalized = GL_FALSE;
as->attrib[i].frequency = 1;
as->attrib[i].arrayBuffer = 0;
}
as->attrib[_RGL_ATTRIB_PRIMARY_COLOR_INDEX].value[0] = 1.0f;
as->attrib[_RGL_ATTRIB_PRIMARY_COLOR_INDEX].value[1] = 1.0f;
as->attrib[_RGL_ATTRIB_PRIMARY_COLOR_INDEX].value[2] = 1.0f;
as->attrib[_RGL_ATTRIB_PRIMARY_COLOR_INDEX].value[3] = 1.0f;
as->attrib[_RGL_ATTRIB_SECONDARY_COLOR_INDEX].value[0] = 1.0f;
as->attrib[_RGL_ATTRIB_SECONDARY_COLOR_INDEX].value[1] = 1.0f;
as->attrib[_RGL_ATTRIB_SECONDARY_COLOR_INDEX].value[2] = 1.0f;
as->attrib[_RGL_ATTRIB_SECONDARY_COLOR_INDEX].value[3] = 1.0f;
as->attrib[_RGL_ATTRIB_NORMAL_INDEX].value[0] = 0.f;
as->attrib[_RGL_ATTRIB_NORMAL_INDEX].value[1] = 0.f;
as->attrib[_RGL_ATTRIB_NORMAL_INDEX].value[2] = 1.f;
as->DirtyMask = (1 << MAX_VERTEX_ATTRIBS) - 1;
as->EnabledMask = 0;
as->NeedsConversionMask = 0;
as->HasVBOMask = 0;
as->ModuloMask = 0;
}
static jsAttribSet* _RGLCreateAttribSet( void )
{
jsAttribSet* attribSet = (jsAttribSet*)memalign(16, sizeof(jsAttribSet));
_RGLResetAttributeState(&attribSet->attribs);
attribSet->dirty = GL_TRUE;
attribSet->beenUpdatedMask = 0;
attribSet->cmdBuffer = NULL;
attribSet->cmdNumWords = 0;
return attribSet;
}
static void _RGLDestroyAttribSet( jsAttribSet* attribSet )
{
if ( attribSet->cmdBuffer )
free( attribSet->cmdBuffer );
free( attribSet );
}
static void _RGLAttribSetDeleteBuffer( PSGLcontext *LContext, GLuint buffName )
{
jsBufferObject *bufferObject = ( jsBufferObject * )LContext->bufferObjectNameSpace.data[buffName];
GLuint attrSetCount = bufferObject->attribSets.getCount();
if ( attrSetCount == 0 ) return;
for ( unsigned int i = 0;i < attrSetCount;++i )
{
jsAttribSet *attribSet = bufferObject->attribSets[i];
for(GLuint j = 0; j < MAX_VERTEX_ATTRIBS; ++j)
{
if(attribSet->attribs.attrib[j].arrayBuffer == buffName)
attribSet->attribs.attrib[j].arrayBuffer = 0;
}
attribSet->dirty = GL_TRUE;
}
LContext->attribSetDirty = GL_TRUE;
bufferObject->attribSets.clear();
}
static jsBufferObject *_RGLCreateBufferObject (void)
{
GLuint size = sizeof(jsBufferObject) + sizeof(RGLBufferObject);
jsBufferObject *buffer = (jsBufferObject*)malloc(size);
if( !buffer )
return NULL;
memset(buffer, 0, size);
buffer->refCount = 1;
new( &buffer->textureReferences ) RGL::Vector<jsTexture *>();
new( &buffer->attribSets ) RGL::Vector<jsAttribSet *>();
return buffer;
}
static void _RGLPlatformDestroyBufferObject( jsBufferObject* bufferObject )
{
RGLBufferObject *jsBuffer = (RGLBufferObject*)bufferObject->platformBufferObject;
switch(jsBuffer->pool)
{
case SURFACE_POOL_SYSTEM:
case SURFACE_POOL_LINEAR:
gmmFree( jsBuffer->bufferId );
break;
case SURFACE_POOL_NONE:
break;
default:
break;
}
jsBuffer->pool = SURFACE_POOL_NONE;
jsBuffer->bufferId = GMM_ERROR;
}
static void _RGLFreeBufferObject( jsBufferObject *buffer )
{
if(--buffer->refCount == 0)
{
_RGLPlatformDestroyBufferObject( buffer );
buffer->textureReferences.~Vector<jsTexture *>();
buffer->attribSets.~Vector<jsAttribSet *>();
if(buffer != NULL)
free( buffer );
}
}
GLAPI void APIENTRY glBindBuffer( GLenum target, GLuint name )
{
PSGLcontext *LContext = _CurrentContext;
if(name)
_RGLTexNameSpaceCreateNameLazy( &LContext->bufferObjectNameSpace, name );
switch(target)
{
case GL_ARRAY_BUFFER:
LContext->ArrayBuffer = name;
break;
case GL_ELEMENT_ARRAY_BUFFER:
break;
case GL_PIXEL_PACK_BUFFER_ARB:
break;
case GL_PIXEL_UNPACK_BUFFER_ARB:
LContext->PixelUnpackBuffer = name;
break;
case GL_TEXTURE_REFERENCE_BUFFER_SCE:
LContext->TextureBuffer = name;
break;
default:
break;
}
}
GLAPI void APIENTRY glDeleteBuffers(GLsizei n, const GLuint *buffers)
{
PSGLcontext *LContext = _CurrentContext;
for(int i = 0; i < n; ++i)
{
if(!_RGLTexNameSpaceIsName( &LContext->bufferObjectNameSpace, buffers[i] ) )
continue;
if(buffers[i] )
{
GLuint name = buffers[i];
if(LContext->ArrayBuffer == name)
LContext->ArrayBuffer = 0;
if(LContext->PixelUnpackBuffer == name)
LContext->PixelUnpackBuffer = 0;
for(int i = 0;i < MAX_VERTEX_ATTRIBS; ++i)
{
if(LContext->attribs->attrib[i].arrayBuffer == name)
{
LContext->attribs->attrib[i].arrayBuffer = 0;
LContext->attribs->HasVBOMask &= ~( 1 << i );
}
}
_RGLAttribSetDeleteBuffer( LContext, name );
}
}
_RGLTexNameSpaceDeleteNames( &LContext->bufferObjectNameSpace, n, buffers );
}
GLAPI void APIENTRY glGenBuffers(GLsizei n, GLuint *buffers)
{
PSGLcontext *LContext = _CurrentContext;
_RGLTexNameSpaceGenNames( &LContext->bufferObjectNameSpace, n, buffers );
}
static inline void _RGLTextureTouchFBOs(jsTexture *texture)
{
PSGLcontext *LContext = _CurrentContext;
if(!LContext)
return;
GLuint fbCount = texture->framebuffers.getCount();
if(fbCount > 0)
{
jsFramebuffer *contextFramebuffer = LContext->framebuffer ? (jsFramebuffer *)LContext->framebufferNameSpace.data[LContext->framebuffer] : NULL;
for (GLuint i = 0; i < fbCount; ++i)
{
jsFramebuffer* framebuffer = texture->framebuffers[i];
framebuffer->needValidate = GL_TRUE;
if(RGL_UNLIKELY(framebuffer == contextFramebuffer))
LContext->needValidate |= PSGL_VALIDATE_FRAMEBUFFER;
}
}
}
static void _RGLAllocateBuffer(jsBufferObject* bufferObject)
{
RGLBufferObject *jsBuffer = (RGLBufferObject *)bufferObject->platformBufferObject;
_RGLPlatformDestroyBufferObject(bufferObject);
jsBuffer->pool = SURFACE_POOL_LINEAR;
jsBuffer->bufferId = gmmAlloc(0, jsBuffer->bufferSize);
jsBuffer->pitch = 0;
if(jsBuffer->bufferId == GMM_ERROR)
jsBuffer->pool = SURFACE_POOL_NONE;
GLuint referenceCount = bufferObject->textureReferences.getCount();
if(referenceCount > 0)
{
for (GLuint i = 0;i < referenceCount; ++i)
{
jsTexture *texture = bufferObject->textureReferences[i];
RGLTexture *gcmTexture = ( RGLTexture * )texture->platformTexture;
gcmTexture->gpuAddressId = jsBuffer->bufferId;
gcmTexture->gpuAddressIdOffset = texture->offset;
texture->revalidate |= TEXTURE_REVALIDATE_PARAMETERS;
_RGLTextureTouchFBOs( texture );
}
_CurrentContext->needValidate |= PSGL_VALIDATE_TEXTURES_USED | PSGL_VALIDATE_VERTEX_TEXTURES_USED ;
}
}
static void _RGLMemcpy( const GLuint dstId, unsigned dstOffset, unsigned int pitch, const GLuint srcId, unsigned int size )
{
pitch = pitch ? : 64;
const GLuint dstOffsetAlign = dstOffset % pitch;
GLuint srcOffset = 0;
if ( dstOffsetAlign )
{
const GLuint firstBytes = MIN( pitch - dstOffsetAlign, size );
transfer_params_t transfer_params;
transfer_params.dst_id = dstId;
transfer_params.dst_id_offset = 0;
transfer_params.dst_pitch = pitch;
transfer_params.dst_x = dstOffsetAlign / 2;
transfer_params.dst_y = dstOffset / pitch;
transfer_params.src_id = srcId;
transfer_params.src_id_offset = srcOffset;
transfer_params.src_pitch = pitch;
transfer_params.src_x = 0;
transfer_params.src_y = 0;
transfer_params.width = firstBytes / 2;
transfer_params.height = 1;
transfer_params.bpp = 2;
transfer_params.fifo_ptr = &_RGLState.fifo;
TransferDataVidToVid(&transfer_params);
dstOffset += firstBytes;
srcOffset += firstBytes;
size -= firstBytes;
}
const GLuint fullLines = size / pitch;
const GLuint extraBytes = size % pitch;
if ( fullLines )
{
transfer_params_t transfer_params;
transfer_params.dst_id = dstId;
transfer_params.dst_id_offset = 0;
transfer_params.dst_pitch = pitch;
transfer_params.dst_x = 0;
transfer_params.dst_y = dstOffset / pitch;
transfer_params.src_id = srcId;
transfer_params.src_id_offset = srcOffset;
transfer_params.src_pitch = pitch;
transfer_params.src_x = 0;
transfer_params.src_y = 0;
transfer_params.width = pitch / 2;
transfer_params.height = fullLines;
transfer_params.bpp = 2;
transfer_params.fifo_ptr = &_RGLState.fifo;
TransferDataVidToVid(&transfer_params);
}
if ( extraBytes )
{
transfer_params_t transfer_params;
transfer_params.dst_id = dstId;
transfer_params.dst_id_offset = 0;
transfer_params.dst_pitch = pitch;
transfer_params.dst_x = 0;
transfer_params.dst_y = fullLines + dstOffset / pitch;
transfer_params.src_id = srcId;
transfer_params.src_id_offset = srcOffset;
transfer_params.src_pitch = pitch;
transfer_params.src_x = 0;
transfer_params.src_y = fullLines;
transfer_params.width = extraBytes / 2;
transfer_params.height = 1;
transfer_params.bpp = 2;
transfer_params.fifo_ptr = &_RGLState.fifo;
TransferDataVidToVid(&transfer_params);
}
}
static void _RGLPlatformBufferObjectSetData( jsBufferObject* bufferObject, GLintptr offset, GLsizeiptr size, const GLvoid *data, GLboolean tryImmediateCopy )
{
RGLBufferObject *jsBuffer = ( RGLBufferObject * )bufferObject->platformBufferObject;
if ( size == bufferObject->size && tryImmediateCopy )
memcpy( gmmIdToAddress( jsBuffer->bufferId ) + offset, data, size );
else
if ( size >= bufferObject->size )
{
jsBuffer->bufferSize = _RGLPad( size, _RGL_BUFFER_OBJECT_BLOCK_SIZE );
_RGLAllocateBuffer( bufferObject );
switch ( jsBuffer->pool )
{
case SURFACE_POOL_NONE:
_RGLSetError( GL_OUT_OF_MEMORY );
return;
default:
memcpy( gmmIdToAddress( jsBuffer->bufferId ), data, size );
break;
}
}
else
{
if ( tryImmediateCopy )
memcpy( gmmIdToAddress( jsBuffer->bufferId ) + offset, data, size );
else
{
unsigned int dstId = jsBuffer->bufferId;
unsigned int pitch = jsBuffer->pitch;
const char *src = (const char *)data;
switch ( bufferObject->usage )
{
case GL_STREAM_DRAW:
case GL_STREAM_READ:
case GL_STREAM_COPY:
case GL_DYNAMIC_DRAW:
case GL_DYNAMIC_READ:
case GL_DYNAMIC_COPY:
{
GLuint id = gmmAlloc(0, size);
memcpy( gmmIdToAddress(id), src, size );
_RGLMemcpy( dstId, offset, pitch, id, size );
gmmFree( id );
}
break;
default:
cellGcmSetInvalidateVertexCache( &_RGLState.fifo);
_RGLFifoFinish( &_RGLState.fifo );
memcpy( gmmIdToAddress( dstId ) + offset, src, size );
break;
};
}
}
((RGLDriver *)_CurrentDevice->rasterDriver)->invalidateVertexCache = GL_TRUE;
}
static GLboolean _RGLPlatformCreateBufferObject( jsBufferObject* bufferObject )
{
RGLBufferObject *jsBuffer = ( RGLBufferObject * )bufferObject->platformBufferObject;
jsBuffer->pool = SURFACE_POOL_NONE;
jsBuffer->bufferId = GMM_ERROR;
jsBuffer->mapCount = 0;
jsBuffer->mapAccess = GL_NONE;
jsBuffer->bufferSize = _RGLPad( bufferObject->size, _RGL_BUFFER_OBJECT_BLOCK_SIZE );
_RGLAllocateBuffer(bufferObject);
return jsBuffer->bufferId != GMM_ERROR;
}
GLAPI void APIENTRY glBufferData( GLenum target, GLsizeiptr size, const GLvoid * data, GLenum usage )
{
PSGLcontext *LContext = _CurrentContext;
GLuint name = 0;
switch(target)
{
case GL_ARRAY_BUFFER:
name = LContext->ArrayBuffer;
break;
case GL_ELEMENT_ARRAY_BUFFER:
break;
case GL_PIXEL_PACK_BUFFER_ARB:
break;
case GL_PIXEL_UNPACK_BUFFER_ARB:
name = LContext->PixelUnpackBuffer;
break;
case GL_TEXTURE_REFERENCE_BUFFER_SCE:
name = LContext->TextureBuffer;
break;
default:
_RGLSetError(GL_INVALID_ENUM);
return;
}
jsBufferObject* bufferObject = (jsBufferObject *)LContext->bufferObjectNameSpace.data[name];
if(bufferObject->refCount > 1)
{
_RGLTexNameSpaceDeleteNames( &LContext->bufferObjectNameSpace, 1, &name );
_RGLTexNameSpaceCreateNameLazy( &LContext->bufferObjectNameSpace, name );
bufferObject = (jsBufferObject *)LContext->bufferObjectNameSpace.data[name];
}
if (bufferObject->size > 0)
_RGLPlatformDestroyBufferObject( bufferObject );
bufferObject->usage = usage;
bufferObject->size = size;
bufferObject->width = 0;
bufferObject->height = 0;
bufferObject->internalFormat = GL_NONE;
if (size > 0)
{
GLboolean created = _RGLPlatformCreateBufferObject( bufferObject );
if ( !created )
{
_RGLSetError( GL_OUT_OF_MEMORY );
return;
}
if ( data )
_RGLPlatformBufferObjectSetData( bufferObject, 0, size, data, GL_TRUE );
}
GLuint attrSetCount = bufferObject->attribSets.getCount();
if ( attrSetCount == 0 )
return;
for(unsigned int i = 0; i < attrSetCount; ++i)
{
jsAttribSet *attribSet = bufferObject->attribSets[i];
attribSet->dirty = GL_TRUE;
}
LContext->attribSetDirty = GL_TRUE;
}
static GLvoid _RGLPlatformBufferObjectCopyData( jsBufferObject* bufferObjectDst,
jsBufferObject* bufferObjectSrc )
{
RGLBufferObject* dst = ( RGLBufferObject* )bufferObjectDst->platformBufferObject;
RGLBufferObject* src = ( RGLBufferObject* )bufferObjectSrc->platformBufferObject;
switch ( dst->pool )
{
case SURFACE_POOL_LINEAR:
_RGLMemcpy( dst->bufferId, 0, dst->pitch, src->bufferId, src->bufferSize );
break;
case SURFACE_POOL_SYSTEM:
cellGcmSetInvalidateVertexCache( &_RGLState.fifo);
_RGLFifoFinish( &_RGLState.fifo );
memcpy( gmmIdToAddress( dst->bufferId ), gmmIdToAddress( src->bufferId ),
src->bufferSize );
break;
}
((RGLDriver *)_CurrentDevice->rasterDriver)->invalidateVertexCache = GL_TRUE;
}
GLAPI void APIENTRY glBufferSubData( GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data )
{
PSGLcontext *LContext = _CurrentContext;
GLuint name = 0;
switch ( target )
{
case GL_ARRAY_BUFFER:
name = LContext->ArrayBuffer;
break;
case GL_ELEMENT_ARRAY_BUFFER:
break;
case GL_PIXEL_PACK_BUFFER_ARB:
break;
case GL_PIXEL_UNPACK_BUFFER_ARB:
name = LContext->PixelUnpackBuffer;
break;
case GL_TEXTURE_REFERENCE_BUFFER_SCE:
name = LContext->TextureBuffer;
break;
default:
_RGLSetError( GL_INVALID_ENUM );
return;
}
jsBufferObject* bufferObject = (jsBufferObject *)LContext->bufferObjectNameSpace.data[name];
if ( bufferObject->refCount > 1 )
{
jsBufferObject* oldBufferObject = bufferObject;
_RGLTexNameSpaceDeleteNames( &LContext->bufferObjectNameSpace, 1, &name );
_RGLTexNameSpaceCreateNameLazy( &LContext->bufferObjectNameSpace, name );
bufferObject = (jsBufferObject *)LContext->bufferObjectNameSpace.data[name];
bufferObject->size = oldBufferObject->size;
bufferObject->usage = oldBufferObject->usage;
GLboolean created = _RGLPlatformCreateBufferObject( bufferObject );
if ( !created )
{
_RGLSetError( GL_OUT_OF_MEMORY );
return;
}
_RGLPlatformBufferObjectCopyData( bufferObject, oldBufferObject );
}
_RGLPlatformBufferObjectSetData( bufferObject, offset, size, data, GL_FALSE );
}
static void _RGLFramebufferGetAttachmentTexture(
const jsFramebufferAttachment* attachment,
jsTexture** texture)
{
PSGLcontext* LContext = _CurrentContext;
switch ( attachment->type )
{
case FRAMEBUFFER_ATTACHMENT_NONE:
*texture = NULL;
break;
case FRAMEBUFFER_ATTACHMENT_RENDERBUFFER:
break;
case FRAMEBUFFER_ATTACHMENT_TEXTURE:
*texture = _RGLTexNameSpaceIsName( &LContext->textureNameSpace, attachment->name ) ? ( jsTexture* )LContext->textureNameSpace.data[attachment->name] : NULL;
break;
default:
*texture = NULL;
break;
}
}
static GLboolean _RGLTextureIsValid(const jsTexture* texture)
{
if(texture->imageCount < 1)
return GL_FALSE;
if ( !texture->image )
return GL_FALSE;
const jsImage* image = texture->image;
int width = image->width;
int height = image->height;
GLenum format = image->format;
GLenum type = image->type;
GLenum internalFormat = image->internalFormat;
if (( internalFormat == 0 ) || ( format == 0 ) || ( type == 0 ) )
return GL_FALSE;
if(!image->isSet)
return GL_FALSE;
if(width != image->width)
return GL_FALSE;
if(height != image->height)
return GL_FALSE;
if(format != image->format)
return GL_FALSE;
if(type != image->type)
return GL_FALSE;
if(internalFormat != image->internalFormat)
return GL_FALSE;
return GL_TRUE;
}
static GLenum _RGLPlatformFramebufferCheckStatus(jsFramebuffer* framebuffer)
{
GLuint nBuffers = 0;
jsImage* image[MAX_COLOR_ATTACHMENTS + 2] = {0};
GLuint colorFormat = 0;
for ( int i = 0; i < MAX_COLOR_ATTACHMENTS; ++i )
{
jsTexture* colorTexture = NULL;
_RGLFramebufferGetAttachmentTexture(&framebuffer->color[i], &colorTexture);
if ( colorTexture != NULL )
{
if ( !_RGLTextureIsValid( colorTexture ) )
{
RARCH_ERR("Framebuffer color attachment texture is not complete.\n");
return GL_FRAMEBUFFER_UNSUPPORTED_OES;
}
image[nBuffers] = colorTexture->image;
if ( colorFormat && colorFormat != image[nBuffers]->internalFormat )
{
RARCH_ERR("Framebuffer attachments have inconsistent color formats.\n" );
return GL_FRAMEBUFFER_INCOMPLETE_FORMATS_OES;
}
colorFormat = image[nBuffers]->internalFormat;
++nBuffers;
}
}
if ( nBuffers && colorFormat != RGL_ARGB8)
{
RARCH_ERR("Color attachment to framebuffer must be a supported drawable format (GL_ARGB_SCE)\n");
return GL_FRAMEBUFFER_UNSUPPORTED_OES;
}
if ( nBuffers == 0 )
return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_OES;
for ( GLuint i = 0; i < nBuffers; ++i )
for ( GLuint j = i + 1; j < nBuffers; ++j )
if ( image[i] == image[j] )
return GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_OES;
return GL_FRAMEBUFFER_COMPLETE_OES;
}
enum _RGLTextureStrategy
{
TEXTURE_STRATEGY_END,
TEXTURE_STRATEGY_UNTILED_ALLOC,
TEXTURE_STRATEGY_UNTILED_CLEAR,
};
static enum _RGLTextureStrategy linearGPUStrategy[] =
{
TEXTURE_STRATEGY_UNTILED_ALLOC,
TEXTURE_STRATEGY_UNTILED_CLEAR,
TEXTURE_STRATEGY_UNTILED_ALLOC,
TEXTURE_STRATEGY_END,
};
static void _RGLImageAllocCPUStorage( jsImage *image )
{
if((image->storageSize > image->mallocStorageSize) || (!image->mallocData))
{
if(image->mallocData)
free( image->mallocData );
image->mallocData = ( char * )malloc( image->storageSize + 128 );
image->mallocStorageSize = image->storageSize;
}
intptr_t x = (intptr_t)image->mallocData;
x = ( x + 128 - 1 ) / 128 * 128;
image->data = (char*)x;
}
static inline int _RGLGetComponentCount( GLenum format )
{
switch ( format )
{
#define DECLARE_FORMAT(FORMAT,COUNT) \
case FORMAT: \
return COUNT;
DECLARE_FORMATS
#undef DECLARE_FORMAT
default:
return 0;
}
}
typedef void( GetComponentsFunction_t )( const unsigned char *bytes, GLfloat *values, int count );
typedef void( PutComponentsFunction_t )( unsigned char *bytes, GLfloat *values, int count );
typedef void( ColorConvertFunction_t )( jsColorRGBAf *color, GLfloat *values );
#define DECLARE_UNPACKED_TYPE(TYPE) \
static void _RGLGetComponents_##TYPE(const unsigned char *bytes, GLfloat *values, int count) \
{ \
int i; \
for (i=0;i<count;++i) \
{ \
const type_##TYPE data=*(const type_##TYPE *)bytes; \
values[i]=_RGLFloatFrom_##TYPE(data); \
bytes+=sizeof(type_##TYPE); \
} \
}
DECLARE_UNPACKED_TYPES
#undef DECLARE_UNPACKED_TYPE
#define DECLARE_PACKED_TYPE(REALTYPE,TYPE,N,S1,S2,S3,S4,REV) \
static void _RGLGetComponents_##TYPE(const unsigned char *bytes, GLfloat *values, int count) \
{ \
const type_##REALTYPE data=*(const type_##REALTYPE *)bytes; \
GET_BITS(values[INDEX##REV(N,0)],data,S2+S3+S4,S1); \
GET_BITS(values[INDEX##REV(N,1)],data,S3+S4,S2); \
GET_BITS(values[INDEX##REV(N,2)],data,S4,S3); \
GET_BITS(values[INDEX##REV(N,3)],data,0,S4); \
}
DECLARE_PACKED_TYPES
#undef DECLARE_PACKED_TYPE
#define DECLARE_UNPACKED_TYPE(TYPE) \
static void _RGLPutComponents_##TYPE(unsigned char *bytes, GLfloat *values, int count) \
{ \
int i; \
for (i=0;i<count;++i) \
{ \
type_##TYPE *data=(type_##TYPE *)bytes; \
*data=_RGLFloatTo_##TYPE(values[i]); \
bytes+=sizeof(type_##TYPE); \
} \
}
DECLARE_UNPACKED_TYPES
#undef DECLARE_UNPACKED_TYPE
#define DECLARE_PACKED_TYPE(REALTYPE,TYPE,N,S1,S2,S3,S4,REV) \
static void _RGLPutComponents_##TYPE(unsigned char *bytes, GLfloat *values, int count) \
{ \
type_##REALTYPE *data=(type_##REALTYPE *)bytes; \
*data=0; \
PUT_BITS(values[INDEX##REV(N,0)],*data,S2+S3+S4,S1); \
PUT_BITS(values[INDEX##REV(N,1)],*data,S3+S4,S2); \
PUT_BITS(values[INDEX##REV(N,2)],*data,S4,S3); \
PUT_BITS(values[INDEX##REV(N,3)],*data,0,S4); \
}
DECLARE_PACKED_TYPES
#undef DECLARE_PACKED_TYPE
static inline GetComponentsFunction_t *_RGLFindGetComponentsFunction( GLenum type )
{
switch ( type )
{
#define DECLARE_UNPACKED_TYPE(TYPE) \
case TYPE: \
return &_RGLGetComponents_##TYPE;
DECLARE_UNPACKED_TYPES
#undef DECLARE_UNPACKED_TYPE
#define DECLARE_PACKED_TYPE(REALTYPE,TYPE,N,S1,S2,S3,S4,REV) \
case TYPE: \
return &_RGLGetComponents_##TYPE;
DECLARE_PACKED_TYPES
#undef DECLARE_PACKED_TYPE
default:
return NULL;
}
}
static inline PutComponentsFunction_t *_RGLFindPutComponentsFunction( GLenum type )
{
switch ( type )
{
#define DECLARE_UNPACKED_TYPE(TYPE) \
case TYPE: \
return &_RGLPutComponents_##TYPE;
DECLARE_UNPACKED_TYPES
#undef DECLARE_UNPACKED_TYPE
#define DECLARE_PACKED_TYPE(REALTYPE,TYPE,N,S1,S2,S3,S4,REV) \
case TYPE: \
return &_RGLPutComponents_##TYPE;
DECLARE_PACKED_TYPES
#undef DECLARE_PACKED_TYPE
default:
return NULL;
}
}
static void _RGLValuesToColor_GL_RGB( jsColorRGBAf *c, GLfloat *v ) { c->R = v[0]; c->G = v[1]; c->B = v[2]; c->A = 1.f; }
static void _RGLValuesToColor_GL_BGR( jsColorRGBAf *c, GLfloat *v ) { c->B = v[0]; c->G = v[1]; c->R = v[2]; c->A = 1.f; }
static void _RGLValuesToColor_GL_RGBA( jsColorRGBAf *c, GLfloat *v ) { c->R = v[0]; c->G = v[1]; c->B = v[2]; c->A = v[3]; }
static void _RGLValuesToColor_GL_BGRA( jsColorRGBAf *c, GLfloat *v ) { c->B = v[0]; c->G = v[1]; c->R = v[2]; c->A = v[3]; }
static void _RGLValuesToColor_GL_ABGR( jsColorRGBAf *c, GLfloat *v ) { c->A = v[0]; c->B = v[1]; c->G = v[2]; c->R = v[3]; }
static void _RGLValuesToColor_GL_ARGB_SCE( jsColorRGBAf *c, GLfloat *v ) { c->A = v[0]; c->R = v[1]; c->G = v[2]; c->B = v[3]; }
static void _RGLValuesToColor_GL_RED( jsColorRGBAf *c, GLfloat *v ) { c->R = v[0]; c->G = 0.f; c->B = 0.f; c->A = 1.f; }
static void _RGLValuesToColor_GL_GREEN( jsColorRGBAf *c, GLfloat *v ) { c->R = 0.f; c->G = v[0]; c->B = 0.f; c->A = 1.f; }
static void _RGLValuesToColor_GL_BLUE( jsColorRGBAf *c, GLfloat *v ) { c->R = 0.f; c->G = 0.f; c->B = v[0]; c->A = 1.f; }
static void _RGLValuesToColor_GL_ALPHA( jsColorRGBAf *c, GLfloat *v ) { c->R = 0.f; c->G = 0.f; c->B = 0.f; c->A = v[0]; }
static void _RGLColorToValues_GL_RGB( jsColorRGBAf *c, GLfloat *v ) { v[0] = c->R; v[1] = c->G; v[2] = c->B; }
static void _RGLColorToValues_GL_BGR( jsColorRGBAf *c, GLfloat *v ) { v[0] = c->B; v[1] = c->G; v[2] = c->R; }
static void _RGLColorToValues_GL_RGBA( jsColorRGBAf *c, GLfloat *v ) { v[0] = c->R; v[1] = c->G; v[2] = c->B; v[3] = c->A; }
static void _RGLColorToValues_GL_BGRA( jsColorRGBAf *c, GLfloat *v ) { v[0] = c->B; v[1] = c->G; v[2] = c->R; v[3] = c->A; }
static void _RGLColorToValues_GL_ABGR( jsColorRGBAf *c, GLfloat *v ) { v[0] = c->A; v[1] = c->B; v[2] = c->G; v[3] = c->R; }
static void _RGLColorToValues_GL_ARGB_SCE( jsColorRGBAf *c, GLfloat *v ) { v[0] = c->A; v[1] = c->R; v[2] = c->G; v[3] = c->B; }
static void _RGLColorToValues_GL_RED( jsColorRGBAf *c, GLfloat *v ) { v[0] = c->R; }
static void _RGLColorToValues_GL_GREEN( jsColorRGBAf *c, GLfloat *v ) { v[0] = c->G; }
static void _RGLColorToValues_GL_BLUE( jsColorRGBAf *c, GLfloat *v ) { v[0] = c->B; }
static void _RGLColorToValues_GL_ALPHA( jsColorRGBAf *c, GLfloat *v ) { v[0] = c->A; }
static inline ColorConvertFunction_t *_RGLFindValuesToColorFunction( GLenum format )
{
switch ( format )
{
#define DECLARE_FORMAT(FORMAT,COUNT) \
case FORMAT: \
return &_RGLValuesToColor_##FORMAT;
DECLARE_FORMATS
#undef DECLARE_FORMAT
default:
return NULL;
}
}
static inline ColorConvertFunction_t *_RGLFindColorToValuesFunction( GLenum format )
{
switch ( format )
{
#define DECLARE_FORMAT(FORMAT,COUNT) \
case FORMAT: \
return &_RGLColorToValues_##FORMAT;
DECLARE_FORMATS
#undef DECLARE_FORMAT
default:
return NULL;
}
}
static void _RGLRasterToImage(const jsRaster* raster, jsImage* image)
{
const int srcComponents = _RGLGetComponentCount( raster->format );
const int dstComponents = _RGLGetComponentCount( image->format );
GetComponentsFunction_t* getComponents = _RGLFindGetComponentsFunction( raster->type );
PutComponentsFunction_t* putComponents = _RGLFindPutComponentsFunction( image->type );
ColorConvertFunction_t* valuesToColor = _RGLFindValuesToColorFunction( raster->format );
ColorConvertFunction_t* colorToValues = _RGLFindColorToValuesFunction( image->format );
for ( int j = 0; j < raster->height; ++j )
{
const unsigned char *src = ( const unsigned char * )raster->data + j * raster->ystride;
unsigned char *dst = ( unsigned char * )image->data + (j) * image->ystride;
for ( int k = 0; k < raster->width; ++k )
{
GLfloat values[4];
jsColorRGBAf color;
getComponents( src, values, srcComponents );
valuesToColor( &color, values );
colorToValues( &color, values );
if (image->type!=GL_FLOAT && image->type!=GL_HALF_FLOAT_ARB)
{
values[0]= MAX( MIN( values[0], 1.f ), 0.f );
values[1]= MAX( MIN( values[1], 1.f ), 0.f );
values[2]= MAX( MIN( values[2], 1.f ), 0.f );
values[3]= MAX( MIN( values[3], 1.f ), 0.f );
}
putComponents( dst, values, dstComponents );
src += raster->xstride;
dst += image->xstride;
}
}
}
static void _RGLPlatformCopyGPUTexture( jsTexture* texture )
{
RGLTexture *gcmTexture = ( RGLTexture * )texture->platformTexture;
if ( gcmTexture->gpuAddressId == GMM_ERROR )
return;
RGLTextureLayout *layout = &gcmTexture->gpuLayout;
jsImage* image = texture->image;
if ( image->dataState == IMAGE_DATASTATE_GPU )
{
_RGLImageAllocCPUStorage( image );
cellGcmSetInvalidateVertexCache( &_RGLState.fifo);
_RGLFifoFinish( &_RGLState.fifo );
char* gpuData = gmmIdToAddress(gcmTexture->gpuAddressId) + gcmTexture->gpuAddressIdOffset;
jsRaster raster =
{
format : image->format,
type : image->type,
width : image->width,
height : image->height,
xstride : image->xstride,
ystride : layout->pitch,
data : gpuData
};
_RGLRasterToImage( &raster, image);
image->dataState = IMAGE_DATASTATE_HOST;
}
}
static void _RGLPlatformFreeGcmTexture(jsTexture* texture)
{
RGLTexture *gcmTexture = (RGLTexture *)texture->platformTexture;
switch (gcmTexture->pool)
{
case SURFACE_POOL_LINEAR:
case SURFACE_POOL_SYSTEM:
gmmFree(gcmTexture->gpuAddressId);
case SURFACE_POOL_NONE:
break;
default:
break;
}
gcmTexture->gpuAddressId = GMM_ERROR;
gcmTexture->gpuAddressIdOffset = 0;
gcmTexture->gpuSize = 0;
}
void _RGLPlatformDropTexture( jsTexture *texture )
{
RGLTexture * gcmTexture = (RGLTexture *)texture->platformTexture;
if(gcmTexture->pbo != NULL)
{
_RGLPlatformCopyGPUTexture(texture);
_RGLFreeBufferObject(gcmTexture->pbo);
gcmTexture->pbo = NULL;
gcmTexture->gpuAddressId = GMM_ERROR;
gcmTexture->gpuAddressIdOffset = 0;
gcmTexture->pool = SURFACE_POOL_NONE;
gcmTexture->gpuSize = 0;
}
if(gcmTexture->pool != SURFACE_POOL_NONE)
{
_RGLPlatformCopyGPUTexture( texture );
_RGLPlatformFreeGcmTexture( texture );
}
gcmTexture->pool = SURFACE_POOL_NONE;
gcmTexture->gpuAddressId = GMM_ERROR;
gcmTexture->gpuAddressIdOffset = 0;
gcmTexture->gpuSize = 0;
texture->revalidate |= TEXTURE_REVALIDATE_IMAGES;
_RGLTextureTouchFBOs(texture);
}
int _RGLGetPixelSize( GLenum format, GLenum type )
{
int componentSize;
switch(type)
{
#define DECLARE_PACKED_TYPE(REALTYPE,TYPE,N,S1,S2,S3,S4,REV) \
case TYPE: \
return sizeof(type_##REALTYPE);
DECLARE_PACKED_TYPES
#undef DECLARE_PACKED_TYPE
#define DECLARE_UNPACKED_TYPE(TYPE) \
case TYPE: \
componentSize=sizeof(type_##TYPE); \
break;
DECLARE_UNPACKED_TYPES
#undef DECLARE_UNPACKED_TYPE
default:
return 0;
}
return _RGLGetComponentCount( format )*componentSize;
}
static void _RGLPlatformChooseGPUFormatAndLayout(
const jsTexture* texture,
GLboolean forceLinear,
GLuint pitch,
RGLTextureLayout* newLayout )
{
jsImage *image = texture->image;
newLayout->baseWidth = image->width;
newLayout->baseHeight = image->height;
newLayout->internalFormat = (RGLEnum)image->internalFormat;
newLayout->pixelBits = _RGLPlatformGetBitsPerPixel( newLayout->internalFormat );
newLayout->pitch = pitch ? pitch : _RGLPad( _RGLGetPixelSize( texture->image->format, texture->image->type )*texture->image->width, 64);
}
void _RGLPlatformDropUnboundTextures(GLenum pool)
{
PSGLcontext* LContext = _CurrentContext;
GLuint i, j;
for (i = 0; i < LContext->textureNameSpace.capacity; ++i)
{
GLboolean bound = GL_FALSE;
jsTexture *texture = ( jsTexture * )LContext->textureNameSpace.data[i];
if(!texture || (texture->referenceBuffer != 0))
continue;
for (j = 0; j < MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++j)
{
if (LContext->VertexTextureImages[j] == texture)
{
bound = GL_TRUE;
break;
}
}
for ( j = 0; j < MAX_TEXTURE_IMAGE_UNITS; ++j)
{
jsTextureImageUnit *tu = LContext->TextureImageUnits + j;
if (tu->bound2D == i)
{
bound = GL_TRUE;
break;
}
}
if ( bound )
continue;
RGLTexture *gcmTexture = ( RGLTexture * )texture->platformTexture;
if ( gcmTexture->pbo != NULL && gcmTexture->pbo->refCount > 1 )
continue;
if ( pool != SURFACE_POOL_NONE && pool != gcmTexture->pool )
continue;
_RGLPlatformDropTexture( texture );
}
}
static void _RGLPlatformReallocateGcmTexture( jsTexture* texture )
{
RGLTexture *gcmTexture = ( RGLTexture * )texture->platformTexture;
enum _RGLTextureStrategy *step = linearGPUStrategy;
GLuint size = 0;
GLuint id = GMM_ERROR;
const RGLTextureLayout currentLayout = gcmTexture->gpuLayout;
const GLuint currentSize = gcmTexture->gpuSize;
// process strategy
GLboolean done = GL_FALSE;
while ( !done )
{
RGLTextureLayout newLayout;
switch ( *step++ )
{
case TEXTURE_STRATEGY_UNTILED_ALLOC:
_RGLPlatformChooseGPUFormatAndLayout( texture, GL_TRUE, 0, &newLayout );
size = _RGLPad( newLayout.baseHeight * newLayout.pitch, 1);
if ( gcmTexture->pool == SURFACE_POOL_LINEAR )
{
if ( currentSize >= size && newLayout.pitch == currentLayout.pitch )
{
gcmTexture->gpuLayout = newLayout;
done = GL_TRUE;
}
else
_RGLPlatformDropTexture( texture );
}
if ( !done )
{
id = gmmAlloc(0, size);
if ( id != GMM_ERROR )
{
if ( gcmTexture->pool != SURFACE_POOL_NONE )
_RGLPlatformDropTexture( texture );
gcmTexture->pool = SURFACE_POOL_LINEAR;
gcmTexture->gpuAddressId = id;
gcmTexture->gpuAddressIdOffset = 0;
gcmTexture->gpuSize = size;
gcmTexture->gpuLayout = newLayout;
done = GL_TRUE;
}
}
break;
case TEXTURE_STRATEGY_UNTILED_CLEAR:
_RGLPlatformDropUnboundTextures(SURFACE_POOL_LINEAR);
break;
case TEXTURE_STRATEGY_END:
_RGLSetError( GL_OUT_OF_MEMORY );
done = GL_TRUE;
break;
default:
break;
}
}
_RGLTextureTouchFBOs( texture );
}
static void _RGLImageFreeCPUStorage( jsImage *image )
{
if (!image->mallocData)
return;
if (image->mallocData != NULL)
free( image->mallocData );
image->mallocStorageSize = 0;
image->data = NULL;
image->mallocData = NULL;
image->dataState &= ~IMAGE_DATASTATE_HOST;
}
static void _RGLPlatformValidateTextureResources( jsTexture *texture )
{
if ( RGL_UNLIKELY( !_RGLTextureIsValid( texture ) ) )
{
texture->isComplete = GL_FALSE;
return;
}
texture->isComplete = GL_TRUE;
if ( texture->revalidate & TEXTURE_REVALIDATE_IMAGES ||
texture->revalidate & TEXTURE_REVALIDATE_LAYOUT )
{
_RGLPlatformReallocateGcmTexture( texture );
RGLTexture *gcmTexture = ( RGLTexture * )texture->platformTexture;
RGLTextureLayout *layout = &gcmTexture->gpuLayout;
const GLuint pixelBytes = layout->pixelBits / 8;
RGLSurface src;
src.source = SURFACE_SOURCE_TEMPORARY;
src.width = 0;
src.height = 0;
src.bpp = pixelBytes;
src.pitch = 0;
src.format = layout->internalFormat;
src.pool = SURFACE_POOL_LINEAR;
src.ppuData = NULL;
src.dataId = GMM_ERROR;
src.dataIdOffset = 0;
RGLSurface dst;
dst.source = SURFACE_SOURCE_TEXTURE;
dst.width = 0;
dst.height = 0;
dst.bpp = pixelBytes;
dst.pitch = layout->pitch;
dst.format = layout->internalFormat;
dst.pool = SURFACE_POOL_SYSTEM;
dst.ppuData = NULL;
dst.dataId = GMM_ERROR;
dst.dataIdOffset = 0;
GLuint bounceBufferId = GMM_ERROR;
jsImage *image = texture->image;
if(image->dataState == IMAGE_DATASTATE_HOST)
{
src.ppuData = image->data;
if ( bounceBufferId == GMM_ERROR)
bounceBufferId = gmmAlloc(0, gcmTexture->gpuSize);
if ( bounceBufferId != GMM_ERROR )
{
src.dataId = bounceBufferId;
src.dataIdOffset = 0;
memcpy( gmmIdToAddress( src.dataId ), image->data,
image->storageSize );
}
src.width = image->width;
src.height = image->height;
src.pitch = pixelBytes * src.width;
dst.width = src.width;
dst.height = image->height;
dst.dataId = gcmTexture->gpuAddressId;
dst.dataIdOffset = gcmTexture->gpuAddressIdOffset;
transfer_params_t transfer_params;
transfer_params.dst_id = dst.dataId;
transfer_params.dst_id_offset = dst.dataIdOffset;
transfer_params.dst_pitch = dst.pitch ? dst.pitch : (dst.bpp * dst.width);
transfer_params.dst_x = 0;
transfer_params.dst_y = 0;
transfer_params.src_id = src.dataId;
transfer_params.src_id_offset = src.dataIdOffset;
transfer_params.src_pitch = src.pitch ? src.pitch : (src.bpp * src.width);
transfer_params.src_x = 0;
transfer_params.src_y = 0;
transfer_params.width = src.width;
transfer_params.height = src.height;
transfer_params.bpp = src.bpp;
transfer_params.fifo_ptr = &_RGLState.fifo;
TransferDataVidToVid(&transfer_params);
_RGLImageFreeCPUStorage( image );
image->dataState |= IMAGE_DATASTATE_GPU;
}
if ( bounceBufferId != GMM_ERROR )
gmmFree( bounceBufferId );
cellGcmSetInvalidateTextureCacheInline( &_RGLState.fifo, CELL_GCM_INVALIDATE_TEXTURE);
}
RGLTexture *platformTexture = ( RGLTexture * )texture->platformTexture;
RGLTextureLayout *layout = &platformTexture->gpuLayout;
GLuint minFilter = texture->minFilter;
GLuint magFilter = texture->magFilter;
platformTexture->gcmMethods.filter.min = _RGLMapMinTextureFilter( minFilter );
platformTexture->gcmMethods.filter.mag = _RGLMapMagTextureFilter( magFilter );
platformTexture->gcmMethods.filter.bias = ( GLint )(( -.26f ) * 256.0f );
GLuint gamma = 0;
GLuint remap = texture->gammaRemap;
gamma |= (remap & RGL_GAMMA_REMAP_RED_BIT) ? CELL_GCM_TEXTURE_GAMMA_R : 0;
gamma |= (remap & RGL_GAMMA_REMAP_GREEN_BIT) ? CELL_GCM_TEXTURE_GAMMA_G : 0;
gamma |= (remap & RGL_GAMMA_REMAP_BLUE_BIT) ? CELL_GCM_TEXTURE_GAMMA_B : 0;
gamma |= (remap & RGL_GAMMA_REMAP_ALPHA_BIT) ? CELL_GCM_TEXTURE_GAMMA_A : 0;
platformTexture->gcmMethods.address.gamma = gamma;
GLuint internalFormat = layout->internalFormat;
_RGLMapTextureFormat( internalFormat,
platformTexture->gcmTexture.format, platformTexture->gcmTexture.remap );
if ( layout->pitch )
platformTexture->gcmTexture.format += 0x20;
platformTexture->gcmTexture.width = layout->baseWidth;
platformTexture->gcmTexture.height = layout->baseHeight;
platformTexture->gcmTexture.depth = 1;
platformTexture->gcmTexture.pitch = layout->pitch;
platformTexture->gcmTexture.mipmap = 1;
platformTexture->gcmTexture.cubemap = CELL_GCM_FALSE;
platformTexture->gcmTexture.dimension = CELL_GCM_TEXTURE_DIMENSION_2;
if(gmmIdIsMain(platformTexture->gpuAddressId))
platformTexture->gcmTexture.location = CELL_GCM_LOCATION_MAIN;
else
platformTexture->gcmTexture.location = CELL_GCM_LOCATION_LOCAL;
texture->revalidate = 0;
}
static void jsPlatformFramebuffer_validate( jsPlatformFramebuffer * fb, PSGLcontext *LContext )
{
fb->complete = ( _RGLPlatformFramebufferCheckStatus(fb) == GL_FRAMEBUFFER_COMPLETE_OES );
if(!fb->complete)
return;
GLuint width = CELL_GCM_MAX_RT_DIMENSION;
GLuint height = CELL_GCM_MAX_RT_DIMENSION;
fb->rt.colorBufferCount = 0;
fb->rt.colorFormat = RGL_NONE;
fb->colorBufferMask = 0x0;
GLuint defaultPitch = 0;
GLuint defaultId = GMM_ERROR;
GLuint defaultIdOffset = 0;
for(int i = 0; i < RGL_SETRENDERTARGET_MAXCOUNT; ++i)
{
jsTexture* colorTexture = NULL;
_RGLFramebufferGetAttachmentTexture(&fb->color[i], &colorTexture);
if(colorTexture == NULL)
continue;
RGLTexture* nvTexture = ( RGLTexture * )colorTexture->platformTexture;
if ( !colorTexture->isRenderTarget )
{
colorTexture->isRenderTarget = GL_TRUE;
colorTexture->revalidate |= TEXTURE_REVALIDATE_LAYOUT;
}
_RGLPlatformValidateTextureResources( colorTexture );
colorTexture->image->dataState = IMAGE_DATASTATE_GPU;
fb->rt.colorId[i] = nvTexture->gpuAddressId;
fb->rt.colorIdOffset[i] = nvTexture->gpuAddressIdOffset;
fb->rt.colorPitch[i] = nvTexture->gpuLayout.pitch ? nvTexture->gpuLayout.pitch : nvTexture->gpuLayout.pixelBits * nvTexture->gpuLayout.baseWidth / 8;
fb->colorBufferMask |= 1 << i;
width = MIN( width, nvTexture->gpuLayout.baseWidth );
height = MIN( height, nvTexture->gpuLayout.baseHeight );
fb->rt.colorFormat = nvTexture->gpuLayout.internalFormat;
fb->rt.colorBufferCount = i + 1;
defaultId = fb->rt.colorId[i];
defaultIdOffset = fb->rt.colorIdOffset[i];
defaultPitch = fb->rt.colorPitch[i];
if ( !( fb->colorBufferMask & ( 1 << i ) ) )
{
fb->rt.colorId[i] = defaultId;
fb->rt.colorIdOffset[i] = defaultIdOffset;
fb->rt.colorPitch[i] = defaultPitch;
}
}
fb->rt.width = width;
fb->rt.height = height;
fb->rt.yInverted = CELL_GCM_FALSE;
fb->rt.xOffset = 0;
fb->rt.yOffset = 0;
fb->needValidate = GL_FALSE;
}
static void _RGLValidateFramebuffer( void )
{
PSGLdevice *LDevice = _CurrentDevice;
RGLDevice *gcmDevice = ( RGLDevice * )LDevice->platformDevice;
PSGLcontext* LContext = _CurrentContext;
RGLDriver *driver= (RGLDriver *)_CurrentDevice->rasterDriver;
driver->rtValid = GL_FALSE;
if(LContext->framebuffer)
{
jsPlatformFramebuffer* framebuffer = static_cast<jsPlatformFramebuffer *>((jsFramebuffer *)LContext->framebufferNameSpace.data[LContext->framebuffer] );
if ( framebuffer->needValidate )
jsPlatformFramebuffer_validate( framebuffer, LContext );
driver->rt = framebuffer->rt;
driver->colorBufferMask = framebuffer->colorBufferMask;
}
else
{
driver->rt = gcmDevice->rt;
driver->colorBufferMask = 0x1;
}
driver->rtValid = GL_TRUE;
_RGLFifoGlSetRenderTarget( &driver->rt );
LContext->needValidate &= ~PSGL_VALIDATE_FRAMEBUFFER;
_RGLFifoGlViewport(LContext->ViewPort.X, LContext->ViewPort.Y,
LContext->ViewPort.XSize, LContext->ViewPort.YSize, 0.0f, 1.0f);
}
GLAPI void APIENTRY glClear( GLbitfield mask )
{
PSGLcontext *LContext = _CurrentContext;
RGLDriver *driver= (RGLDriver *)_CurrentDevice->rasterDriver;
RGLFifo * fifo = &_RGLState.fifo;
if ( LContext->needValidate & PSGL_VALIDATE_FRAMEBUFFER )
_RGLValidateFramebuffer();
if ( !driver->rtValid )
return;
GLbitfield newmask = 0;
if(driver->rt.colorBufferCount)
newmask |= RGL_COLOR_BUFFER_BIT;
if(!newmask)
return;
GLbitfield clearMask = newmask;
if(driver->rt.colorBufferCount > 1)
clearMask &= ~RGL_COLOR_BUFFER_BIT;
if (clearMask)
{
GLuint hwColor;
RGL_CALC_COLOR_LE_ARGB8( &hwColor, RGL_CLAMPF_01(LContext->ClearColor.R), RGL_CLAMPF_01(LContext->ClearColor.G), RGL_CLAMPF_01(LContext->ClearColor.B), RGL_CLAMPF_01(LContext->ClearColor.A) );
cellGcmSetClearColorInline( &_RGLState.fifo, hwColor);
cellGcmSetClearSurfaceInline ( &_RGLState.fifo, CELL_GCM_CLEAR_R | CELL_GCM_CLEAR_G | CELL_GCM_CLEAR_B | CELL_GCM_CLEAR_A);
newmask &= ~clearMask;
}
if ( newmask )
{
static float _RGLClearVertexBuffer[12] __attribute__((aligned(128))) =
{
-1.f, -1.f, 0.f,
-1.f, 1.f, 0.f,
1.f, -1.f, 0.f,
1.f, 1.f, 0.f,
};
_RGLClearVertexBuffer[2] = 2.f - 1.f;
_RGLClearVertexBuffer[5] = 2.f - 1.f;
_RGLClearVertexBuffer[8] = 2.f - 1.f;
_RGLClearVertexBuffer[11] = 2.f - 1.f;
GLuint bufferId = gmmAlloc(0, sizeof(_RGLClearVertexBuffer));
memcpy( gmmIdToAddress(bufferId), _RGLClearVertexBuffer, sizeof( _RGLClearVertexBuffer ) );
GmmBaseBlock *pBaseBlock = (GmmBaseBlock *)bufferId;
cellGcmSetVertexDataArrayInline( &_RGLState.fifo, 0 /* index */, 1/* frequency */, 3 * sizeof(GLfloat)/*stride */, 3 /* size */, CELL_GCM_VERTEX_F /* gcmType */, CELL_GCM_LOCATION_LOCAL, gmmAddressToOffset(pBaseBlock->address, pBaseBlock->isMain)/* offset */);
RGLBIT_TRUE( LContext->attribs->DirtyMask, 0 );
for(int i = 1; i < MAX_VERTEX_ATTRIBS; ++i)
{
cellGcmSetVertexDataArrayInline( &_RGLState.fifo, i/* index */, 0/* frequency */, 0/*stride */, 0/* size */, CELL_GCM_VERTEX_F /*gcmType */, CELL_GCM_LOCATION_LOCAL, 0/* offset */ );
RGLBIT_TRUE( LContext->attribs->DirtyMask, i );
}
cellGcmSetVertexData4fInline( &_RGLState.fifo, _RGL_ATTRIB_PRIMARY_COLOR_INDEX, (GLfloat*)&LContext->ClearColor);
LContext->needValidate |= PSGL_VALIDATE_FRAGMENT_PROGRAM;
gmmFree( bufferId );
}
cellGcmSetInvalidateVertexCache( &_RGLState.fifo);
_RGLFifoFlush( fifo );
}
GLAPI void APIENTRY glClearColor( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha )
{
PSGLcontext *LContext = _CurrentContext;
LContext->ClearColor.R = MAX(MIN(red, 1.f), 0.f);
LContext->ClearColor.G = MAX(MIN(green, 1.f), 0.f);
LContext->ClearColor.B = MAX(MIN(blue, 1.f), 0.f);
LContext->ClearColor.A = MAX(MIN(alpha, 1.f), 0.f);
}
GLAPI void APIENTRY glBlendEquation( GLenum mode )
{
PSGLcontext *LContext = _CurrentContext;
LContext->BlendEquationRGB = LContext->BlendEquationAlpha = mode;
LContext->needValidate |= PSGL_VALIDATE_BLENDING;
}
GLAPI void APIENTRY glBlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
{
PSGLcontext* LContext = _CurrentContext;
LContext->BlendColor.R = MAX(MIN(red, 1.f), 0.f);
LContext->BlendColor.G = MAX(MIN(green, 1.f), 0.f);
LContext->BlendColor.B = MAX(MIN(blue, 1.f), 0.f);
LContext->BlendColor.A = MAX(MIN(alpha, 1.f), 0.f);
LContext->needValidate |= PSGL_VALIDATE_BLENDING;
}
GLAPI void APIENTRY glBlendFunc(GLenum sfactor, GLenum dfactor)
{
PSGLcontext *LContext = _CurrentContext;
LContext->BlendFactorSrcRGB = sfactor;
LContext->BlendFactorSrcAlpha = sfactor;
LContext->BlendFactorDestRGB = dfactor;
LContext->BlendFactorDestAlpha = dfactor;
LContext->needValidate |= PSGL_VALIDATE_BLENDING;
}
jsFramebufferAttachment* _RGLFramebufferGetAttachment( jsFramebuffer *framebuffer, GLenum attachment )
{
switch ( attachment )
{
case GL_COLOR_ATTACHMENT0_EXT:
case GL_COLOR_ATTACHMENT1_EXT:
case GL_COLOR_ATTACHMENT2_EXT:
case GL_COLOR_ATTACHMENT3_EXT:
return &framebuffer->color[attachment - GL_COLOR_ATTACHMENT0_EXT];
case GL_DEPTH_ATTACHMENT_OES:
case GL_STENCIL_ATTACHMENT_OES:
default:
_RGLSetError( GL_INVALID_ENUM );
return NULL;
}
}
GLAPI void APIENTRY glBindFramebufferOES( GLenum target, GLuint framebuffer )
{
PSGLcontext* LContext = _CurrentContext;
if ( framebuffer )
_RGLTexNameSpaceCreateNameLazy( &LContext->framebufferNameSpace, framebuffer );
LContext->framebuffer = framebuffer;
LContext->needValidate |= PSGL_VALIDATE_FRAMEBUFFER;
}
GLAPI void APIENTRY glDeleteFramebuffersOES( GLsizei n, const GLuint *framebuffers )
{
PSGLcontext *LContext = _CurrentContext;
for(int i = 0; i < n; ++i)
{
if ( framebuffers[i] && framebuffers[i] == LContext->framebuffer )
glBindFramebufferOES( GL_FRAMEBUFFER_OES, 0 );
}
_RGLTexNameSpaceDeleteNames( &LContext->framebufferNameSpace, n, framebuffers );
}
GLAPI void APIENTRY glGenFramebuffersOES( GLsizei n, GLuint *framebuffers )
{
PSGLcontext *LContext = _CurrentContext;
_RGLTexNameSpaceGenNames( &LContext->framebufferNameSpace, n, framebuffers );
}
GLAPI GLenum APIENTRY glCheckFramebufferStatusOES( GLenum target )
{
PSGLcontext *LContext = _CurrentContext;
if ( LContext->framebuffer )
{
jsFramebuffer* framebuffer = (jsFramebuffer *)LContext->framebufferNameSpace.data[LContext->framebuffer];
return _RGLPlatformFramebufferCheckStatus( framebuffer );
}
return GL_FRAMEBUFFER_COMPLETE_OES;
}
GLAPI void APIENTRY glFramebufferTexture2DOES( GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level )
{
PSGLcontext* LContext = _CurrentContext;
jsFramebuffer* framebuffer = (jsFramebuffer *)LContext->framebufferNameSpace.data[LContext->framebuffer];
jsFramebufferAttachment* attach = _RGLFramebufferGetAttachment( framebuffer, GL_COLOR_ATTACHMENT0_EXT );
if ( !attach )
return;
jsTexture *textureObject = NULL;
_RGLFramebufferGetAttachmentTexture(attach, &textureObject);
if ( textureObject )
textureObject->framebuffers.removeElement( framebuffer );
if ( texture )
{
attach->type = FRAMEBUFFER_ATTACHMENT_TEXTURE;
textureObject = ( jsTexture* )LContext->textureNameSpace.data[texture];
textureObject->framebuffers.pushBack( framebuffer );
}
else
attach->type = FRAMEBUFFER_ATTACHMENT_NONE;
attach->name = texture;
attach->textureTarget = GL_TEXTURE_2D;
framebuffer->needValidate = GL_TRUE;
LContext->needValidate |= PSGL_VALIDATE_FRAMEBUFFER;
}
void cgRTCgcInit( void )
{
_cgRTCgcCompileProgramHook = &compile_program_from_string;
_cgRTCgcFreeCompiledProgramHook = &free_compiled_program;
}
void cgRTCgcFree( void )
{
_cgRTCgcCompileProgramHook = 0;
_cgRTCgcFreeCompiledProgramHook = 0;
}
jsName _RGLCreateName(jsNameSpace * ns, void* object)
{
if ( ns->firstFree == NULL )
{
int newCapacity = ns->capacity + NAME_INCREMENT;
void** newData = ( void** )malloc( newCapacity * sizeof( void* ) );
if ( newData == NULL )
{
_RGLCgRaiseError( CG_MEMORY_ALLOC_ERROR );
return 0;
}
memcpy( newData, ns->data, ns->capacity * sizeof( void* ) );
if ( ns->data != NULL )
free( ns->data );
ns->data = newData;
for ( int index = ns->capacity; index < newCapacity - 1; ++index )
ns->data[index] = ns->data + index + 1;
ns->data[newCapacity - 1] = NULL;
ns->firstFree = ns->data + ns->capacity;
ns->capacity = newCapacity;
}
jsName result = ns->firstFree - ns->data;
ns->firstFree = ( void** ) * ns->firstFree;
ns->data[result] = object;
return result + 1;
}
unsigned int _RGLIsName(jsNameSpace* ns, jsName name)
{
if ( RGL_UNLIKELY( name == 0 ) )
return 0;
--name;
if ( RGL_UNLIKELY( name >= ns->capacity ) )
return 0;
void** value = ( void** )ns->data[name];
if ( RGL_UNLIKELY( value == NULL ||
(value >= ns->data && value < ns->data + ns->capacity)))
return 0;
return 1;
}
void _RGLEraseName(jsNameSpace* ns, jsName name)
{
if(_RGLIsName( ns, name))
{
--name;
ns->data[name] = ns->firstFree;
ns->firstFree = ns->data + name;
}
}
void _RGLTexNameSpaceInit( jsTexNameSpace *ns, jsTexNameSpaceCreateFunction create, jsTexNameSpaceDestroyFunction destroy )
{
ns->capacity = CAPACITY_INCR;
ns->data = ( void ** )malloc( ns->capacity * sizeof( void* ) );
memset( ns->data, 0, ns->capacity*sizeof( void* ) );
ns->create = create;
ns->destroy = destroy;
}
void _RGLTexNameSpaceFree( jsTexNameSpace *ns )
{
for(GLuint i = 1; i < ns->capacity; ++i)
if ( ns->data[i] ) ns->destroy( ns->data[i] );
if(ns->data != NULL)
free( ns->data );
ns->data = NULL;
}
void _RGLTexNameSpaceResetNames( jsTexNameSpace *ns )
{
for ( GLuint i = 1;i < ns->capacity;++i )
{
if ( ns->data[i] )
{
ns->destroy( ns->data[i] );
ns->data[i] = NULL;
}
}
}
GLuint _RGLTexNameSpaceGetFree( jsTexNameSpace *ns )
{
GLuint i;
for(i = 1; i < ns->capacity; ++i)
if ( !ns->data[i] )
break;
return i;
}
GLboolean _RGLTexNameSpaceCreateNameLazy( jsTexNameSpace *ns, GLuint name )
{
if ( name >= ns->capacity )
{
int newCapacity = name >= ns->capacity + CAPACITY_INCR ? name + 1 : ns->capacity + CAPACITY_INCR;
void **newData = (void**)realloc(ns->data, newCapacity * sizeof(void*));
memset( newData + ns->capacity, 0, (newCapacity - ns->capacity )*sizeof(void*));
ns->data = newData;
ns->capacity = newCapacity;
}
if (!ns->data[name])
{
ns->data[name] = ns->create();
if(ns->data[name])
return GL_TRUE;
}
return GL_FALSE;
}
GLboolean _RGLTexNameSpaceIsName( jsTexNameSpace *ns, GLuint name )
{
if (( name > 0 ) && (name < ns->capacity))
return( ns->data[name] != 0 );
else
return GL_FALSE;
}
void _RGLTexNameSpaceGenNames( jsTexNameSpace *ns, GLsizei n, GLuint *names )
{
for (int i = 0; i < n; ++i)
{
GLuint name = _RGLTexNameSpaceGetFree( ns );
names[i] = name;
if(name)
_RGLTexNameSpaceCreateNameLazy( ns, name );
}
}
void _RGLTexNameSpaceDeleteNames( jsTexNameSpace *ns, GLsizei n, const GLuint *names )
{
for ( int i = 0;i < n;++i )
{
GLuint name = names[i];
if(!_RGLTexNameSpaceIsName(ns, name))
continue;
ns->destroy( ns->data[name] );
ns->data[name] = NULL;
}
}
static inline unsigned int endianSwapWordByHalf( unsigned int v )
{
return (v & 0xffff ) << 16 | v >> 16;
}
static uint32_t gmmInitFixedAllocator (void)
{
pGmmFixedAllocData = (GmmFixedAllocData *)malloc(sizeof(GmmFixedAllocData));
if (pGmmFixedAllocData == NULL)
return GMM_ERROR;
memset(pGmmFixedAllocData, 0, sizeof(GmmFixedAllocData));
for (int i = 0; i < 2; i++)
{
int blockCount = (i==0) ? GMM_BLOCK_COUNT : GMM_TILE_BLOCK_COUNT;
int blockSize = (i==0) ? sizeof(GmmBlock): sizeof(GmmTileBlock);
pGmmFixedAllocData->ppBlockList[i] = (char **)malloc(sizeof(char *));
if (pGmmFixedAllocData->ppBlockList[i] == NULL)
return GMM_ERROR;
pGmmFixedAllocData->ppBlockList[i][0] = (char *)malloc(blockSize * blockCount);
if (pGmmFixedAllocData->ppBlockList[i][0] == NULL)
return GMM_ERROR;
pGmmFixedAllocData->ppFreeBlockList[i] = (uint16_t **)malloc(sizeof(uint16_t *));
if (pGmmFixedAllocData->ppFreeBlockList[i] == NULL)
return GMM_ERROR;
pGmmFixedAllocData->ppFreeBlockList[i][0] = (uint16_t *)malloc(sizeof(uint16_t) * blockCount);
if (pGmmFixedAllocData->ppFreeBlockList[i][0] == NULL)
return GMM_ERROR;
pGmmFixedAllocData->pBlocksUsed[i] = (uint16_t *)malloc(sizeof(uint16_t));
if (pGmmFixedAllocData->pBlocksUsed[i] == NULL)
return GMM_ERROR;
for (int j=0; j<blockCount; j++)
pGmmFixedAllocData->ppFreeBlockList[i][0][j] = j;
pGmmFixedAllocData->pBlocksUsed[i][0] = 0;
pGmmFixedAllocData->BlockListCount[i] = 1;
}
return CELL_OK;
}
static uint8_t gmmSizeToFreeIndex(uint32_t size)
{
if (size >= GMM_FREE_BIN_0 && size < GMM_FREE_BIN_1)
return 0;
else if (size >= GMM_FREE_BIN_1 && size < GMM_FREE_BIN_2)
return 1;
else if (size >= GMM_FREE_BIN_2 && size < GMM_FREE_BIN_3)
return 2;
else if (size >= GMM_FREE_BIN_3 && size < GMM_FREE_BIN_4)
return 3;
else if (size >= GMM_FREE_BIN_4 && size < GMM_FREE_BIN_5)
return 4;
else if (size >= GMM_FREE_BIN_5 && size < GMM_FREE_BIN_6)
return 5;
else if (size >= GMM_FREE_BIN_6 && size < GMM_FREE_BIN_7)
return 6;
else if (size >= GMM_FREE_BIN_7 && size < GMM_FREE_BIN_8)
return 7;
else if (size >= GMM_FREE_BIN_8 && size < GMM_FREE_BIN_9)
return 8;
else if (size >= GMM_FREE_BIN_9 && size < GMM_FREE_BIN_10)
return 9;
else if (size >= GMM_FREE_BIN_10 && size < GMM_FREE_BIN_11)
return 10;
else if (size >= GMM_FREE_BIN_11 && size < GMM_FREE_BIN_12)
return 11;
else if (size >= GMM_FREE_BIN_12 && size < GMM_FREE_BIN_13)
return 12;
else if (size >= GMM_FREE_BIN_13 && size < GMM_FREE_BIN_14)
return 13;
else if (size >= GMM_FREE_BIN_14 && size < GMM_FREE_BIN_15)
return 14;
else if (size >= GMM_FREE_BIN_15 && size < GMM_FREE_BIN_16)
return 15;
else if (size >= GMM_FREE_BIN_16 && size < GMM_FREE_BIN_17)
return 16;
else if (size >= GMM_FREE_BIN_17 && size < GMM_FREE_BIN_18)
return 17;
else if (size >= GMM_FREE_BIN_18 && size < GMM_FREE_BIN_19)
return 18;
else if (size >= GMM_FREE_BIN_19 && size < GMM_FREE_BIN_20)
return 19;
else if (size >= GMM_FREE_BIN_20 && size < GMM_FREE_BIN_21)
return 20;
else
return 21;
}
void gmmAddFree(GmmAllocator *pAllocator, GmmBlock *pBlock)
{
uint8_t freeIndex = gmmSizeToFreeIndex(pBlock->base.size);
if (pAllocator->pFreeHead[freeIndex])
{
GmmBlock *pInsertBefore = pAllocator->pFreeHead[freeIndex];
while (pInsertBefore && pInsertBefore->base.size < pBlock->base.size)
{
pInsertBefore = pInsertBefore->pNextFree;
}
if (pInsertBefore == NULL)
{
pBlock->pNextFree = NULL;
pBlock->pPrevFree = pAllocator->pFreeTail[freeIndex];
pAllocator->pFreeTail[freeIndex]->pNextFree = pBlock;
pAllocator->pFreeTail[freeIndex] = pBlock;
}
else if (pInsertBefore == pAllocator->pFreeHead[freeIndex])
{
pBlock->pNextFree = pInsertBefore;
pBlock->pPrevFree = pInsertBefore->pPrevFree;
pInsertBefore->pPrevFree = pBlock;
pAllocator->pFreeHead[freeIndex] = pBlock;
}
else
{
pBlock->pNextFree = pInsertBefore;
pBlock->pPrevFree = pInsertBefore->pPrevFree;
pInsertBefore->pPrevFree->pNextFree = pBlock;
pInsertBefore->pPrevFree = pBlock;
}
}
else
{
pBlock->pNextFree = NULL;
pBlock->pPrevFree = NULL;
pAllocator->pFreeHead[freeIndex] = pBlock;
pAllocator->pFreeTail[freeIndex] = pBlock;
}
}
static void *gmmAllocFixed(uint8_t isTile)
{
int blockCount = isTile ? GMM_TILE_BLOCK_COUNT : GMM_BLOCK_COUNT;
int blockSize = isTile ? sizeof(GmmTileBlock) : sizeof(GmmBlock);
int listCount = pGmmFixedAllocData->BlockListCount[isTile];
for (int i=0; i<listCount; i++)
{
if (pGmmFixedAllocData->pBlocksUsed[isTile][i] < blockCount)
{
return pGmmFixedAllocData->ppBlockList[isTile][i] +
(pGmmFixedAllocData->ppFreeBlockList[isTile][i][pGmmFixedAllocData->pBlocksUsed[isTile][i]++] *
blockSize);
}
}
char **ppBlockList =
(char **)realloc(pGmmFixedAllocData->ppBlockList[isTile],
(listCount + 1) * sizeof(char *));
if (ppBlockList == NULL)
return NULL;
pGmmFixedAllocData->ppBlockList[isTile] = ppBlockList;
pGmmFixedAllocData->ppBlockList[isTile][listCount] =
(char *)malloc(blockSize * blockCount);
if (pGmmFixedAllocData->ppBlockList[isTile][listCount] == NULL)
return NULL;
uint16_t **ppFreeBlockList =
(uint16_t **)realloc(pGmmFixedAllocData->ppFreeBlockList[isTile],
(listCount + 1) * sizeof(uint16_t *));
if (ppFreeBlockList == NULL)
return NULL;
pGmmFixedAllocData->ppFreeBlockList[isTile] = ppFreeBlockList;
pGmmFixedAllocData->ppFreeBlockList[isTile][listCount] =
(uint16_t *)malloc(sizeof(uint16_t) * blockCount);
if (pGmmFixedAllocData->ppFreeBlockList[isTile][listCount] == NULL)
return NULL;
uint16_t *pBlocksUsed =
(uint16_t *)realloc(pGmmFixedAllocData->pBlocksUsed[isTile],
(listCount + 1) * sizeof(uint16_t));
if (pBlocksUsed == NULL)
return NULL;
pGmmFixedAllocData->pBlocksUsed[isTile] = pBlocksUsed;
for (int i=0; i<blockCount; i++)
pGmmFixedAllocData->ppFreeBlockList[isTile][listCount][i] = i;
pGmmFixedAllocData->pBlocksUsed[isTile][listCount] = 0;
pGmmFixedAllocData->BlockListCount[isTile]++;
return pGmmFixedAllocData->ppBlockList[isTile][listCount] +
(pGmmFixedAllocData->ppFreeBlockList[isTile][listCount][pGmmFixedAllocData->pBlocksUsed[isTile][listCount]++] *
blockSize);
}
static void gmmFreeFixed(uint8_t isTile, void *pBlock)
{
int blockCount = isTile ? GMM_TILE_BLOCK_COUNT : GMM_BLOCK_COUNT;
int blockSize = isTile ? sizeof(GmmTileBlock) : sizeof(GmmBlock);
for (int i=0; i<pGmmFixedAllocData->BlockListCount[isTile]; i++)
{
if (pBlock >= pGmmFixedAllocData->ppBlockList[isTile][i] &&
pBlock < (pGmmFixedAllocData->ppBlockList[isTile][i] + blockSize * blockCount))
{
int index = ((char *)pBlock - pGmmFixedAllocData->ppBlockList[isTile][i]) / blockSize;
pGmmFixedAllocData->ppFreeBlockList[isTile][i][--pGmmFixedAllocData->pBlocksUsed[isTile][i]] = index;
}
}
}
uint32_t gmmInit(
const void *localMemoryBase,
const void *localStartAddress,
const uint32_t localSize,
const void *mainMemoryBase,
const void *mainStartAddress,
const uint32_t mainSize
)
{
GmmAllocator *pAllocator[2];
uint32_t alignedLocalSize, alignedMainSize;
uint32_t localEndAddress = (uint32_t)localStartAddress + localSize;
uint32_t mainEndAddress = (uint32_t)mainStartAddress + mainSize;
localEndAddress = (localEndAddress / GMM_TILE_ALIGNMENT) * GMM_TILE_ALIGNMENT;
mainEndAddress = (mainEndAddress / GMM_TILE_ALIGNMENT) * GMM_TILE_ALIGNMENT;
alignedLocalSize = localEndAddress - (uint32_t)localStartAddress;
alignedMainSize = mainEndAddress - (uint32_t)mainStartAddress;
pAllocator[0] = (GmmAllocator *)malloc(2*sizeof(GmmAllocator));
pAllocator[1] = pAllocator[0] + 1;
if (pAllocator[0] == NULL)
return GMM_ERROR;
memset(pAllocator[0], 0, 2*sizeof(GmmAllocator));
if (pAllocator[0])
{
pAllocator[0]->memoryBase = (uint32_t)localMemoryBase;
pAllocator[1]->memoryBase = (uint32_t)mainMemoryBase;
pAllocator[0]->startAddress = (uint32_t)localStartAddress;
pAllocator[1]->startAddress = (uint32_t)mainStartAddress;
pAllocator[0]->size = alignedLocalSize;
pAllocator[1]->size = alignedMainSize;
pAllocator[0]->freeAddress = pAllocator[0]->startAddress;
pAllocator[1]->freeAddress = pAllocator[1]->startAddress;
pAllocator[0]->tileStartAddress = ((uint32_t)localStartAddress) + alignedLocalSize;
pAllocator[1]->tileStartAddress = ((uint32_t)mainStartAddress) + alignedMainSize;
pAllocator[0]->totalSize = alignedLocalSize;
pAllocator[1]->totalSize = alignedMainSize;
pGmmLocalAllocator = pAllocator[0];
pGmmMainAllocator = pAllocator[1];
}
else
return GMM_ERROR;
pLock = cellGcmGetLabelAddress(GMM_PPU_WAIT_INDEX);
*pLock = 0;
cachedLockValue = 0;
return gmmInitFixedAllocator();
}
void gmmSetTileAttrib(const uint32_t id, const uint32_t tag, void *pData)
{
GmmTileBlock *pTileBlock = (GmmTileBlock *)id;
pTileBlock->tileTag = tag;
pTileBlock->pData = pData;
}
uint32_t gmmIdToOffset(const uint32_t id)
{
GmmBaseBlock *pBaseBlock = (GmmBaseBlock *)id;
return gmmAddressToOffset(pBaseBlock->address, pBaseBlock->isMain);
}
char *gmmIdToAddress(const uint32_t id)
{
GmmBaseBlock *pBaseBlock = (GmmBaseBlock *)id;
do
{
if (cachedLockValue == 0)
break;
cachedLockValue = *pLock;
if (cachedLockValue == 0)
break;
}while(1);
return (char *)pBaseBlock->address;
}
static void _RGLGetTileRegionInfo(void* data, GLuint *address, GLuint *size)
{
jsTiledRegion* region = ( jsTiledRegion* )data;
*address = region->offset;
*size = region->size;
}
static GmmBlock *gmmAllocBlock(GmmAllocator *pAllocator, uint32_t size)
{
uint32_t address;
GmmBlock *pNewBlock = NULL;
GmmBlock *pBlock = pAllocator->pTail;
address = pAllocator->freeAddress;
if (UINT_MAX - address >= size &&
address + size <= pAllocator->startAddress + pAllocator->size)
{
pNewBlock = (GmmBlock *)gmmAllocFixed(0);
if (pNewBlock == NULL)
return NULL;
memset(pNewBlock, 0, sizeof(GmmBlock));
pNewBlock->base.address = address;
pNewBlock->base.isMain = (pAllocator == pGmmMainAllocator);
pNewBlock->base.size = size;
pAllocator->freeAddress = address + size;
if (pBlock)
{
pNewBlock->pPrev = pBlock;
pBlock->pNext = pNewBlock;
pAllocator->pTail = pNewBlock;
}
else
{
pAllocator->pHead = pNewBlock;
pAllocator->pTail = pNewBlock;
}
}
return pNewBlock;
}
static GmmTileBlock *gmmFindFreeTileBlock(GmmAllocator *pAllocator, const uint32_t size)
{
GmmTileBlock *pBlock = pAllocator->pTileHead;
GmmTileBlock *pBestAfterBlock = NULL;
GmmTileBlock *pNewBlock = NULL;
uint32_t bestSize = 0;
uint32_t freeSize = 0;
while (pBlock && pBlock->pNext)
{
freeSize = pBlock->pNext->base.address - pBlock->base.address - pBlock->base.size;
if (freeSize >= size &&
(pBestAfterBlock == NULL || freeSize < bestSize) &&
(pBlock->pNext == NULL ||
pBlock->pData != pBlock->pNext->pData))
{
pBestAfterBlock = pBlock;
bestSize = freeSize;
}
pBlock = pBlock->pNext;
}
if (pBestAfterBlock)
{
pNewBlock = (GmmTileBlock *)gmmAllocFixed(1);
if (pNewBlock == NULL)
return NULL;
memset(pNewBlock, 0, sizeof(GmmTileBlock));
pNewBlock->base.address = pBestAfterBlock->base.address + pBestAfterBlock->base.size;
pNewBlock->base.isMain = (pAllocator == pGmmMainAllocator);
pNewBlock->base.isTile = 1;
pNewBlock->base.size = size;
pNewBlock->pNext = pBestAfterBlock->pNext;
pNewBlock->pPrev = pBestAfterBlock;
pNewBlock->pPrev->pNext = pNewBlock;
pNewBlock->pNext->pPrev = pNewBlock;
return pNewBlock;
}
else
return NULL;
}
static GmmTileBlock *gmmCreateTileBlock(GmmAllocator *pAllocator, const uint32_t size)
{
GmmTileBlock *pNewBlock;
uint32_t address;
address = pAllocator->tileStartAddress - size;
if (address > pAllocator->startAddress + pAllocator->size)
return NULL;
if (pAllocator->pTail &&
pAllocator->pTail->base.address + pAllocator->pTail->base.size > address)
return NULL;
pAllocator->size = address - pAllocator->startAddress;
pAllocator->tileSize = pAllocator->tileStartAddress + pAllocator->tileSize - address;
pAllocator->tileStartAddress = address;
pNewBlock = (GmmTileBlock *)gmmAllocFixed(1);
if (pNewBlock == NULL)
return NULL;
memset(pNewBlock, 0, sizeof(GmmTileBlock));
pNewBlock->base.address = address;
pNewBlock->base.isMain = (pAllocator == pGmmMainAllocator);
pNewBlock->base.isTile = 1;
pNewBlock->base.size = size;
pNewBlock->pNext = pAllocator->pTileHead;
if (pAllocator->pTileHead)
pAllocator->pTileHead->pPrev = pNewBlock;
else
pAllocator->pTileTail = pNewBlock;
pAllocator->pTileHead = pNewBlock;
return pNewBlock;
}
static void gmmFreeTileBlock(GmmTileBlock *pTileBlock)
{
GmmAllocator *pAllocator;
if (pTileBlock->pPrev)
pTileBlock->pPrev->pNext = pTileBlock->pNext;
if (pTileBlock->pNext)
pTileBlock->pNext->pPrev = pTileBlock->pPrev;
if (pTileBlock->base.isMain)
pAllocator = pGmmMainAllocator;
else
pAllocator = pGmmLocalAllocator;
if (pAllocator->pTileHead == pTileBlock)
{
pAllocator->pTileHead = pTileBlock->pNext;
if (pAllocator->pTileHead)
pAllocator->pTileHead->pPrev = NULL;
pAllocator->size = pAllocator->pTileHead ?
pAllocator->pTileHead->base.address - pAllocator->startAddress :
pAllocator->totalSize;
pAllocator->tileSize = pAllocator->totalSize - pAllocator->size;
pAllocator->tileStartAddress = pAllocator->pTileHead ?
pAllocator->pTileHead->base.address :
pAllocator->startAddress + pAllocator->size;
}
if (pAllocator->pTileTail == pTileBlock)
{
pAllocator->pTileTail = pTileBlock->pPrev;
if (pAllocator->pTileTail)
pAllocator->pTileTail->pNext = NULL;
}
gmmFreeFixed(1, pTileBlock);
}
uint32_t gmmAllocExtendedTileBlock(const uint32_t size, const uint32_t tag)
{
GmmAllocator *pAllocator = pGmmLocalAllocator;
uint32_t retId = 0;
uint32_t newSize;
uint8_t resizeSucceed = 1;
newSize = pad(size, GMM_TILE_ALIGNMENT);
GmmTileBlock *pBlock = pAllocator->pTileTail;
while (pBlock)
{
if (pBlock->tileTag == tag)
{
GLuint address, tileSize;
_RGLGetTileRegionInfo(pBlock->pData, &address, &tileSize);
if ((pBlock->pNext && pBlock->pNext->base.address-pBlock->base.address-pBlock->base.size >= newSize) ||
(pBlock->pPrev && pBlock->base.address-pBlock->pPrev->base.address-pBlock->pPrev->base.size >= newSize))
{
GmmTileBlock *pNewBlock = (GmmTileBlock *)gmmAllocFixed(1);
if (pNewBlock == NULL)
break;
retId = (uint32_t)pNewBlock;
memset(pNewBlock, 0, sizeof(GmmTileBlock));
pNewBlock->base.isMain = (pAllocator == pGmmMainAllocator);
pNewBlock->base.isTile = 1;
pNewBlock->base.size = newSize;
if (pBlock->pNext && pBlock->pNext->base.address-pBlock->base.address-pBlock->base.size >= newSize)
{
pNewBlock->base.address = pBlock->base.address+pBlock->base.size;
pNewBlock->pNext = pBlock->pNext;
pNewBlock->pPrev = pBlock;
pBlock->pNext->pPrev = pNewBlock;
pBlock->pNext = pNewBlock;
if (pNewBlock->pPrev->pData != pNewBlock->pNext->pData)
{
resizeSucceed = _RGLTryResizeTileRegion( address, tileSize+newSize, pBlock->pData );
}
}
else
{
pNewBlock->base.address = pBlock->base.address-newSize;
pNewBlock->pNext = pBlock;
pNewBlock->pPrev = pBlock->pPrev;
pBlock->pPrev->pNext = pNewBlock;
pBlock->pPrev = pNewBlock;
if (pNewBlock->pPrev->pData != pNewBlock->pNext->pData)
{
GmmBaseBlock *pBaseBlock = (GmmBaseBlock *)(uint32_t)(pNewBlock);
resizeSucceed = _RGLTryResizeTileRegion((GLuint)gmmAddressToOffset(pBaseBlock->address, pBaseBlock->isMain), tileSize+newSize, pBlock->pData);
}
}
gmmSetTileAttrib( retId, tag, pBlock->pData );
break;
}
if (pBlock == pAllocator->pTileHead)
{
retId = (uint32_t)gmmCreateTileBlock(pAllocator, newSize);
if (retId == 0)
break;
resizeSucceed = _RGLTryResizeTileRegion( (GLuint)gmmIdToOffset(retId), tileSize+newSize, pBlock->pData );
gmmSetTileAttrib( retId, tag, pBlock->pData );
break;
}
}
pBlock = pBlock->pPrev;
}
if (retId == 0)
return GMM_ERROR;
if (!resizeSucceed)
{
gmmFreeTileBlock((GmmTileBlock *)retId);
return GMM_ERROR;
}
return retId;
}
static GmmTileBlock *gmmAllocTileBlock(
GmmAllocator *pAllocator,
const uint32_t size
)
{
GmmTileBlock *pBlock = gmmFindFreeTileBlock(pAllocator, size);
if (pBlock == NULL)
pBlock = gmmCreateTileBlock(pAllocator, size);
return pBlock;
}
static void gmmFreeBlock(GmmBlock *pBlock)
{
GmmAllocator *pAllocator;
if (pBlock->pPrev)
pBlock->pPrev->pNext = pBlock->pNext;
if (pBlock->pNext)
pBlock->pNext->pPrev = pBlock->pPrev;
if (pBlock->base.isMain)
pAllocator = pGmmMainAllocator;
else
pAllocator = pGmmLocalAllocator;
if (pAllocator->pHead == pBlock)
{
pAllocator->pHead = pBlock->pNext;
if (pAllocator->pHead)
pAllocator->pHead->pPrev = NULL;
}
if (pAllocator->pTail == pBlock)
{
pAllocator->pTail = pBlock->pPrev;
if (pAllocator->pTail)
pAllocator->pTail->pNext = NULL;
}
if (pBlock->pPrev == NULL)
pAllocator->pSweepHead = pAllocator->pHead;
else if (pBlock->pPrev &&
(pAllocator->pSweepHead == NULL ||
(pAllocator->pSweepHead &&
pAllocator->pSweepHead->base.address > pBlock->pPrev->base.address)))
{
pAllocator->pSweepHead = pBlock->pPrev;
}
pAllocator->freedSinceSweep += pBlock->base.size;
gmmFreeFixed(0, pBlock);
}
static void gmmAddPendingFree(GmmBlock *pBlock)
{
GmmAllocator *pAllocator;
if (pBlock->base.isMain)
pAllocator = pGmmMainAllocator;
else
pAllocator = pGmmLocalAllocator;
if (pAllocator->pPendingFreeTail)
{
pBlock->pNextFree = NULL;
pBlock->pPrevFree = pAllocator->pPendingFreeTail;
pAllocator->pPendingFreeTail->pNextFree = pBlock;
pAllocator->pPendingFreeTail = pBlock;
}
else
{
pBlock->pNextFree = NULL;
pBlock->pPrevFree = NULL;
pAllocator->pPendingFreeHead = pBlock;
pAllocator->pPendingFreeTail = pBlock;
}
pBlock->isPinned = 0;
GLuint* ref = &pBlock->fence;
++nvFenceCounter;
cellGcmSetWriteBackEndLabelInline( &_RGLState.fifo, SEMA_FENCE, nvFenceCounter);
*ref = nvFenceCounter;
}
uint32_t gmmFree(const uint32_t freeId)
{
GmmBaseBlock *pBaseBlock = (GmmBaseBlock *)freeId;
if (pBaseBlock->isTile)
{
GmmTileBlock *pTileBlock = (GmmTileBlock *)pBaseBlock;
if (pTileBlock->pPrev &&
pTileBlock->pNext &&
pTileBlock->pPrev->pData == pTileBlock->pNext->pData)
{
}
else if (pTileBlock->pPrev && pTileBlock->pPrev->pData == pTileBlock->pData)
{
GLuint address, size;
_RGLGetTileRegionInfo(pTileBlock->pData, &address, &size);
if ( !_RGLTryResizeTileRegion(address, (size-pTileBlock->base.size), pTileBlock->pData) )
{
_RGLTryResizeTileRegion(address, 0, pTileBlock->pData);
if ( !_RGLTryResizeTileRegion(address, (size-pTileBlock->base.size), pTileBlock->pData) )
{
}
}
}
else if (pTileBlock->pNext && pTileBlock->pNext->pData == pTileBlock->pData)
{
GLuint address, size;
_RGLGetTileRegionInfo(pTileBlock->pData, &address, &size);
if ( !_RGLTryResizeTileRegion((address+pTileBlock->base.size), (size-pTileBlock->base.size), pTileBlock->pData) )
{
_RGLTryResizeTileRegion(address, 0, pTileBlock->pData);
if ( !_RGLTryResizeTileRegion((address+pTileBlock->base.size), (size-pTileBlock->base.size), pTileBlock->pData) )
{
}
}
}
else
{
if ( !_RGLTryResizeTileRegion( (GLuint)gmmIdToOffset(freeId), 0, ((GmmTileBlock *)freeId)->pData ) )
{
}
}
gmmFreeTileBlock(pTileBlock);
}
else
{
GmmBlock *pBlock = (GmmBlock *)pBaseBlock;
gmmAddPendingFree(pBlock);
}
return CELL_OK;
}
static inline void gmmLocalMemcpy(
const uint32_t dstOffset,
const uint32_t srcOffset,
const uint32_t moveSize
)
{
CellGcmContextData *thisContext = &_RGLState.fifo;
int32_t offset = 0;
int32_t sizeLeft = moveSize;
int32_t dimension = 4096;
while (sizeLeft)
{
while(sizeLeft >= dimension*dimension*4)
{
cellGcmSetTransferImage(thisContext,
CELL_GCM_TRANSFER_LOCAL_TO_LOCAL,
dstOffset+offset,
dimension*4,
0,
0,
srcOffset+offset,
dimension*4,
0,
0,
dimension,
dimension,
4);
offset = offset + dimension*dimension*4;
sizeLeft = sizeLeft - (dimension*dimension*4);
}
dimension = dimension >> 1;
if (dimension == 32)
break;
}
if (sizeLeft)
cellGcmSetTransferImage(thisContext,
CELL_GCM_TRANSFER_LOCAL_TO_LOCAL,
dstOffset+offset,
sizeLeft,
0,
0,
srcOffset+offset,
sizeLeft,
0,
0,
sizeLeft/4,
1,
4);
}
static uint8_t gmmInternalSweep (void)
{
GmmAllocator *pAllocator = pGmmLocalAllocator;
GmmBlock *pBlock;
GmmBlock *pSrcBlock;
GmmBlock *pTempBlock;
GmmBlock *pTempBlockNext;
uint32_t dstAddress, srcAddress;
uint32_t srcOffset, dstOffset;
uint32_t prevEndAddress;
uint32_t moveSize, moveDistance;
uint8_t ret = 0;
uint32_t totalMoveSize = 0;
pBlock = pAllocator->pSweepHead;
srcAddress = 0;
dstAddress = 0;
prevEndAddress = 0;
pSrcBlock = pBlock;
while (pBlock != NULL)
{
if (pBlock->isPinned == 0)
{
if (pBlock->pPrev)
prevEndAddress = pBlock->pPrev->base.address + pBlock->pPrev->base.size;
else
prevEndAddress = pAllocator->startAddress;
if (pBlock->base.address > prevEndAddress)
{
dstAddress = prevEndAddress;
srcAddress = pBlock->base.address;
pSrcBlock = pBlock;
}
moveSize = pBlock->base.address + pBlock->base.size - srcAddress;
if (srcAddress > dstAddress &&
(pBlock->pNext == NULL ||
pBlock->pNext->base.address > pBlock->base.address + pBlock->base.size ||
pBlock->pNext->isPinned))
{
dstOffset = gmmAddressToOffset(dstAddress, 0);
srcOffset = gmmAddressToOffset(srcAddress, 0);
totalMoveSize += moveSize;
if (dstOffset + moveSize <= srcOffset)
gmmLocalMemcpy(dstOffset, srcOffset, moveSize);
else
{
uint32_t moveBlockSize = srcOffset-dstOffset;
uint32_t iterations = (moveSize+moveBlockSize-1)/moveBlockSize;
for (uint32_t i = 0; i < iterations; i++)
gmmLocalMemcpy(dstOffset+(i*moveBlockSize), srcOffset+(i*moveBlockSize), moveBlockSize);
}
pTempBlock = pSrcBlock;
moveDistance = srcOffset - dstOffset;
while (pTempBlock != pBlock->pNext)
{
pTempBlock->base.address -= moveDistance;
pTempBlock = pTempBlock->pNext;
}
}
}
else
{
uint32_t availableSize;
srcAddress = 0;
dstAddress = 0;
if (pBlock->pPrev == NULL)
availableSize = pBlock->base.address - pAllocator->startAddress;
else
availableSize = pBlock->base.address - (pBlock->pPrev->base.address + pBlock->pPrev->base.size);
pTempBlock = pBlock->pNext;
while (availableSize >= GMM_ALIGNMENT && pTempBlock)
{
pTempBlockNext = pTempBlock->pNext;
if (pTempBlock->isPinned == 0 && pTempBlock->base.size <= availableSize)
{
uint32_t pinDstAddress = (pBlock->pPrev == NULL) ?
pAllocator->startAddress :
pBlock->pPrev->base.address + pBlock->pPrev->base.size;
uint32_t pinSrcAddress = pTempBlock->base.address;
uint32_t moveSize = pTempBlock->base.size;
dstOffset = gmmAddressToOffset(pinDstAddress, 0);
srcOffset = gmmAddressToOffset(pinSrcAddress, 0);
totalMoveSize += moveSize;
if (dstOffset + moveSize <= srcOffset)
gmmLocalMemcpy(dstOffset, srcOffset, moveSize);
else
{
uint32_t moveBlockSize = srcOffset-dstOffset;
uint32_t iterations = (moveSize+moveBlockSize-1)/moveBlockSize;
for (uint32_t i = 0; i < iterations; i++)
gmmLocalMemcpy(dstOffset+(i*moveBlockSize), srcOffset+(i*moveBlockSize), moveBlockSize);
}
pTempBlock->base.address = pinDstAddress;
if (pTempBlock == pAllocator->pTail)
{
if (pTempBlock->pNext)
pAllocator->pTail = pTempBlock->pNext;
else
pAllocator->pTail = pTempBlock->pPrev;
}
if (pTempBlock->pNext)
pTempBlock->pNext->pPrev = pTempBlock->pPrev;
if (pTempBlock->pPrev)
pTempBlock->pPrev->pNext = pTempBlock->pNext;
if (pBlock->pPrev)
pBlock->pPrev->pNext = pTempBlock;
else
pAllocator->pHead = pTempBlock;
pTempBlock->pPrev = pBlock->pPrev;
pTempBlock->pNext = pBlock;
pBlock->pPrev = pTempBlock;
}
if (pBlock->pPrev)
availableSize = pBlock->base.address - (pBlock->pPrev->base.address + pBlock->pPrev->base.size);
pTempBlock = pTempBlockNext;
}
if (availableSize)
{
GmmBlock *pNewBlock = (GmmBlock *)gmmAllocFixed(0);
if (pNewBlock)
{
memset(pNewBlock, 0, sizeof(GmmBlock));
pNewBlock->base.address = pBlock->base.address - availableSize;
pNewBlock->base.isMain = pBlock->base.isMain;
pNewBlock->base.size = availableSize;
pNewBlock->pNext = pBlock;
pNewBlock->pPrev = pBlock->pPrev;
if (pBlock->pPrev)
pBlock->pPrev->pNext = pNewBlock;
pBlock->pPrev = pNewBlock;
if (pBlock == pAllocator->pHead)
pAllocator->pHead = pNewBlock;
gmmAddFree(pAllocator, pNewBlock);
ret = 1;
}
}
}
pBlock = pBlock->pNext;
}
uint32_t newFreeAddress = pAllocator->pTail ?
pAllocator->pTail->base.address + pAllocator->pTail->base.size :
pAllocator->startAddress;
if (pAllocator->freeAddress != newFreeAddress)
{
pAllocator->freeAddress = newFreeAddress;
ret = 1;
}
pAllocator->freedSinceSweep = 0;
pAllocator->pSweepHead = NULL;
return ret;
}
static void gmmFreeAll (void)
{
GmmAllocator *pAllocator = pGmmLocalAllocator;
GmmBlock *pBlock;
GmmBlock *pTemp;
pBlock = pAllocator->pPendingFreeHead;
while (pBlock)
{
pTemp = pBlock->pNextFree;
gmmFreeBlock(pBlock);
pBlock = pTemp;
}
pAllocator->pPendingFreeHead = NULL;
pAllocator->pPendingFreeTail = NULL;
for (int i=0; i<GMM_NUM_FREE_BINS; i++)
{
pBlock = pAllocator->pFreeHead[i];
while (pBlock)
{
pTemp = pBlock->pNextFree;
gmmFreeBlock(pBlock);
pBlock = pTemp;
}
pAllocator->pFreeHead[i] = NULL;
pAllocator->pFreeTail[i] = NULL;
}
}
static uint32_t gmmFindFreeBlock(
GmmAllocator *pAllocator,
uint32_t size
)
{
uint32_t retId = GMM_ERROR;
GmmBlock *pBlock;
uint8_t found = 0;
uint8_t freeIndex = gmmSizeToFreeIndex(size);
pBlock = pAllocator->pFreeHead[freeIndex];
while (freeIndex < GMM_NUM_FREE_BINS)
{
if (pBlock)
{
if (pBlock->base.size >= size)
{
found = 1;
break;
}
pBlock = pBlock->pNextFree;
}
else if (++freeIndex < GMM_NUM_FREE_BINS)
pBlock = pAllocator->pFreeHead[freeIndex];
}
if (found)
{
if (pBlock->base.size != size)
{
// create a new block here
GmmBlock *pNewBlock = (GmmBlock *)gmmAllocFixed(0);
if (pNewBlock == NULL)
return GMM_ERROR;
memset(pNewBlock, 0, sizeof(GmmBlock));
pNewBlock->base.address = pBlock->base.address + size;
pNewBlock->base.isMain = pBlock->base.isMain;
pNewBlock->base.size = pBlock->base.size - size;
pNewBlock->pNext = pBlock->pNext;
pNewBlock->pPrev = pBlock;
if (pBlock->pNext)
pBlock->pNext->pPrev = pNewBlock;
pBlock->pNext = pNewBlock;
if (pBlock == pAllocator->pTail)
pAllocator->pTail = pNewBlock;
gmmAddFree(pAllocator, pNewBlock);
}
pBlock->base.size = size;
if (pBlock == pAllocator->pFreeHead[freeIndex])
pAllocator->pFreeHead[freeIndex] = pBlock->pNextFree;
if (pBlock == pAllocator->pFreeTail[freeIndex])
pAllocator->pFreeTail[freeIndex] = pBlock->pPrevFree;
if (pBlock->pNextFree)
pBlock->pNextFree->pPrevFree = pBlock->pPrevFree;
if (pBlock->pPrevFree)
pBlock->pPrevFree->pNextFree = pBlock->pNextFree;
retId = (uint32_t)pBlock;
}
return retId;
}
uint32_t gmmAlloc(const uint8_t isTile, const uint32_t size)
{
CellGcmContextData *thisContext = (CellGcmContextData*)&_RGLState.fifo;
GmmAllocator *pAllocator;
uint32_t retId;
uint32_t newSize;
if (__builtin_expect((size == 0),0))
return GMM_ERROR;
pAllocator = pGmmLocalAllocator;
if (!isTile)
{
newSize = pad(size, GMM_ALIGNMENT);
retId = gmmFindFreeBlock(pAllocator, newSize);
}
else
{
newSize = pad(size, GMM_TILE_ALIGNMENT);
retId = GMM_ERROR;
}
if (retId == GMM_ERROR)
{
if (isTile)
retId = (uint32_t)gmmAllocTileBlock(pAllocator, newSize);
else
retId = (uint32_t)gmmAllocBlock(pAllocator, newSize);
if (retId == MEMORY_ALLOC_ERROR)
{
gmmFreeAll();
if (gmmInternalSweep())
{
*pLock = 1;
cachedLockValue = 1;
cellGcmSetWriteBackEndLabel(thisContext, GMM_PPU_WAIT_INDEX, 0);
cellGcmFlush(thisContext);
}
if (isTile)
retId = (uint32_t)gmmAllocTileBlock(pAllocator, newSize);
else
retId = (uint32_t)gmmAllocBlock(pAllocator, newSize);
if (!isTile && retId == MEMORY_ALLOC_ERROR)
retId = gmmFindFreeBlock(pAllocator, newSize);
}
}
return retId;
}
static int _RGLLoadFPShader( _CGprogram *program )
{
unsigned int ucodeSize = program->header.instructionCount * 16;
if ( program->loadProgramId == GMM_ERROR )
{
program->loadProgramId = gmmAlloc(0, ucodeSize);
program->loadProgramOffset = 0;
}
unsigned int dstId = program->loadProgramId;
unsigned dstOffset = program->loadProgramOffset;
const char *src = (char*)program->ucode;
GLuint id = gmmAlloc(0, ucodeSize);
memcpy( gmmIdToAddress(id), src, ucodeSize );
_RGLMemcpy( dstId, dstOffset, 0, id, ucodeSize );
gmmFree( id );
return GL_TRUE;
}
void _RGLPlatformSetVertexRegister4fv( unsigned int reg, const float * __restrict v ) {}
void _RGLPlatformSetVertexRegisterBlock( unsigned int reg, unsigned int count, const float * __restrict v ) {}
void _RGLPlatformSetFragmentRegister4fv( unsigned int reg, const float * __restrict v ) {}
void _RGLPlatformSetFragmentRegisterBlock( unsigned int reg, unsigned int count, const float * __restrict v ) {}
template<int SIZE> inline static void swapandsetfp( int ucodeSize, unsigned int loadProgramId, unsigned int loadProgramOffset, unsigned short *ec, const unsigned int * __restrict v )
{
cellGcmSetTransferLocationInline ( &_RGLState.fifo, CELL_GCM_LOCATION_LOCAL);
unsigned short count = *( ec++ );
for ( unsigned long offsetIndex = 0; offsetIndex < count; ++offsetIndex )
{
void *ptr = NULL;
const int paddedSIZE = (SIZE + 1) & ~1;
cellGcmSetInlineTransferPointerInline( &_RGLState.fifo, gmmIdToOffset( loadProgramId ) + loadProgramOffset + *(ec++), paddedSIZE, &ptr);
float *fp = (float*)ptr;
float *src = (float*)v;
for (uint32_t j=0; j<SIZE;j++)
{
*fp = cellGcmSwap16Float32(*src);
fp++;src++;
}
}
}
template<int SIZE> static void setVectorTypefp( CgRuntimeParameter* __restrict ptr, const void* __restrict v )
{
float * __restrict f = ( float* )v;
float * __restrict data = ( float* )ptr->pushBufferPointer;
for ( long i = 0; i < SIZE; ++i )
data[i] = f[i];
_CGprogram *program = ptr->program;
CgParameterResource *parameterResource = _RGLGetParameterResource( ptr->program, ptr->parameterEntry );
unsigned short resource = parameterResource->resource;
unsigned short *ec = ( unsigned short * )( ptr->program->resources ) + resource + 1;
if ( RGL_LIKELY( *ec ) )
{
swapandsetfp<SIZE>(program->header.instructionCount*16, program->loadProgramId, program->loadProgramOffset, ec, (unsigned int *)data);
}
}
template<int SIZE> static void setVectorTypeSharedfpIndex( CgRuntimeParameter* __restrict ptr, const void* __restrict v, const int ) {}
template<int SIZE> static void setVectorTypeSharedfpIndexArray( CgRuntimeParameter* __restrict ptr, const void* __restrict v, const int index ) {}
template<int SIZE> static void setVectorTypeSharedvpIndex( CgRuntimeParameter* __restrict ptr, const void* __restrict v, const int )
{
const float * __restrict f = ( const float * __restrict )v;
const CgParameterResource *parameterResource = _RGLGetParameterResource( ptr->program, ptr->parameterEntry );
unsigned short resource = parameterResource->resource;
float * __restrict dst = (float * __restrict)ptr->pushBufferPointer;
for (long i = 0; i < SIZE; ++i)
dst[i] = f[i];
_RGLPlatformSetVertexRegister4fv( resource, dst );
}
template<int SIZE> static void setVectorTypeSharedvpIndexArray( CgRuntimeParameter* __restrict ptr, const void* __restrict v, const int index )
{
const float * __restrict f = ( const float * __restrict )v;
const CgParameterResource *parameterResource = _RGLGetParameterResource( ptr->program, ptr->parameterEntry );
unsigned short resource = parameterResource->resource + index;
float * __restrict dst = ( float * __restrict )ptr->pushBufferPointer;
for ( long i = 0; i < SIZE; ++ i )
dst[i] = f[i];
_RGLPlatformSetVertexRegister4fv( resource, dst );
}
template <int SIZE> static void setVectorTypevpIndex( CgRuntimeParameter* __restrict ptr, const void* __restrict v, const int )
{
PSGLcontext * LContext = _CurrentContext;
const float * __restrict f = ( const float* )v;
float * __restrict dst = ( float* )ptr->pushBufferPointer;
for ( long i = 0; i < SIZE; ++ i )
dst[i] = f[i];
LContext->needValidate |= PSGL_VALIDATE_VERTEX_CONSTANTS;
}
template <int SIZE> static void setVectorTypevpIndexArray( CgRuntimeParameter* __restrict ptr, const void* __restrict v, const int index )
{
PSGLcontext * LContext = _CurrentContext;
const float * __restrict f = ( const float* )v;
float * __restrict dst = ( float* )( *(( unsigned int ** )ptr->pushBufferPointer + index ) );
for ( long i = 0; i < SIZE; ++ i )
dst[i] = f[i];
LContext->needValidate |= PSGL_VALIDATE_VERTEX_CONSTANTS;
}
template<int SIZE> static void setVectorTypefpIndex( CgRuntimeParameter* __restrict ptr, const void* __restrict v, const int )
{
float * __restrict f = ( float* )v;
float * __restrict data = ( float* )ptr->pushBufferPointer;
for ( long i = 0; i < SIZE; ++i )
data[i] = f[i];
_CGprogram *program = ptr->program;
const CgParameterResource *parameterResource = _RGLGetParameterResource( program, ptr->parameterEntry );
unsigned short resource = parameterResource->resource;
unsigned short *ec = ( unsigned short * )( ptr->program->resources ) + resource + 1;
if ( RGL_LIKELY( *ec ) )
{
swapandsetfp<SIZE>( program->header.instructionCount*16, program->loadProgramId, program->loadProgramOffset, ec, ( unsigned int * )data );
}
}
template<int SIZE> static void setVectorTypefpIndexArray( CgRuntimeParameter* __restrict ptr, const void* __restrict v, const int index )
{
float * __restrict f = ( float* )v;
float * __restrict data = ( float* )ptr->pushBufferPointer;
for ( long i = 0; i < SIZE; ++i )
data[i] = f[i];
_CGprogram *program = ptr->program;
const CgParameterResource *parameterResource = _RGLGetParameterResource( program, ptr->parameterEntry );
unsigned short resource = parameterResource->resource;
unsigned short *ec = ( unsigned short * )( program->resources ) + resource + 1;
int arrayIndex = index;
while ( arrayIndex )
{
ec += (( *ec ) + 2 );
arrayIndex--;
}
if ( RGL_LIKELY( *ec ) )
{
swapandsetfp<SIZE>( program->header.instructionCount*16, program->loadProgramId, program->loadProgramOffset, ec, ( unsigned int * )data );
}
}
template <int ROWS, int COLS, int ORDER> static void setMatrixvpIndex( CgRuntimeParameter* __restrict ptr, const void* __restrict v, const int index )
{
PSGLcontext * LContext = _CurrentContext;
float * __restrict f = ( float* )v;
float * __restrict dst = ( float* )ptr->pushBufferPointer;
for ( long row = 0; row < ROWS; ++row )
{
for ( long col = 0; col < COLS; ++col )
dst[row * 4 + col] = ( ORDER == ROW_MAJOR ) ? f[row * COLS + col] : f[col * ROWS + row];
}
LContext->needValidate |= PSGL_VALIDATE_VERTEX_CONSTANTS;
}
template <int ROWS, int COLS, int ORDER> static void setMatrixSharedvpIndex( CgRuntimeParameter* __restrict ptr, const void* __restrict v, const int /*index*/ )
{
float * __restrict f = ( float* )v;
float * __restrict dst = ( float* )ptr->pushBufferPointer;
const CgParameterResource *parameterResource = _RGLGetParameterResource( ptr->program, ptr->parameterEntry );
unsigned short resource = parameterResource->resource;
float tmp[ROWS*4];
for ( long row = 0; row < ROWS; ++row )
{
for(long col = 0; col < COLS; ++col)
tmp[row*4 + col] = dst[row * 4 + col] = ( ORDER == ROW_MAJOR ) ? f[row * COLS + col] : f[col * ROWS + row];
for(long col = COLS; col < 4; ++col)
tmp[row*4 + col] = dst[row*4+col];
}
cellGcmSetVertexProgramParameterBlockInline( &_RGLState.fifo, resource, ROWS, (const float*)tmp);
}
template <int ROWS, int COLS, int ORDER> static void setMatrixSharedvpIndexArray( CgRuntimeParameter* __restrict ptr, const void* __restrict v, const int index )
{
float * __restrict f = ( float* )v;
float * __restrict dst = ( float* )ptr->pushBufferPointer;
const CgParameterResource *parameterResource = _RGLGetParameterResource( ptr->program, ptr->parameterEntry );
unsigned short resource = parameterResource->resource + index * ROWS;
float tmp[ROWS*4];
for ( long row = 0; row < ROWS; ++row )
{
for ( long col = 0; col < COLS; ++col )
{
tmp[row*4 + col] = dst[row * 4 + col] = ( ORDER == ROW_MAJOR ) ? f[row * COLS + col] : f[col * ROWS + row];
}
for ( long col = COLS; col < 4; ++col ) tmp[row*4 + col] = dst[row*4+col];
}
cellGcmSetVertexProgramParameterBlockInline( &_RGLState.fifo, resource, ROWS, (const float*)tmp);
}
template <int ROWS, int COLS, int ORDER> static void setMatrixSharedfpIndex( CgRuntimeParameter* __restrict ptr, const void* __restrict v, const int /*index*/ )
{
}
template <int ROWS, int COLS, int ORDER> static void setMatrixSharedfpIndexArray( CgRuntimeParameter* __restrict ptr, const void* __restrict v, const int index )
{
}
template <int ROWS, int COLS, int ORDER> static void setMatrixvpIndexArray( CgRuntimeParameter* __restrict ptr, const void* __restrict v, const int index )
{
PSGLcontext * LContext = _CurrentContext;
float * __restrict f = ( float* )v;
float * __restrict dst = ( float* )( *(( unsigned int ** )ptr->pushBufferPointer + index ) );
for ( long row = 0; row < ROWS; ++row )
{
for ( long col = 0; col < COLS; ++col )
dst[row * 4 + col] = ( ORDER == ROW_MAJOR ) ? f[row * COLS + col] : f[col * ROWS + row];
}
LContext->needValidate |= PSGL_VALIDATE_VERTEX_CONSTANTS;
}
template <int ROWS, int COLS, int ORDER> static void setMatrixfpIndex( CgRuntimeParameter* __restrict ptr, const void* __restrict v, const int /*index*/ )
{
float * __restrict f = ( float* )v;
float * __restrict dst = ( float* )ptr->pushBufferPointer;
_CGprogram *program = (( CgRuntimeParameter* )ptr )->program;
const CgParameterResource *parameterResource = _RGLGetParameterResource( program, ptr->parameterEntry );
unsigned short resource = parameterResource->resource;
unsigned short *ec = ( unsigned short * )program->resources + resource + 1;
for ( long row = 0; row < ROWS; ++row )
{
for ( long col = 0; col < COLS; ++col )
dst[row * 4 + col] = ( ORDER == ROW_MAJOR ) ? f[row * COLS + col] : f[col * ROWS + row];
int count = *ec;
if ( RGL_LIKELY( count ) )
{
swapandsetfp<COLS>( program->header.instructionCount*16, program->loadProgramId, program->loadProgramOffset, ec, ( unsigned int * )dst + row * 4 );
}
ec += count + 2;
}
}
template <int ROWS, int COLS, int ORDER> static void setMatrixfpIndexArray( CgRuntimeParameter* __restrict ptr, const void* __restrict v, const int index )
{
float * __restrict f = ( float* )v;
float * __restrict dst = ( float* )ptr->pushBufferPointer;
_CGprogram *program = ptr->program;
const CgParameterResource *parameterResource = _RGLGetParameterResource( program, ptr->parameterEntry );
unsigned short resource = parameterResource->resource;
unsigned short *ec = ( unsigned short * )program->resources + resource + 1;
int arrayIndex = index * ROWS;
while ( arrayIndex )
{
unsigned short count = ( *ec );
ec += ( count + 2 );
arrayIndex--;
}
for ( long row = 0; row < ROWS; ++row )
{
for ( long col = 0; col < COLS; ++col )
dst[row * 4 + col] = ( ORDER == ROW_MAJOR ) ? f[row * COLS + col] : f[col * ROWS + row];
int count = *ec;
if ( RGL_LIKELY( count ) )
{
swapandsetfp<COLS>( program->header.instructionCount*16, program->loadProgramId, program->loadProgramOffset, ec, ( unsigned int * )dst + row * 4 );
}
ec += count + 2;
}
}
static _cgSetArrayIndexFunction setVectorTypeIndex[2][2][2][4] =
{
{
{
{&setVectorTypevpIndex<1>, &setVectorTypevpIndex<2>, &setVectorTypevpIndex<3>, &setVectorTypevpIndex<4>, },
{&setVectorTypefpIndex<1>, &setVectorTypefpIndex<2>, &setVectorTypefpIndex<3>, &setVectorTypefpIndex<4>, }
},
{
{&setVectorTypeSharedvpIndex<1>, &setVectorTypeSharedvpIndex<2>, &setVectorTypeSharedvpIndex<3>, &setVectorTypeSharedvpIndex<4>, },
{&setVectorTypeSharedfpIndex<1>, &setVectorTypeSharedfpIndex<2>, &setVectorTypeSharedfpIndex<3>, &setVectorTypeSharedfpIndex<4>, }
},
},
{
{
{&setVectorTypevpIndexArray<1>, &setVectorTypevpIndexArray<2>, &setVectorTypevpIndexArray<3>, &setVectorTypevpIndexArray<4>, },
{&setVectorTypefpIndexArray<1>, &setVectorTypefpIndexArray<2>, &setVectorTypefpIndexArray<3>, &setVectorTypefpIndexArray<4>, }
},
{
{&setVectorTypeSharedvpIndexArray<1>, &setVectorTypeSharedvpIndexArray<2>, &setVectorTypeSharedvpIndexArray<3>, &setVectorTypeSharedvpIndexArray<4>, }, //should be the shared
{&setVectorTypeSharedfpIndexArray<1>, &setVectorTypeSharedfpIndexArray<2>, &setVectorTypeSharedfpIndexArray<3>, &setVectorTypeSharedfpIndexArray<4>, } //should be the shared
},
},
};
static _cgSetArrayIndexFunction setMatrixTypeIndex[2][2][2][4][4][2] =
{
{
{
{
{{ &setMatrixvpIndex<1, 1, 0>, &setMatrixvpIndex<1, 1, 1>}, { &setMatrixvpIndex<1, 2, 0>, &setMatrixvpIndex<1, 2, 1>}, { &setMatrixvpIndex<1, 3, 0>, &setMatrixvpIndex<1, 3, 1>}, { &setMatrixvpIndex<1, 4, 0>, &setMatrixvpIndex<1, 4, 1>}},
{{ &setMatrixvpIndex<2, 1, 0>, &setMatrixvpIndex<2, 1, 1>}, { &setMatrixvpIndex<2, 2, 0>, &setMatrixvpIndex<2, 2, 1>}, { &setMatrixvpIndex<2, 3, 0>, &setMatrixvpIndex<2, 3, 1>}, { &setMatrixvpIndex<2, 4, 0>, &setMatrixvpIndex<2, 4, 1>}},
{{ &setMatrixvpIndex<3, 1, 0>, &setMatrixvpIndex<3, 1, 1>}, { &setMatrixvpIndex<3, 2, 0>, &setMatrixvpIndex<3, 2, 1>}, { &setMatrixvpIndex<3, 3, 0>, &setMatrixvpIndex<3, 3, 1>}, { &setMatrixvpIndex<3, 4, 0>, &setMatrixvpIndex<3, 4, 1>}},
{{ &setMatrixvpIndex<4, 1, 0>, &setMatrixvpIndex<4, 1, 1>}, { &setMatrixvpIndex<4, 2, 0>, &setMatrixvpIndex<4, 2, 1>}, { &setMatrixvpIndex<4, 3, 0>, &setMatrixvpIndex<4, 3, 1>}, { &setMatrixvpIndex<4, 4, 0>, &setMatrixvpIndex<4, 4, 1>}},
},
{
{{ &setMatrixfpIndex<1, 1, 0>, &setMatrixfpIndex<1, 1, 1>}, { &setMatrixfpIndex<1, 2, 0>, &setMatrixfpIndex<1, 2, 1>}, { &setMatrixfpIndex<1, 3, 0>, &setMatrixfpIndex<1, 3, 1>}, { &setMatrixfpIndex<1, 4, 0>, &setMatrixfpIndex<1, 4, 1>}},
{{ &setMatrixfpIndex<2, 1, 0>, &setMatrixfpIndex<2, 1, 1>}, { &setMatrixfpIndex<2, 2, 0>, &setMatrixfpIndex<2, 2, 1>}, { &setMatrixfpIndex<2, 3, 0>, &setMatrixfpIndex<2, 3, 1>}, { &setMatrixfpIndex<2, 4, 0>, &setMatrixfpIndex<2, 4, 1>}},
{{ &setMatrixfpIndex<3, 1, 0>, &setMatrixfpIndex<3, 1, 1>}, { &setMatrixfpIndex<3, 2, 0>, &setMatrixfpIndex<3, 2, 1>}, { &setMatrixfpIndex<3, 3, 0>, &setMatrixfpIndex<3, 3, 1>}, { &setMatrixfpIndex<3, 4, 0>, &setMatrixfpIndex<3, 4, 1>}},
{{ &setMatrixfpIndex<4, 1, 0>, &setMatrixfpIndex<4, 1, 1>}, { &setMatrixfpIndex<4, 2, 0>, &setMatrixfpIndex<4, 2, 1>}, { &setMatrixfpIndex<4, 3, 0>, &setMatrixfpIndex<4, 3, 1>}, { &setMatrixfpIndex<4, 4, 0>, &setMatrixfpIndex<4, 4, 1>}},
},
},
{ //should be shared
{
{{ &setMatrixSharedvpIndex<1, 1, 0>, &setMatrixSharedvpIndex<1, 1, 1>}, { &setMatrixSharedvpIndex<1, 2, 0>, &setMatrixSharedvpIndex<1, 2, 1>}, { &setMatrixSharedvpIndex<1, 3, 0>, &setMatrixSharedvpIndex<1, 3, 1>}, { &setMatrixSharedvpIndex<1, 4, 0>, &setMatrixSharedvpIndex<1, 4, 1>}},
{{ &setMatrixSharedvpIndex<2, 1, 0>, &setMatrixSharedvpIndex<2, 1, 1>}, { &setMatrixSharedvpIndex<2, 2, 0>, &setMatrixSharedvpIndex<2, 2, 1>}, { &setMatrixSharedvpIndex<2, 3, 0>, &setMatrixSharedvpIndex<2, 3, 1>}, { &setMatrixSharedvpIndex<2, 4, 0>, &setMatrixSharedvpIndex<2, 4, 1>}},
{{ &setMatrixSharedvpIndex<3, 1, 0>, &setMatrixSharedvpIndex<3, 1, 1>}, { &setMatrixSharedvpIndex<3, 2, 0>, &setMatrixSharedvpIndex<3, 2, 1>}, { &setMatrixSharedvpIndex<3, 3, 0>, &setMatrixSharedvpIndex<3, 3, 1>}, { &setMatrixSharedvpIndex<3, 4, 0>, &setMatrixSharedvpIndex<3, 4, 1>}},
{{ &setMatrixSharedvpIndex<4, 1, 0>, &setMatrixSharedvpIndex<4, 1, 1>}, { &setMatrixSharedvpIndex<4, 2, 0>, &setMatrixSharedvpIndex<4, 2, 1>}, { &setMatrixSharedvpIndex<4, 3, 0>, &setMatrixSharedvpIndex<4, 3, 1>}, { &setMatrixSharedvpIndex<4, 4, 0>, &setMatrixSharedvpIndex<4, 4, 1>}},
},
{
{{ &setMatrixSharedfpIndex<1, 1, 0>, &setMatrixSharedfpIndex<1, 1, 1>}, { &setMatrixSharedfpIndex<1, 2, 0>, &setMatrixSharedfpIndex<1, 2, 1>}, { &setMatrixSharedfpIndex<1, 3, 0>, &setMatrixSharedfpIndex<1, 3, 1>}, { &setMatrixSharedfpIndex<1, 4, 0>, &setMatrixSharedfpIndex<1, 4, 1>}},
{{ &setMatrixSharedfpIndex<2, 1, 0>, &setMatrixSharedfpIndex<2, 1, 1>}, { &setMatrixSharedfpIndex<2, 2, 0>, &setMatrixSharedfpIndex<2, 2, 1>}, { &setMatrixSharedfpIndex<2, 3, 0>, &setMatrixSharedfpIndex<2, 3, 1>}, { &setMatrixSharedfpIndex<2, 4, 0>, &setMatrixSharedfpIndex<2, 4, 1>}},
{{ &setMatrixSharedfpIndex<3, 1, 0>, &setMatrixSharedfpIndex<3, 1, 1>}, { &setMatrixSharedfpIndex<3, 2, 0>, &setMatrixSharedfpIndex<3, 2, 1>}, { &setMatrixSharedfpIndex<3, 3, 0>, &setMatrixSharedfpIndex<3, 3, 1>}, { &setMatrixSharedfpIndex<3, 4, 0>, &setMatrixSharedfpIndex<3, 4, 1>}},
{{ &setMatrixSharedfpIndex<4, 1, 0>, &setMatrixSharedfpIndex<4, 1, 1>}, { &setMatrixSharedfpIndex<4, 2, 0>, &setMatrixSharedfpIndex<4, 2, 1>}, { &setMatrixSharedfpIndex<4, 3, 0>, &setMatrixSharedfpIndex<4, 3, 1>}, { &setMatrixSharedfpIndex<4, 4, 0>, &setMatrixSharedfpIndex<4, 4, 1>}},
},
},
},
{
{
{
{{ &setMatrixvpIndexArray<1, 1, 0>, &setMatrixvpIndexArray<1, 1, 1>}, { &setMatrixvpIndexArray<1, 2, 0>, &setMatrixvpIndexArray<1, 2, 1>}, { &setMatrixvpIndexArray<1, 3, 0>, &setMatrixvpIndexArray<1, 3, 1>}, { &setMatrixvpIndexArray<1, 4, 0>, &setMatrixvpIndexArray<1, 4, 1>}},
{{ &setMatrixvpIndexArray<2, 1, 0>, &setMatrixvpIndexArray<2, 1, 1>}, { &setMatrixvpIndexArray<2, 2, 0>, &setMatrixvpIndexArray<2, 2, 1>}, { &setMatrixvpIndexArray<2, 3, 0>, &setMatrixvpIndexArray<2, 3, 1>}, { &setMatrixvpIndexArray<2, 4, 0>, &setMatrixvpIndexArray<2, 4, 1>}},
{{ &setMatrixvpIndexArray<3, 1, 0>, &setMatrixvpIndexArray<3, 1, 1>}, { &setMatrixvpIndexArray<3, 2, 0>, &setMatrixvpIndexArray<3, 2, 1>}, { &setMatrixvpIndexArray<3, 3, 0>, &setMatrixvpIndexArray<3, 3, 1>}, { &setMatrixvpIndexArray<3, 4, 0>, &setMatrixvpIndexArray<3, 4, 1>}},
{{ &setMatrixvpIndexArray<4, 1, 0>, &setMatrixvpIndexArray<4, 1, 1>}, { &setMatrixvpIndexArray<4, 2, 0>, &setMatrixvpIndexArray<4, 2, 1>}, { &setMatrixvpIndexArray<4, 3, 0>, &setMatrixvpIndexArray<4, 3, 1>}, { &setMatrixvpIndexArray<4, 4, 0>, &setMatrixvpIndexArray<4, 4, 1>}},
},
{
{{ &setMatrixfpIndexArray<1, 1, 0>, &setMatrixfpIndexArray<1, 1, 1>}, { &setMatrixfpIndexArray<1, 2, 0>, &setMatrixfpIndexArray<1, 2, 1>}, { &setMatrixfpIndexArray<1, 3, 0>, &setMatrixfpIndexArray<1, 3, 1>}, { &setMatrixfpIndexArray<1, 4, 0>, &setMatrixfpIndexArray<1, 4, 1>}},
{{ &setMatrixfpIndexArray<2, 1, 0>, &setMatrixfpIndexArray<2, 1, 1>}, { &setMatrixfpIndexArray<2, 2, 0>, &setMatrixfpIndexArray<2, 2, 1>}, { &setMatrixfpIndexArray<2, 3, 0>, &setMatrixfpIndexArray<2, 3, 1>}, { &setMatrixfpIndexArray<2, 4, 0>, &setMatrixfpIndexArray<2, 4, 1>}},
{{ &setMatrixfpIndexArray<3, 1, 0>, &setMatrixfpIndexArray<3, 1, 1>}, { &setMatrixfpIndexArray<3, 2, 0>, &setMatrixfpIndexArray<3, 2, 1>}, { &setMatrixfpIndexArray<3, 3, 0>, &setMatrixfpIndexArray<3, 3, 1>}, { &setMatrixfpIndexArray<3, 4, 0>, &setMatrixfpIndexArray<3, 4, 1>}},
{{ &setMatrixfpIndexArray<4, 1, 0>, &setMatrixfpIndexArray<4, 1, 1>}, { &setMatrixfpIndexArray<4, 2, 0>, &setMatrixfpIndexArray<4, 2, 1>}, { &setMatrixfpIndexArray<4, 3, 0>, &setMatrixfpIndexArray<4, 3, 1>}, { &setMatrixfpIndexArray<4, 4, 0>, &setMatrixfpIndexArray<4, 4, 1>}},
},
},
{ //should be shared
{
{{ &setMatrixSharedvpIndexArray<1, 1, 0>, &setMatrixSharedvpIndexArray<1, 1, 1>}, { &setMatrixSharedvpIndexArray<1, 2, 0>, &setMatrixSharedvpIndexArray<1, 2, 1>}, { &setMatrixSharedvpIndexArray<1, 3, 0>, &setMatrixSharedvpIndexArray<1, 3, 1>}, { &setMatrixSharedvpIndexArray<1, 4, 0>, &setMatrixSharedvpIndexArray<1, 4, 1>}},
{{ &setMatrixSharedvpIndexArray<2, 1, 0>, &setMatrixSharedvpIndexArray<2, 1, 1>}, { &setMatrixSharedvpIndexArray<2, 2, 0>, &setMatrixSharedvpIndexArray<2, 2, 1>}, { &setMatrixSharedvpIndexArray<2, 3, 0>, &setMatrixSharedvpIndexArray<2, 3, 1>}, { &setMatrixSharedvpIndexArray<2, 4, 0>, &setMatrixSharedvpIndexArray<2, 4, 1>}},
{{ &setMatrixSharedvpIndexArray<3, 1, 0>, &setMatrixSharedvpIndexArray<3, 1, 1>}, { &setMatrixSharedvpIndexArray<3, 2, 0>, &setMatrixSharedvpIndexArray<3, 2, 1>}, { &setMatrixSharedvpIndexArray<3, 3, 0>, &setMatrixSharedvpIndexArray<3, 3, 1>}, { &setMatrixSharedvpIndexArray<3, 4, 0>, &setMatrixSharedvpIndexArray<3, 4, 1>}},
{{ &setMatrixSharedvpIndexArray<4, 1, 0>, &setMatrixSharedvpIndexArray<4, 1, 1>}, { &setMatrixSharedvpIndexArray<4, 2, 0>, &setMatrixSharedvpIndexArray<4, 2, 1>}, { &setMatrixSharedvpIndexArray<4, 3, 0>, &setMatrixSharedvpIndexArray<4, 3, 1>}, { &setMatrixSharedvpIndexArray<4, 4, 0>, &setMatrixSharedvpIndexArray<4, 4, 1>}},
},
{
{{ &setMatrixSharedfpIndexArray<1, 1, 0>, &setMatrixSharedfpIndexArray<1, 1, 1>}, { &setMatrixSharedfpIndexArray<1, 2, 0>, &setMatrixSharedfpIndexArray<1, 2, 1>}, { &setMatrixSharedfpIndexArray<1, 3, 0>, &setMatrixSharedfpIndexArray<1, 3, 1>}, { &setMatrixSharedfpIndexArray<1, 4, 0>, &setMatrixSharedfpIndexArray<1, 4, 1>}},
{{ &setMatrixSharedfpIndexArray<2, 1, 0>, &setMatrixSharedfpIndexArray<2, 1, 1>}, { &setMatrixSharedfpIndexArray<2, 2, 0>, &setMatrixSharedfpIndexArray<2, 2, 1>}, { &setMatrixSharedfpIndexArray<2, 3, 0>, &setMatrixSharedfpIndexArray<2, 3, 1>}, { &setMatrixSharedfpIndexArray<2, 4, 0>, &setMatrixSharedfpIndexArray<2, 4, 1>}},
{{ &setMatrixSharedfpIndexArray<3, 1, 0>, &setMatrixSharedfpIndexArray<3, 1, 1>}, { &setMatrixSharedfpIndexArray<3, 2, 0>, &setMatrixSharedfpIndexArray<3, 2, 1>}, { &setMatrixSharedfpIndexArray<3, 3, 0>, &setMatrixSharedfpIndexArray<3, 3, 1>}, { &setMatrixSharedfpIndexArray<3, 4, 0>, &setMatrixSharedfpIndexArray<3, 4, 1>}},
{{ &setMatrixSharedfpIndexArray<4, 1, 0>, &setMatrixSharedfpIndexArray<4, 1, 1>}, { &setMatrixSharedfpIndexArray<4, 2, 0>, &setMatrixSharedfpIndexArray<4, 2, 1>}, { &setMatrixSharedfpIndexArray<4, 3, 0>, &setMatrixSharedfpIndexArray<4, 3, 1>}, { &setMatrixSharedfpIndexArray<4, 4, 0>, &setMatrixSharedfpIndexArray<4, 4, 1>}},
},
},
}
};
_cgSetArrayIndexFunction getVectorTypeIndexSetterFunction( unsigned short a, unsigned short b, unsigned short c, unsigned short d )
{
return setVectorTypeIndex[a][b][c][d];
}
_cgSetArrayIndexFunction getMatrixTypeIndexSetterFunction( unsigned short a, unsigned short b, unsigned short c, unsigned short d, unsigned short e, unsigned short f )
{
return setMatrixTypeIndex[a][b][c][d][e][f];
}
static void _RGLBindTextureInternal( jsTextureImageUnit *unit, GLuint name)
{
PSGLcontext* LContext = _CurrentContext;
jsTexture *texture = NULL;
if ( name )
{
_RGLTexNameSpaceCreateNameLazy( &LContext->textureNameSpace, name );
texture = ( jsTexture * )LContext->textureNameSpace.data[name];
texture->target = GL_TEXTURE_2D;
}
unit->bound2D = name;
unit->currentTexture = _RGLGetCurrentTexture( unit, GL_TEXTURE_2D );
LContext->needValidate |= PSGL_VALIDATE_TEXTURES_USED;
}
static void setSamplerfp( CgRuntimeParameter*ptr, const void*v, int )
{
_CGprogram *program = (( CgRuntimeParameter* )ptr )->program;
const CgParameterResource *parameterResource = _RGLGetParameterResource( program, (( CgRuntimeParameter* )ptr )->parameterEntry );
if ( v )
*( GLuint* )ptr->pushBufferPointer = *( GLuint* )v;
else
{
jsTextureImageUnit *unit = _CurrentContext->TextureImageUnits + ( parameterResource->resource - CG_TEXUNIT0 );
_RGLBindTextureInternal( unit, *( GLuint* )ptr->pushBufferPointer);
}
}
static void setSamplervp( CgRuntimeParameter*ptr, const void*v, int )
{
_CGprogram *program = (( CgRuntimeParameter* )ptr )->program;
const CgParameterResource *parameterResource = _RGLGetParameterResource( program, (( CgRuntimeParameter* )ptr )->parameterEntry );
if ( v )
{
*( GLuint* )ptr->pushBufferPointer = *( GLuint* )v;
}
else
{
GLuint unit = parameterResource->resource - CG_TEXUNIT0;
GLuint name = *( GLuint* )ptr->pushBufferPointer;
PSGLcontext *LContext = _CurrentContext;
jsTexture *texture = NULL;
if ( name && (name < LContext->textureNameSpace.capacity) )
texture = ( jsTexture * )LContext->textureNameSpace.data[name];
LContext->VertexTextureImages[unit] = texture;
LContext->needValidate |= PSGL_VALIDATE_VERTEX_TEXTURES_USED;
}
}
static void _RGLCreatePushBuffer( _CGprogram *program )
{
int bufferSize = 0;
int programPushBufferPointersSize = 0;
int extraStorageInWords = 0;
int offsetCount = 0;
int samplerCount = 0;
int profileIndex = ( program->header.profile == CG_PROFILE_SCE_FP_TYPEB ||
program->header.profile == CG_PROFILE_SCE_FP_RSX ) ? FRAGMENT_PROFILE_INDEX : VERTEX_PROFILE_INDEX;
bool hasSharedParams = false;
int arrayCount = 1;
for ( int i = 0;i < program->rtParametersCount;i++ )
{
const CgParameterEntry *parameterEntry = program->parametersEntries + i;
if (( parameterEntry->flags & CGP_STRUCTURE ) || ( parameterEntry->flags & CGP_UNROLLED ) )
{
arrayCount = 1;
continue;
}
if (( parameterEntry->flags & CGPF_REFERENCED ) )
{
if ( parameterEntry->flags & CGP_ARRAY )
{
const CgParameterArray *parameterArray = _RGLGetParameterArray( program, parameterEntry );
arrayCount = _RGLGetSizeofSubArray( parameterArray->dimensions, parameterArray->dimensionCount );
continue;
}
if (( parameterEntry->flags & CGPV_MASK ) == CGPV_UNIFORM )
{
const CgParameterResource *parameterResource = _RGLGetParameterResource( program, parameterEntry );
if ( parameterResource->type >= CG_SAMPLER1D && parameterResource->type <= CG_SAMPLERCUBE )
{
offsetCount += arrayCount;
samplerCount += arrayCount;
}
else if ( profileIndex == VERTEX_PROFILE_INDEX )
{
if ( parameterResource->type == CGP_SCF_BOOL )
{
}
else if ( !( parameterEntry->flags & CGPF_SHARED ) )
{
int registerStride = isMatrix(( CGtype )parameterResource->type ) ? _RGLGetTypeRowCount(( CGtype )parameterResource->type ) : 1;
if ( parameterEntry->flags & CGP_CONTIGUOUS )
bufferSize += 3 + 4 * arrayCount * registerStride;
else
{
programPushBufferPointersSize += arrayCount;
int resourceIndex = parameterResource->resource;
int referencedSize = 3 + 4 * registerStride;
int notReferencedSize = 4 * registerStride;
for ( int j = 0;j < arrayCount;j++, resourceIndex += registerStride )
{
if ( program->resources[resourceIndex] != 0xffff )
bufferSize += referencedSize;
else
extraStorageInWords += notReferencedSize;
}
}
}
else
{
hasSharedParams = true;
if ( !( parameterEntry->flags & CGP_CONTIGUOUS ) )
{
programPushBufferPointersSize += arrayCount;
}
}
}
else
{
int registerStride = isMatrix(( CGtype )parameterResource->type ) ? _RGLGetTypeRowCount(( CGtype )parameterResource->type ) : 1;
if ( !( parameterEntry->flags & CGPF_SHARED ) )
{
extraStorageInWords += 4 * arrayCount * registerStride;
}
else
{
hasSharedParams = true;
unsigned short *resource = program->resources + parameterResource->resource;
for ( int j = 0;j < arrayCount*registerStride;j++ )
{
resource++;
unsigned short count = *resource++;
bufferSize += 24 * count;
resource += count;
}
}
}
}
}
arrayCount = 1;
}
if (( profileIndex == FRAGMENT_PROFILE_INDEX ) && ( hasSharedParams ) )
bufferSize += 8 + 3 + 2;
bufferSize = _RGLPad( bufferSize, 4 );
unsigned int storageSizeInWords = bufferSize + extraStorageInWords;
if ( storageSizeInWords )
program->memoryBlock = ( unsigned int* )memalign( 16, storageSizeInWords * 4 );
else
program->memoryBlock = NULL;
program->samplerCount = samplerCount;
if ( samplerCount )
{
program->samplerValuesLocation = ( GLuint* )malloc( samplerCount * sizeof( GLuint ) );
program->samplerIndices = ( GLuint* )malloc( samplerCount * sizeof( GLuint ) );
program->samplerUnits = ( GLuint* )malloc( samplerCount * sizeof( GLuint ) );
}
else
{
program->samplerValuesLocation = NULL;
program->samplerIndices = NULL;
program->samplerUnits = NULL;
}
GLuint *samplerValuesLocation = program->samplerValuesLocation;
GLuint *samplerIndices = program->samplerIndices;
GLuint *samplerUnits = program->samplerUnits;
if ( programPushBufferPointersSize )
program->constantPushBufferPointers = ( unsigned int** )malloc( programPushBufferPointersSize * 4 );
else
program->constantPushBufferPointers = NULL;
uint32_t *RGLCurrent = ( uint32_t * )program->memoryBlock;
program->constantPushBuffer = ( bufferSize > 0 ) ? ( unsigned int * )RGLCurrent : NULL;
unsigned int **programPushBuffer = program->constantPushBufferPointers;
program->constantPushBufferWordSize = bufferSize;
GLuint *currentStorage = ( GLuint * )( RGLCurrent + bufferSize );
arrayCount = 1;
const CgParameterEntry *containerEntry = NULL;
for ( int i = 0;i < program->rtParametersCount;i++ )
{
CgRuntimeParameter *rtParameter = program->runtimeParameters + i;
const CgParameterEntry *parameterEntry = program->parametersEntries + i;
if ( containerEntry == NULL )
containerEntry = parameterEntry;
rtParameter->samplerSetter = _cgRaiseInvalidParamIndex;
rtParameter->setterIndex = _cgRaiseInvalidParamIndex;
rtParameter->setterrIndex = _cgRaiseNotMatrixParamIndex;
rtParameter->settercIndex = _cgRaiseNotMatrixParamIndex;
CGparameter id = ( CGparameter )_RGLCreateName( &_CurrentContext->cgParameterNameSpace, ( void* )rtParameter );
if ( !id )
break;
rtParameter->id = id;
rtParameter->parameterEntry = parameterEntry;
rtParameter->program = program;
if (( parameterEntry->flags & CGP_STRUCTURE ) || ( parameterEntry->flags & CGP_UNROLLED ) )
{
arrayCount = 1;
containerEntry = NULL;
continue;
}
if ( parameterEntry->flags & CGPF_REFERENCED )
{
if ( parameterEntry->flags & CGP_ARRAY )
{
const CgParameterArray *parameterArray = _RGLGetParameterArray( program, parameterEntry );
arrayCount = _RGLGetSizeofSubArray( parameterArray->dimensions, parameterArray->dimensionCount );
continue;
}
if (( parameterEntry->flags & CGPV_MASK ) == CGPV_UNIFORM )
{
rtParameter->glType = GL_NONE;
const CgParameterResource *parameterResource = _RGLGetParameterResource( program, parameterEntry );
if ( parameterResource->type >= CG_SAMPLER1D && parameterResource->type <= CG_SAMPLERCUBE )
{
rtParameter->pushBufferPointer = samplerValuesLocation;
*samplerValuesLocation = 0;
samplerValuesLocation++;
*samplerIndices = i;
samplerIndices++;
*samplerUnits = parameterResource->resource - CG_TEXUNIT0;
samplerUnits++;
if ( profileIndex == VERTEX_PROFILE_INDEX )
{
rtParameter->setterIndex = _cgIgnoreSetParamIndex;
rtParameter->samplerSetter = setSamplervp;
}
else
{
rtParameter->samplerSetter = setSamplerfp;
}
rtParameter->glType = _RGLCgGetSamplerGLTypeFromCgType(( CGtype )( parameterResource->type ) );
}
else
{
if ( profileIndex == VERTEX_PROFILE_INDEX )
{
if ( parameterResource->type == CGP_SCF_BOOL )
{
}
else if ( !( parameterEntry->flags & CGPF_SHARED ) )
{
int registerStride = isMatrix(( CGtype )parameterResource->type ) ? _RGLGetTypeRowCount(( CGtype )parameterResource->type ) : 1;
int registerCount = arrayCount * registerStride;
if ( parameterEntry->flags & CGP_CONTIGUOUS )
{
memset( RGLCurrent, 0, 4*( 4*registerCount + 3 ) );
GCM_FUNC_BUFFERED( cellGcmSetVertexProgramParameterBlock, RGLCurrent, parameterResource->resource, registerCount, ( float* )RGLCurrent );
rtParameter->pushBufferPointer = RGLCurrent - 4 * registerCount;
}
else
{
rtParameter->pushBufferPointer = programPushBuffer;
int resourceIndex = parameterResource->resource;
for ( int j = 0;j < arrayCount;j++, resourceIndex += registerStride )
{
if ( program->resources[resourceIndex] != 0xffff )
{
memset( RGLCurrent, 0, 4*( 4*registerStride + 3 ) );
GCM_FUNC_BUFFERED( cellGcmSetVertexProgramParameterBlock, RGLCurrent, program->resources[resourceIndex], registerStride, ( float* )RGLCurrent );
*( programPushBuffer++ ) = ( unsigned int* )( RGLCurrent - 4 * registerStride );
}
else
{
*( programPushBuffer++ ) = ( unsigned int* )currentStorage;
currentStorage += 4 * registerStride;
}
}
}
}
}
else
{
if ( parameterEntry->flags & CGPF_SHARED )
{
rtParameter->pushBufferPointer = NULL;
}
else
{
int registerStride = isMatrix(( CGtype )parameterResource->type ) ? _RGLGetTypeRowCount(( CGtype )parameterResource->type ) : 1;
int registerCount = arrayCount * registerStride;
rtParameter->pushBufferPointer = currentStorage;
currentStorage += 4 * registerCount;
}
}
switch ( parameterResource->type )
{
case CG_FLOAT:
case CG_FLOAT1: case CG_FLOAT2: case CG_FLOAT3: case CG_FLOAT4:
{
unsigned int floatCount = _RGLCountFloatsInCgType(( CGtype )parameterResource->type );
rtParameter->setterIndex = setVectorTypeIndex[( containerEntry->flags&CGP_ARRAY ) ? 1 : 0][( containerEntry->flags&CGPF_SHARED ) ? 1 : 0][profileIndex][floatCount - 1];
}
break;
case CG_FLOAT1x1: case CG_FLOAT1x2: case CG_FLOAT1x3: case CG_FLOAT1x4:
case CG_FLOAT2x1: case CG_FLOAT2x2: case CG_FLOAT2x3: case CG_FLOAT2x4:
case CG_FLOAT3x1: case CG_FLOAT3x2: case CG_FLOAT3x3: case CG_FLOAT3x4:
case CG_FLOAT4x1: case CG_FLOAT4x2: case CG_FLOAT4x3: case CG_FLOAT4x4:
rtParameter->setterrIndex = setMatrixTypeIndex[( containerEntry->flags&CGP_ARRAY ) ? 1 : 0][( containerEntry->flags&CGPF_SHARED ) ? 1 : 0][profileIndex][_RGLGetTypeRowCount(( CGtype )parameterResource->type ) - 1][_RGLGetTypeColCount(( CGtype )parameterResource->type ) - 1][ROW_MAJOR];
rtParameter->settercIndex = setMatrixTypeIndex[( containerEntry->flags&CGP_ARRAY ) ? 1 : 0][( containerEntry->flags&CGPF_SHARED ) ? 1 : 0][profileIndex][_RGLGetTypeRowCount(( CGtype )parameterResource->type ) - 1][_RGLGetTypeColCount(( CGtype )parameterResource->type ) - 1][COL_MAJOR];
break;
case CG_SAMPLER1D: case CG_SAMPLER2D: case CG_SAMPLER3D: case CG_SAMPLERRECT: case CG_SAMPLERCUBE:
break;
case CGP_SCF_BOOL:
break;
case CG_HALF:
case CG_HALF1: case CG_HALF2: case CG_HALF3: case CG_HALF4:
case CG_INT:
case CG_INT1: case CG_INT2: case CG_INT3: case CG_INT4:
case CG_BOOL:
case CG_BOOL1: case CG_BOOL2: case CG_BOOL3: case CG_BOOL4:
case CG_FIXED:
case CG_FIXED1: case CG_FIXED2: case CG_FIXED3: case CG_FIXED4:
{
unsigned int floatCount = _RGLCountFloatsInCgType(( CGtype )parameterResource->type );
rtParameter->setterIndex = setVectorTypeIndex[( containerEntry->flags&CGP_ARRAY ) ? 1 : 0][( containerEntry->flags&CGPF_SHARED ) ? 1 : 0][profileIndex][floatCount - 1];
}
break;
case CG_HALF1x1: case CG_HALF1x2: case CG_HALF1x3: case CG_HALF1x4:
case CG_HALF2x1: case CG_HALF2x2: case CG_HALF2x3: case CG_HALF2x4:
case CG_HALF3x1: case CG_HALF3x2: case CG_HALF3x3: case CG_HALF3x4:
case CG_HALF4x1: case CG_HALF4x2: case CG_HALF4x3: case CG_HALF4x4:
case CG_INT1x1: case CG_INT1x2: case CG_INT1x3: case CG_INT1x4:
case CG_INT2x1: case CG_INT2x2: case CG_INT2x3: case CG_INT2x4:
case CG_INT3x1: case CG_INT3x2: case CG_INT3x3: case CG_INT3x4:
case CG_INT4x1: case CG_INT4x2: case CG_INT4x3: case CG_INT4x4:
case CG_BOOL1x1: case CG_BOOL1x2: case CG_BOOL1x3: case CG_BOOL1x4:
case CG_BOOL2x1: case CG_BOOL2x2: case CG_BOOL2x3: case CG_BOOL2x4:
case CG_BOOL3x1: case CG_BOOL3x2: case CG_BOOL3x3: case CG_BOOL3x4:
case CG_BOOL4x1: case CG_BOOL4x2: case CG_BOOL4x3: case CG_BOOL4x4:
case CG_FIXED1x1: case CG_FIXED1x2: case CG_FIXED1x3: case CG_FIXED1x4:
case CG_FIXED2x1: case CG_FIXED2x2: case CG_FIXED2x3: case CG_FIXED2x4:
case CG_FIXED3x1: case CG_FIXED3x2: case CG_FIXED3x3: case CG_FIXED3x4:
case CG_FIXED4x1: case CG_FIXED4x2: case CG_FIXED4x3: case CG_FIXED4x4:
rtParameter->setterrIndex = setMatrixTypeIndex[( containerEntry->flags&CGP_ARRAY ) ? 1 : 0][( containerEntry->flags&CGPF_SHARED ) ? 1 : 0][profileIndex][_RGLGetTypeRowCount(( CGtype )parameterResource->type ) - 1][_RGLGetTypeColCount(( CGtype )parameterResource->type ) - 1][ROW_MAJOR];
rtParameter->settercIndex = setMatrixTypeIndex[( containerEntry->flags&CGP_ARRAY ) ? 1 : 0][( containerEntry->flags&CGPF_SHARED ) ? 1 : 0][profileIndex][_RGLGetTypeRowCount(( CGtype )parameterResource->type ) - 1][_RGLGetTypeColCount(( CGtype )parameterResource->type ) - 1][COL_MAJOR];
break;
case CG_STRING:
break;
default:
break;
}
}
}
}
else
{
if (( parameterEntry->flags & CGPV_MASK ) == CGPV_UNIFORM )
{
if ( parameterEntry->flags & CGP_ARRAY )
continue;
const CgParameterResource *parameterResource = _RGLGetParameterResource( program, parameterEntry );
switch ( parameterResource->type )
{
case CG_FLOAT:
case CG_FLOAT1: case CG_FLOAT2: case CG_FLOAT3: case CG_FLOAT4:
rtParameter->setterIndex = _cgIgnoreSetParamIndex;
break;
case CG_FLOAT1x1: case CG_FLOAT1x2: case CG_FLOAT1x3: case CG_FLOAT1x4:
case CG_FLOAT2x1: case CG_FLOAT2x2: case CG_FLOAT2x3: case CG_FLOAT2x4:
case CG_FLOAT3x1: case CG_FLOAT3x2: case CG_FLOAT3x3: case CG_FLOAT3x4:
case CG_FLOAT4x1: case CG_FLOAT4x2: case CG_FLOAT4x3: case CG_FLOAT4x4:
rtParameter->setterrIndex = _cgIgnoreSetParamIndex;
rtParameter->settercIndex = _cgIgnoreSetParamIndex;
break;
case CG_SAMPLER1D: case CG_SAMPLER2D: case CG_SAMPLER3D: case CG_SAMPLERRECT: case CG_SAMPLERCUBE:
rtParameter->samplerSetter = _cgIgnoreSetParamIndex;
break;
case CGP_SCF_BOOL:
break;
case CG_HALF:
case CG_HALF1: case CG_HALF2: case CG_HALF3: case CG_HALF4:
case CG_INT:
case CG_INT1: case CG_INT2: case CG_INT3: case CG_INT4:
case CG_BOOL:
case CG_BOOL1: case CG_BOOL2: case CG_BOOL3: case CG_BOOL4:
case CG_FIXED:
case CG_FIXED1: case CG_FIXED2: case CG_FIXED3: case CG_FIXED4:
rtParameter->setterIndex = _cgIgnoreSetParamIndex;
break;
case CG_HALF1x1: case CG_HALF1x2: case CG_HALF1x3: case CG_HALF1x4:
case CG_HALF2x1: case CG_HALF2x2: case CG_HALF2x3: case CG_HALF2x4:
case CG_HALF3x1: case CG_HALF3x2: case CG_HALF3x3: case CG_HALF3x4:
case CG_HALF4x1: case CG_HALF4x2: case CG_HALF4x3: case CG_HALF4x4:
case CG_INT1x1: case CG_INT1x2: case CG_INT1x3: case CG_INT1x4:
case CG_INT2x1: case CG_INT2x2: case CG_INT2x3: case CG_INT2x4:
case CG_INT3x1: case CG_INT3x2: case CG_INT3x3: case CG_INT3x4:
case CG_INT4x1: case CG_INT4x2: case CG_INT4x3: case CG_INT4x4:
case CG_BOOL1x1: case CG_BOOL1x2: case CG_BOOL1x3: case CG_BOOL1x4:
case CG_BOOL2x1: case CG_BOOL2x2: case CG_BOOL2x3: case CG_BOOL2x4:
case CG_BOOL3x1: case CG_BOOL3x2: case CG_BOOL3x3: case CG_BOOL3x4:
case CG_BOOL4x1: case CG_BOOL4x2: case CG_BOOL4x3: case CG_BOOL4x4:
case CG_FIXED1x1: case CG_FIXED1x2: case CG_FIXED1x3: case CG_FIXED1x4:
case CG_FIXED2x1: case CG_FIXED2x2: case CG_FIXED2x3: case CG_FIXED2x4:
case CG_FIXED3x1: case CG_FIXED3x2: case CG_FIXED3x3: case CG_FIXED3x4:
case CG_FIXED4x1: case CG_FIXED4x2: case CG_FIXED4x3: case CG_FIXED4x4:
rtParameter->setterrIndex = _cgIgnoreSetParamIndex;
rtParameter->settercIndex = _cgIgnoreSetParamIndex;
break;
case CG_STRING:
break;
default:
break;
}
}
}
arrayCount = 1;
containerEntry = NULL;
}
if ( bufferSize > 0 )
{
int nopCount = ( program->constantPushBuffer + bufferSize ) - ( unsigned int * )RGLCurrent;
GCM_FUNC_BUFFERED( cellGcmSetNopCommand, RGLCurrent, nopCount );
}
}
static int _RGLGenerateProgram( _CGprogram *program, int profileIndex, const CgProgramHeader *programHeader, const void *ucode, const CgParameterTableHeader *parameterHeader,
const CgParameterEntry *parameterEntries, const char *stringTable, const float *defaultValues )
{
CGprofile profile = ( CGprofile )programHeader->profile;
int need_swapping = 0;
if ( profile == ( CGprofile )7005 )
profile = CG_PROFILE_SCE_VP_RSX;
if ( profile == ( CGprofile )7006 )
profile = CG_PROFILE_SCE_FP_RSX;
if (( profile != CG_PROFILE_SCE_FP_TYPEB ) && ( profile != CG_PROFILE_SCE_VP_TYPEB ) &&
( profile != CG_PROFILE_SCE_FP_RSX ) && ( profile != CG_PROFILE_SCE_VP_RSX ) )
{
need_swapping = 1;
}
int invalidProfile = 0;
switch ( ENDIAN_32( profile, need_swapping ) )
{
case CG_PROFILE_SCE_VP_TYPEB:
if ( profileIndex != VERTEX_PROFILE_INDEX ) invalidProfile = 1;
break;
case CG_PROFILE_SCE_FP_TYPEB:
if ( profileIndex != FRAGMENT_PROFILE_INDEX ) invalidProfile = 1;
break;
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;
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 == NULL )
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->defaultValues = NULL;
memset( program->runtimeParameters, 0, parameterHeader->entryCount*sizeof( CgRuntimeParameter ) );
program->stringTable = stringTable;
program->defaultValues = defaultValues;
_RGLCreatePushBuffer( program );
int count = program->defaultValuesIndexCount;
if ( profileIndex == FRAGMENT_PROFILE_INDEX)
{
for ( int i = 0; i < count;i++ )
{
const void * __restrict pItemDefaultValues = program->defaultValues + program->defaultValuesIndices[i].defaultValueIndex;
const unsigned int * itemDefaultValues = ( const unsigned int * )pItemDefaultValues;
int index = ( int )program->defaultValuesIndices[i].entryIndex;
CgRuntimeParameter *rtParameter = program->runtimeParameters + index;
float *hostMemoryCopy = ( float * )rtParameter->pushBufferPointer;
if ( hostMemoryCopy )
{
const CgParameterEntry *parameterEntry = rtParameter->parameterEntry;
int arrayCount = 1;
if ( parameterEntry->flags & CGP_ARRAY )
{
const CgParameterArray *parameterArray = _RGLGetParameterArray( program, parameterEntry );
arrayCount = _RGLGetSizeofSubArray( parameterArray->dimensions, parameterArray->dimensionCount );
i++;
parameterEntry++;
}
const CgParameterResource *parameterResource = _RGLGetParameterResource( program, parameterEntry );
unsigned short *resource = program->resources + parameterResource->resource + 1;
int registerStride = isMatrix(( CGtype )parameterResource->type ) ? _RGLGetTypeRowCount(( CGtype )parameterResource->type ) : 1;
int registerCount = arrayCount * registerStride;
int j;
for ( j = 0;j < registerCount;j++ )
{
unsigned short embeddedConstCount = *( resource++ );
int k;
for ( k = 0;k < embeddedConstCount;k++ )
{
unsigned short ucodePatchOffset = *( resource )++;
unsigned int *dst = ( unsigned int* )(( char* )program->ucode + ucodePatchOffset );
dst[0] = SWAP_IF_BIG_ENDIAN( itemDefaultValues[0] );
dst[1] = SWAP_IF_BIG_ENDIAN( itemDefaultValues[1] );
dst[2] = SWAP_IF_BIG_ENDIAN( itemDefaultValues[2] );
dst[3] = SWAP_IF_BIG_ENDIAN( itemDefaultValues[3] );
}
memcpy(( void* )hostMemoryCopy, ( void* )itemDefaultValues, sizeof( float )*4 );
hostMemoryCopy += 4;
itemDefaultValues += 4;
resource++;
}
}
}
}
else
{
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 )
{
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;
}
}
}
}
}
program->loadProgramId = GMM_ERROR;
program->loadProgramOffset = 0;
if ( profileIndex == FRAGMENT_PROFILE_INDEX )
{
int loaded = _RGLLoadFPShader( program );
if ( ! loaded )
{
_RGLCgRaiseError( CG_MEMORY_ALLOC_ERROR );
return 0;
}
}
program->programGroup = NULL;
program->programIndexInGroup = -1;
return 1;
}
void _RGLPlatformVertexProgramErase( void* platformProgram )
{
_CGprogram* program = ( _CGprogram* )platformProgram;
if ( program->runtimeParameters )
free( program->runtimeParameters );
if ( program->memoryBlock )
free( program->memoryBlock );
if ( program->samplerIndices )
{
free( program->samplerValuesLocation );
free( program->samplerIndices );
free( program->samplerUnits );
}
if ( program->constantPushBufferPointers )
free( program->constantPushBufferPointers );
}
void _RGLPlatformProgramErase( void* platformProgram )
{
_CGprogram* program = ( _CGprogram* )platformProgram;
if ( program->loadProgramId != GMM_ERROR )
{
if ( program->loadProgramId != GMM_ERROR )
{
gmmFree( program->loadProgramId );
program->loadProgramId = GMM_ERROR;
program->loadProgramOffset = 0;
}
}
if ( program->runtimeParameters )
{
int i;
int count = ( int )program->rtParametersCount;
for ( i = 0;i < count;i++ )
{
_RGLEraseName( &_CurrentContext->cgParameterNameSpace, ( jsName )program->runtimeParameters[i].id );
}
free( program->runtimeParameters );
}
if ( program->memoryBlock )
free( program->memoryBlock );
if ( program->samplerIndices )
{
free( program->samplerValuesLocation );
free( program->samplerIndices );
free( program->samplerUnits );
}
if ( program->constantPushBufferPointers )
free( program->constantPushBufferPointers );
}
CGbool _RGLPlatformSupportsFragmentProgram( CGprofile p )
{
if ( p == CG_PROFILE_SCE_FP_TYPEB )
return CG_TRUE;
if ( CG_PROFILE_SCE_FP_RSX == p )
return CG_TRUE;
return CG_FALSE;
}
CGprofile _RGLPlatformGetLatestProfile( 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;
}
int _RGLPlatformCopyProgram( _CGprogram* source, _CGprogram* destination )
{
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 ) );
int profileIndex;
switch ( source->header.profile )
{
case CG_PROFILE_SCE_VP_TYPEB:
case CG_PROFILE_SCE_VP_RSX:
profileIndex = VERTEX_PROFILE_INDEX;
break;
case CG_PROFILE_SCE_FP_TYPEB:
case CG_PROFILE_SCE_FP_RSX:
profileIndex = FRAGMENT_PROFILE_INDEX;
break;
default:
return 0;
}
return _RGLGenerateProgram( destination, profileIndex, &source->header, source->ucode, &parameterHeader, source->parametersEntries, source->stringTable, source->defaultValues );
}
static char *_RGLPlatformBufferObjectMap( jsBufferObject* bufferObject, GLenum access )
{
RGLBufferObject *jsBuffer = ( RGLBufferObject * )bufferObject->platformBufferObject;
if ( jsBuffer->mapCount++ == 0 )
{
if ( access == GL_WRITE_ONLY )
{
_RGLAllocateBuffer( bufferObject );
if ( jsBuffer->pool == SURFACE_POOL_NONE )
{
_RGLSetError( GL_OUT_OF_MEMORY );
return NULL;
}
}
else
{
cellGcmSetInvalidateVertexCache( &_RGLState.fifo);
_RGLFifoFinish( &_RGLState.fifo );
}
jsBuffer->mapAccess = access;
if ( jsBuffer->mapAccess != GL_READ_ONLY )
{
RGLDriver *driver= (RGLDriver *)_CurrentDevice->rasterDriver;
++driver->flushBufferCount;
}
GmmBaseBlock *pBaseBlock = (GmmBaseBlock *)jsBuffer->bufferId;
if (!pBaseBlock->isTile)
{
GmmBlock *pBlock = (GmmBlock *)jsBuffer->bufferId;
pBlock->isPinned = 1;
}
}
return gmmIdToAddress( jsBuffer->bufferId );
}
static jsFramebuffer* _RGLCreateFramebuffer( void )
{
jsFramebuffer* framebuffer = new jsPlatformFramebuffer();
return framebuffer;
}
static void _RGLDestroyFramebuffer( jsFramebuffer* framebuffer )
{
delete framebuffer;
}
static void _RGLPlatformDestroyTexture( jsTexture* texture )
{
if ( !texture->referenceBuffer )
{
RGLTexture *gcmTexture = ( RGLTexture * )texture->platformTexture;
if ( gcmTexture->pbo != NULL )
{
_RGLFreeBufferObject( gcmTexture->pbo );
gcmTexture->pbo = NULL;
gcmTexture->pool = SURFACE_POOL_NONE;
gcmTexture->gpuAddressId = GMM_ERROR;
gcmTexture->gpuAddressIdOffset = 0;
gcmTexture->gpuSize = 0;
}
_RGLPlatformFreeGcmTexture( texture );
}
_RGLTextureTouchFBOs( texture );
}
#ifndef __PSL1GHT__
#include <cell/gcm/gcm_method_data.h>
#endif
static void _RGLPlatformValidateTextureStage( int unit, jsTexture* texture )
{
if ( RGL_UNLIKELY( texture->revalidate ) )
{
_RGLPlatformValidateTextureResources( texture );
}
GLboolean isCompleteCache = texture->isComplete;
if ( RGL_LIKELY( isCompleteCache ) )
{
RGLTexture *platformTexture = ( RGLTexture * )texture->platformTexture;
GmmBaseBlock *pBaseBlock = (GmmBaseBlock *)platformTexture->gpuAddressId;
const GLuint imageOffset = gmmAddressToOffset(pBaseBlock->address, pBaseBlock->isMain) + platformTexture->gpuAddressIdOffset;
platformTexture->gcmTexture.offset = imageOffset;
cellGcmSetTexture( &_RGLState.fifo, unit, &platformTexture->gcmTexture);
CellGcmContextData *gcm_context = (CellGcmContextData*)&_RGLState.fifo;
cellGcmReserveMethodSizeInline(gcm_context, 11);
uint32_t *current = gcm_context->current;
current[0] = CELL_GCM_METHOD_HEADER_TEXTURE_OFFSET(unit, 8);
current[1] = CELL_GCM_METHOD_DATA_TEXTURE_OFFSET(platformTexture->gcmTexture.offset);
current[2] = CELL_GCM_METHOD_DATA_TEXTURE_FORMAT(platformTexture->gcmTexture.location,
CELL_GCM_FALSE,
CELL_GCM_TEXTURE_DIMENSION_2,
platformTexture->gcmTexture.format,
1);
current[3] = CELL_GCM_METHOD_DATA_TEXTURE_ADDRESS(
CELL_GCM_TEXTURE_BORDER, /* wrapS */
CELL_GCM_TEXTURE_BORDER, /* wrapT */
CELL_GCM_TEXTURE_BORDER, /* wrapR */
CELL_GCM_TEXTURE_UNSIGNED_REMAP_NORMAL, /* unsignedRemap */
CELL_GCM_TEXTURE_ZFUNC_NEVER,
platformTexture->gcmMethods.address.gamma,
0);
current[4] = CELL_GCM_METHOD_DATA_TEXTURE_CONTROL0(CELL_GCM_TRUE,
0, /* minLOD */
256000, /* maxLOD */
CELL_GCM_TEXTURE_MAX_ANISO_1);
current[5] = platformTexture->gcmTexture.remap;
current[6] = CELL_GCM_METHOD_DATA_TEXTURE_FILTER(
(platformTexture->gcmMethods.filter.bias & 0x1fff),
platformTexture->gcmMethods.filter.min,
platformTexture->gcmMethods.filter.mag,
CELL_GCM_TEXTURE_CONVOLUTION_QUINCUNX); /* filter */
current[7] = CELL_GCM_METHOD_DATA_TEXTURE_IMAGE_RECT(
platformTexture->gcmTexture.height,
platformTexture->gcmTexture.width);
current[8] = 0;
current[9] = CELL_GCM_METHOD_HEADER_TEXTURE_CONTROL3(unit,1);
current[10] = CELL_GCM_METHOD_DATA_TEXTURE_CONTROL3(
platformTexture->gcmTexture.pitch,
1); /* depth */
gcm_context->current = &current[11];
}
else
{
//printf("RGL WARN: Texture bound to unit %d is incomplete.\n", unit);
GLuint remap = CELL_GCM_REMAP_MODE(
CELL_GCM_TEXTURE_REMAP_ORDER_XYXY,
CELL_GCM_TEXTURE_REMAP_FROM_A,
CELL_GCM_TEXTURE_REMAP_FROM_R,
CELL_GCM_TEXTURE_REMAP_FROM_G,
CELL_GCM_TEXTURE_REMAP_FROM_B,
CELL_GCM_TEXTURE_REMAP_ONE,
CELL_GCM_TEXTURE_REMAP_ZERO,
CELL_GCM_TEXTURE_REMAP_ZERO,
CELL_GCM_TEXTURE_REMAP_ZERO );
cellGcmSetTextureControlInline( &_RGLState.fifo, unit, CELL_GCM_FALSE, 0, 0, 0);
cellGcmSetTextureRemapInline( &_RGLState.fifo, unit, remap);
}
}
static GLenum _RGLPlatformChooseInternalFormat( GLenum internalFormat )
{
switch ( internalFormat )
{
case GL_ALPHA:
case GL_ALPHA4:
case GL_ALPHA8:
return RGL_ALPHA8;
case GL_RGB10:
case GL_RGB10_A2:
case GL_RGB12:
case GL_RGB16:
return RGL_FLOAT_RGBX32;
case GL_RGBA12:
case GL_RGBA16:
return RGL_FLOAT_RGBA32;
case 3:
case GL_R3_G3_B2:
case GL_RGB4:
case GL_RGB:
case GL_RGB8:
case RGL_RGBX8:
return RGL_RGBX8;
case 4:
case GL_RGBA2:
case GL_RGBA4:
case GL_RGBA8:
case GL_RGBA:
return RGL_RGBA8;
case GL_RGB5_A1:
return RGL_RGB5_A1_SCE;
case GL_RGB5:
return RGL_RGB565_SCE;
case GL_BGRA:
case RGL_BGRA8:
return RGL_BGRA8;
case GL_ARGB_SCE:
return RGL_ARGB8;
default:
return GL_INVALID_ENUM;
}
return GL_INVALID_ENUM;
}
static void _RGLPlatformExpandInternalFormat( GLenum internalFormat, GLenum *format, GLenum *type )
{
switch ( internalFormat )
{
case RGL_ALPHA8:
*format = GL_ALPHA;
*type = GL_UNSIGNED_BYTE;
break;
case RGL_ARGB8:
*format = GL_BGRA;
*type = GL_UNSIGNED_INT_8_8_8_8_REV;
break;
case RGL_RGB5_A1_SCE:
*format = GL_RGBA;
*type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
break;
case RGL_RGB565_SCE:
*format = GL_RGB;
*type = GL_UNSIGNED_SHORT_5_6_5_REV;
break;
default:
return;
}
}
static GLenum _RGLPlatformChooseInternalStorage( jsImage* image, GLenum internalFormat )
{
image->storageSize = 0;
GLenum platformInternalFormat = _RGLPlatformChooseInternalFormat( internalFormat );
if ( platformInternalFormat == GL_INVALID_ENUM )
return GL_INVALID_ENUM;
image->internalFormat = platformInternalFormat;
_RGLPlatformExpandInternalFormat( platformInternalFormat, &image->format, &image->type );
image->storageSize = _RGLGetPixelSize(image->format, image->type) * image->width * image->height;
return GL_NO_ERROR;
}
static inline GLuint _RGLGetBufferObjectOrigin(GLuint buffer)
{
PSGLcontext* LContext = _CurrentContext;
jsBufferObject *bufferObject = (jsBufferObject *)LContext->bufferObjectNameSpace.data[buffer];
RGLBufferObject *gcmBuffer = ( RGLBufferObject * ) & bufferObject->platformBufferObject;
return gcmBuffer->bufferId;
}
static void _RGLSetImage( jsImage *image, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLsizei alignment, GLenum format, GLenum type, const GLvoid *pixels )
{
image->width = width;
image->height = height;
image->alignment = alignment;
image->xblk = 0;
image->yblk = 0;
image->xstride = 0;
image->ystride = 0;
image->format = 0;
image->type = 0;
image->internalFormat = 0;
const GLenum status = _RGLPlatformChooseInternalStorage( image, internalFormat );
(( void )status );
image->data = NULL;
image->mallocData = NULL;
image->mallocStorageSize = 0;
image->isSet = GL_TRUE;
if ( image->xstride == 0 )
image->xstride = _RGLGetPixelSize( image->format, image->type );
if ( image->ystride == 0 )
image->ystride = image->width * image->xstride;
if ( pixels )
{
_RGLImageAllocCPUStorage( image );
if ( !image->data )
return;
jsRaster raster;
raster.format = format;
raster.type = type;
raster.width = width;
raster.height = height;
raster.data = ( void * )pixels;
raster.xstride = _RGLGetPixelSize( raster.format, raster.type );
raster.ystride = ( raster.width * raster.xstride + alignment - 1 ) / alignment * alignment;
_RGLRasterToImage( &raster, image);
image->dataState = IMAGE_DATASTATE_HOST;
}
else
image->dataState = IMAGE_DATASTATE_UNSET;
}
static GLboolean _RGLPlatformTexturePBOImage(
jsTexture* texture,
jsImage* image,
GLint internalFormat,
GLsizei width, GLsizei height,
GLenum format, GLenum type,
const GLvoid *offset )
{
PSGLcontext* LContext = _CurrentContext;
RGLTexture *gcmTexture = ( RGLTexture * )texture->platformTexture;
image->dataState = IMAGE_DATASTATE_UNSET;
if ( gcmTexture->pbo != NULL )
_RGLPlatformDropTexture( texture );
_RGLSetImage( image, internalFormat, width, height, 1 /* depth */, LContext->unpackAlignment, format, type, NULL );
if ( LContext->PixelUnpackBuffer == 0 )
return GL_FALSE;
const GLuint pboPitch = _RGLPad(_RGLGetPixelSize(format, type) * width, LContext->unpackAlignment );
if (( pboPitch&3 ) != 0 )
{
RARCH_WARN("PBO image pitch not a multiple of 4, using slow path.\n" );
return GL_FALSE;
}
GLuint gpuId = _RGLGetBufferObjectOrigin( LContext->PixelUnpackBuffer );
GLuint gpuIdOffset = (( GLubyte* )offset - ( GLubyte* )NULL );
if ( gmmIdToOffset(gpuId)+gpuIdOffset & 63 )
{
RARCH_WARN("PBO offset not 64-byte aligned, using slow path.\n");
return GL_FALSE;
}
GLboolean formatOK = GL_FALSE;
switch ( internalFormat )
{
case 4:
case GL_RGBA:
case GL_RGBA8:
if ( format == GL_RGBA && type == GL_UNSIGNED_INT_8_8_8_8 )
formatOK = GL_TRUE;
break;
case GL_ALPHA:
case GL_ALPHA8:
if ( format == GL_ALPHA && type == GL_UNSIGNED_BYTE )
formatOK = GL_TRUE;
break;
case GL_ARGB_SCE:
if ( format == GL_BGRA && type == GL_UNSIGNED_INT_8_8_8_8_REV )
formatOK = GL_TRUE;
break;
default:
formatOK = GL_FALSE;
}
if (!formatOK )
{
RARCH_WARN("PBO format/type requires conversion to texture internal format, using slow path.\n");
return GL_FALSE;
}
if (!_RGLTextureIsValid(texture))
{
RARCH_WARN("PBO transfering to incomplete texture, using slow path.\n");
return GL_FALSE;
}
RGLTextureLayout newLayout;
_RGLPlatformChooseGPUFormatAndLayout( texture, GL_TRUE, pboPitch, &newLayout );
jsBufferObject* bufferObject = (jsBufferObject *)LContext->bufferObjectNameSpace.data[LContext->PixelUnpackBuffer];
if ( newLayout.pitch != 0 && !bufferObject->mapped )
{
gcmTexture->gpuLayout = newLayout;
if ( gcmTexture->gpuAddressId != GMM_ERROR && gcmTexture->pbo == NULL )
_RGLPlatformFreeGcmTexture( texture );
gcmTexture->pbo = bufferObject;
gcmTexture->gpuAddressId = gpuId;
gcmTexture->gpuAddressIdOffset = gpuIdOffset;
gcmTexture->pool = SURFACE_POOL_LINEAR;
RGLTexture *gcmTexture = ( RGLTexture * )texture->platformTexture;
// Get size of texture in GPU layout
gcmTexture->gpuSize = _RGLPad( gcmTexture->gpuLayout.baseHeight * gcmTexture->gpuLayout.pitch, 1);
++bufferObject->refCount;
}
else
{
const GLuint bytesPerPixel = newLayout.pixelBits / 8;
RGLSurface src;
src.source = SURFACE_SOURCE_PBO;
src.width = image->width;
src.height = image->height;
src.bpp = bytesPerPixel;
src.pitch = pboPitch;
src.format = newLayout.internalFormat;
src.pool = SURFACE_POOL_LINEAR;
src.ppuData = NULL;
src.dataId = gpuId;
src.dataIdOffset = gpuIdOffset;
texture->revalidate |= TEXTURE_REVALIDATE_LAYOUT;
_RGLPlatformValidateTextureResources( texture );
RGLSurface dst;
dst.source = SURFACE_SOURCE_TEXTURE;
dst.width = image->width;
dst.height = image->height;
dst.bpp = bytesPerPixel;
dst.pitch = gcmTexture->gpuLayout.pitch;
dst.format = gcmTexture->gpuLayout.internalFormat;
dst.pool = gcmTexture->pool;
dst.ppuData = NULL;
dst.dataId = gcmTexture->gpuAddressId;
dst.dataIdOffset = gcmTexture->gpuAddressIdOffset;
transfer_params_t transfer_params;
transfer_params.dst_id = dst.dataId;
transfer_params.dst_id_offset = dst.dataIdOffset;
transfer_params.dst_pitch = dst.pitch ? dst.pitch : (dst.bpp * dst.width);
transfer_params.dst_x = 0;
transfer_params.dst_y = 0;
transfer_params.src_id = src.dataId;
transfer_params.src_id_offset = src.dataIdOffset;
transfer_params.src_pitch = src.pitch ? src.pitch : (src.bpp * src.width);
transfer_params.src_x = 0;
transfer_params.src_y = 0;
transfer_params.width = width;
transfer_params.height = height;
transfer_params.bpp = src.bpp;
transfer_params.fifo_ptr = &_RGLState.fifo;
TransferDataVidToVid(&transfer_params);
}
_RGLImageFreeCPUStorage( image );
image->dataState = IMAGE_DATASTATE_GPU;
texture->revalidate &= ~( TEXTURE_REVALIDATE_LAYOUT | TEXTURE_REVALIDATE_IMAGES );
texture->revalidate |= TEXTURE_REVALIDATE_PARAMETERS;
_RGLTextureTouchFBOs( texture );
return GL_TRUE;
}
static GLboolean _RGLPlatformTextureReference( jsTexture *texture, GLuint pitch, jsBufferObject *bufferObject, GLintptr offset )
{
RGLTexture *gcmTexture = (RGLTexture *)texture->platformTexture;
RGLTextureLayout newLayout;
_RGLPlatformChooseGPUFormatAndLayout(texture, GL_TRUE, pitch, &newLayout);
texture->isRenderTarget = GL_TRUE;
if(gcmTexture->gpuAddressId != GMM_ERROR)
_RGLPlatformDestroyTexture( texture );
RGLBufferObject *gcmBuffer = (RGLBufferObject *)& bufferObject->platformBufferObject;
gcmTexture->gpuLayout = newLayout;
gcmTexture->pool = gcmBuffer->pool;
gcmTexture->gpuAddressId = gcmBuffer->bufferId;
gcmTexture->gpuAddressIdOffset = offset;
gcmTexture->gpuSize = _RGLPad( newLayout.baseHeight * newLayout.pitch, 1);
texture->revalidate &= ~(TEXTURE_REVALIDATE_LAYOUT | TEXTURE_REVALIDATE_IMAGES);
texture->revalidate |= TEXTURE_REVALIDATE_PARAMETERS;
_RGLTextureTouchFBOs(texture);
return GL_TRUE;
}
static inline void _RGLSetColorDepthBuffers( RGLRenderTarget *rt, RGLRenderTargetEx const * const args )
{
CellGcmSurface * grt = &rt->gcmRenderTarget;
rt->colorBufferCount = args->colorBufferCount;
GLuint oldHeight;
GLuint oldyInverted;
oldyInverted = rt->yInverted;
oldHeight = rt->gcmRenderTarget.height;
GLuint i;
for ( i = 0; i < args->colorBufferCount; i++ )
{
if ( args->colorPitch[i] == 0 )
{
grt->colorOffset[i] = 0;
grt->colorPitch[i] = 0x200;
grt->colorLocation[i] = CELL_GCM_LOCATION_LOCAL;
}
else
{
if ( args->colorId[i] != GMM_ERROR )
{
if ( gmmIdIsMain(args->colorId[i]) )
grt->colorLocation[i] = CELL_GCM_LOCATION_MAIN;
else
grt->colorLocation[i] = CELL_GCM_LOCATION_LOCAL;
grt->colorOffset[i] = gmmIdToOffset(args->colorId[i]) + args->colorIdOffset[i];
grt->colorPitch[i] = args->colorPitch[i];
}
}
}
for ( ; i < RGL_SETRENDERTARGET_MAXCOUNT; i++ )
{
grt->colorOffset[i] = grt->colorOffset[0];
grt->colorPitch[i] = grt->colorPitch[0];
grt->colorLocation[i] = grt->colorLocation[0];
}
rt->yInverted = args->yInverted;
grt->x = args->xOffset;
grt->y = args->yOffset;
grt->width = args->width;
grt->height = args->height;
if (( grt->height != oldHeight ) | ( rt->yInverted != oldyInverted ) )
{
RGLViewportState *v = &_RGLState.state.viewport;
_RGLFifoGlViewport( v->x, v->y, v->w, v->h );
}
}
void _RGLFifoGlSetRenderTarget( RGLRenderTargetEx const * const args )
{
RGLRenderTarget *rt = &_RGLState.renderTarget;
CellGcmSurface * grt = &_RGLState.renderTarget.gcmRenderTarget;
_RGLSetColorDepthBuffers( rt, args );
//set color depth formats
grt->colorFormat = CELL_GCM_SURFACE_A8R8G8B8;
grt->depthFormat = CELL_GCM_SURFACE_Z24S8;
grt->depthLocation = CELL_GCM_LOCATION_LOCAL;
grt->depthOffset = 0;
grt->depthPitch = 64;
grt->antialias = CELL_GCM_SURFACE_CENTER_1;
grt->type = CELL_GCM_SURFACE_PITCH;
switch ( rt->colorBufferCount )
{
case 0:
grt->colorTarget = CELL_GCM_SURFACE_TARGET_NONE;
break;
case 1:
grt->colorTarget = CELL_GCM_SURFACE_TARGET_1;
break;
case 2:
grt->colorTarget = CELL_GCM_SURFACE_TARGET_MRT1;
break;
case 3:
grt->colorTarget = CELL_GCM_SURFACE_TARGET_MRT2;
break;
case 4:
grt->colorTarget = CELL_GCM_SURFACE_TARGET_MRT3;
break;
default:
break;
}
cellGcmSetSurfaceInline( &_RGLState.fifo, grt);
}
void _RGLSetError( GLenum error )
{
RARCH_ERR("Error code: %d\n", error);
}
GLAPI GLenum APIENTRY glGetError(void)
{
if ( !_CurrentContext )
return GL_INVALID_OPERATION;
else
{
GLenum error = _CurrentContext->error;
_CurrentContext->error = GL_NO_ERROR;
return error;
}
}
static inline void _RGLPushProgramPushBuffer( _CGprogram * cgprog )
{
RGLFifo *fifo = &_RGLState.fifo;
GLuint spaceInWords = cgprog->constantPushBufferWordSize + 4 + 32;
if ( fifo->current + spaceInWords + 1024 > fifo->end )
_RGLOutOfSpaceCallback( fifo, spaceInWords );
uint32_t padding_in_word = ( ( 0x10-(((uint32_t)_RGLState.fifo.current)&0xf))&0xf )>>2;
uint32_t padded_size = ( ((cgprog->constantPushBufferWordSize)<<2) + 0xf )&~0xf;
cellGcmSetNopCommandUnsafeInline( &_RGLState.fifo, padding_in_word);
memcpy(_RGLState.fifo.current, cgprog->constantPushBuffer, padded_size);
_RGLState.fifo.current+=cgprog->constantPushBufferWordSize;
}
static GLuint _RGLValidateStates( void )
{
PSGLcontext* LContext = _CurrentContext;
RGLDriver *driver= (RGLDriver *)_CurrentDevice->rasterDriver;
LContext->needValidate &= PSGL_VALIDATE_ALL;
GLuint dirty = LContext->needValidate;
GLuint needValidate = LContext->needValidate;
if ( RGL_UNLIKELY( needValidate & PSGL_VALIDATE_FRAMEBUFFER ) )
{
_RGLValidateFramebuffer();
needValidate = LContext->needValidate;
}
if ( RGL_UNLIKELY( needValidate & PSGL_VALIDATE_TEXTURES_USED ) )
{
long unitInUseCount = LContext->BoundFragmentProgram->samplerCount;
const GLuint* unitsInUse = LContext->BoundFragmentProgram->samplerUnits;
for ( long i = 0; i < unitInUseCount; ++i )
{
long unit = unitsInUse[i];
jsTexture* texture = LContext->TextureImageUnits[unit].currentTexture;
_RGLPlatformValidateTextureStage( unit, texture );
}
}
if ( RGL_UNLIKELY( needValidate & PSGL_VALIDATE_VERTEX_PROGRAM ) )
{
const void *header = LContext->BoundVertexProgram;
const _CGprogram *vs = ( const _CGprogram* ) header;
__dcbt(vs->ucode);
__dcbt(((uint8_t*)vs->ucode)+128);
__dcbt(((uint8_t*)vs->ucode)+256);
__dcbt(((uint8_t*)vs->ucode)+384);
CellCgbVertexProgramConfiguration conf;
conf.instructionSlot = vs->header.vertexProgram.instructionSlot;
conf.instructionCount = vs->header.instructionCount;
conf.registerCount = vs->header.vertexProgram.registerCount;
conf.attributeInputMask = vs->header.attributeInputMask;
RGLFifo *fifo = &_RGLState.fifo;
GLuint spaceInWords = 7 + 5 * conf.instructionCount;
if ( fifo->current + spaceInWords + 1024 > fifo->end )
_RGLOutOfSpaceCallback( fifo, spaceInWords );
cellGcmSetVertexProgramLoadInline( &_RGLState.fifo, &conf, vs->ucode);
RGLInterpolantState *s = &_RGLState.state.interpolant;
s->vertexProgramAttribMask = vs->header.vertexProgram.attributeOutputMask;
cellGcmSetVertexAttribOutputMaskInline( &_RGLState.fifo, s->vertexProgramAttribMask & s->fragmentProgramAttribMask);
_CGprogram *program = ( _CGprogram* )vs;
int count = program->defaultValuesIndexCount;
for ( int i = 0; i < count; i++ )
{
const CgParameterEntry *parameterEntry = program->parametersEntries + program->defaultValuesIndices[i].entryIndex;
if (( parameterEntry->flags & CGPF_REFERENCED ) && ( parameterEntry->flags & CGPV_MASK ) == CGPV_CONSTANT )
{
const float *itemDefaultValues = program->defaultValues + program->defaultValuesIndices[i].defaultValueIndex;
const GLfloat *value = itemDefaultValues;
const CgParameterResource *parameterResource = _RGLGetParameterResource( program, parameterEntry );
if ( parameterResource->resource != ( unsigned short ) - 1 )
{
switch ( parameterResource->type )
{
case CG_FLOAT:
case CG_FLOAT1:
case CG_FLOAT2:
case CG_FLOAT3:
case CG_FLOAT4:
cellGcmSetVertexProgramParameterBlockInline( &_RGLState.fifo, parameterResource->resource, 1, value );
break;
case CG_FLOAT4x4:
{
GLfloat v2[16];
v2[0] = value[0];v2[1] = value[4];v2[2] = value[8];v2[3] = value[12];
v2[4] = value[1];v2[5] = value[5];v2[6] = value[9];v2[7] = value[13];
v2[8] = value[2];v2[9] = value[6];v2[10] = value[10];v2[11] = value[14];
v2[12] = value[3];v2[13] = value[7];v2[14] = value[11];v2[15] = value[15];
cellGcmSetVertexProgramParameterBlockInline( &_RGLState.fifo, parameterResource->resource, 4, v2 );
}
break;
case CG_FLOAT3x3:
{
GLfloat v2[12];
v2[0] = value[0];v2[1] = value[3];v2[2] = value[6];v2[3] = 0;
v2[4] = value[1];v2[5] = value[4];v2[6] = value[7];v2[7] = 0;
v2[8] = value[2];v2[9] = value[5];v2[10] = value[8];v2[11] = 0;
cellGcmSetVertexProgramParameterBlockInline( &_RGLState.fifo, parameterResource->resource, 3, v2 );
}
break;
case CG_HALF:
case CG_HALF1:
case CG_HALF2:
case CG_HALF3:
case CG_HALF4:
case CG_INT:
case CG_INT1:
case CG_INT2:
case CG_INT3:
case CG_INT4:
case CG_BOOL:
case CG_BOOL1:
case CG_BOOL2:
case CG_BOOL3:
case CG_BOOL4:
case CG_FIXED:
case CG_FIXED1:
case CG_FIXED2:
case CG_FIXED3:
case CG_FIXED4:
cellGcmSetVertexProgramParameterBlockInline( &_RGLState.fifo, parameterResource->resource, 1, value );
break;
case CG_HALF4x4:
case CG_INT4x4:
case CG_BOOL4x4:
case CG_FIXED4x4:
{
GLfloat v2[16];
v2[0] = value[0];v2[1] = value[4];v2[2] = value[8];v2[3] = value[12];
v2[4] = value[1];v2[5] = value[5];v2[6] = value[9];v2[7] = value[13];
v2[8] = value[2];v2[9] = value[6];v2[10] = value[10];v2[11] = value[14];
v2[12] = value[3];v2[13] = value[7];v2[14] = value[11];v2[15] = value[15];
cellGcmSetVertexProgramParameterBlockInline( &_RGLState.fifo, parameterResource->resource, 4, v2 );
}
break;
case CG_HALF3x3:
case CG_INT3x3:
case CG_BOOL3x3:
case CG_FIXED3x3:
{
GLfloat v2[12];
v2[0] = value[0];v2[1] = value[3];v2[2] = value[6];v2[3] = 0;
v2[4] = value[1];v2[5] = value[4];v2[6] = value[7];v2[7] = 0;
v2[8] = value[2];v2[9] = value[5];v2[10] = value[8];v2[11] = 0;
cellGcmSetVertexProgramParameterBlockInline( &_RGLState.fifo, parameterResource->resource, 3, v2 );
}
break;
default:
break;
}
}
}
}
if(!(LContext->needValidate & PSGL_VALIDATE_VERTEX_CONSTANTS) && LContext->BoundVertexProgram->parentContext)
{
cellGcmSetTransformBranchBitsInline( &_RGLState.fifo, LContext->BoundVertexProgram->controlFlowBools | LContext->BoundVertexProgram->parentContext->controlFlowBoolsShared );
_RGLPushProgramPushBuffer( LContext->BoundVertexProgram );
}
}
if ( RGL_LIKELY( needValidate & PSGL_VALIDATE_VERTEX_CONSTANTS ) && LContext->BoundVertexProgram->parentContext)
{
cellGcmSetTransformBranchBitsInline( &_RGLState.fifo, LContext->BoundVertexProgram->controlFlowBools | LContext->BoundVertexProgram->parentContext->controlFlowBoolsShared );
_RGLPushProgramPushBuffer( LContext->BoundVertexProgram );
}
if ( RGL_UNLIKELY( needValidate & PSGL_VALIDATE_VERTEX_TEXTURES_USED ) )
{
for ( int unit = 0; unit < MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++unit )
{
jsTexture *texture = LContext->VertexTextureImages[unit];
if ( texture )
if ( RGL_UNLIKELY( texture->revalidate ) )
_RGLPlatformValidateTextureResources( texture );
cellGcmSetVertexTextureAddressInline( &_RGLState.fifo, unit, CELL_GCM_TEXTURE_WRAP, CELL_GCM_TEXTURE_WRAP);
cellGcmSetVertexTextureControlInline( &_RGLState.fifo, unit, GL_FALSE, 0, 256);
cellGcmSetVertexTextureFilterInline( &_RGLState.fifo, unit, 0);
}
}
if ( RGL_UNLIKELY( needValidate & PSGL_VALIDATE_FRAGMENT_PROGRAM ) )
{
_CGprogram *program = LContext->BoundFragmentProgram;
const GLvoid *header = program;
const _CGprogram *ps = ( const _CGprogram * )header;
CellCgbFragmentProgramConfiguration conf;
conf.offset = gmmIdToOffset(ps->loadProgramId) + ps->loadProgramOffset;
RGLInterpolantState *s = &_RGLState.state.interpolant;
s->fragmentProgramAttribMask |= ps->header.attributeInputMask | CELL_GCM_ATTRIB_OUTPUT_MASK_POINTSIZE;
conf.attributeInputMask = s->vertexProgramAttribMask & s->fragmentProgramAttribMask;
conf.texCoordsInputMask = ps->header.fragmentProgram.texcoordInputMask;
conf.texCoords2D = ps->header.fragmentProgram.texcoord2d;
conf.texCoordsCentroid = ps->header.fragmentProgram.texcoordCentroid;
int fragmentControl = ( 1 << 15 ) | ( 1 << 10 );
fragmentControl |= ps->header.fragmentProgram.flags & CGF_DEPTHREPLACE ? 0xE : 0x0;
fragmentControl |= ps->header.fragmentProgram.flags & CGF_OUTPUTFROMH0 ? 0x00 : 0x40;
fragmentControl |= ps->header.fragmentProgram.flags & CGF_PIXELKILL ? 0x80 : 0x00;
conf.fragmentControl = fragmentControl;
conf.registerCount = ps->header.fragmentProgram.registerCount < 2 ? 2 : ps->header.fragmentProgram.registerCount;
uint32_t controlTxp = _CurrentContext->AllowTXPDemotion;
conf.fragmentControl &= ~CELL_GCM_MASK_SET_SHADER_CONTROL_CONTROL_TXP;
conf.fragmentControl |= controlTxp << CELL_GCM_SHIFT_SET_SHADER_CONTROL_CONTROL_TXP;
cellGcmSetFragmentProgramLoadInline( &_RGLState.fifo, &conf);
cellGcmSetZMinMaxControlInline( &_RGLState.fifo, ( ps->header.fragmentProgram.flags & CGF_DEPTHREPLACE ) ? CELL_GCM_FALSE : CELL_GCM_TRUE, CELL_GCM_FALSE, CELL_GCM_FALSE );
driver->fpLoadProgramId = program->loadProgramId;
driver->fpLoadProgramOffset = program->loadProgramOffset;
}
if ( RGL_LIKELY(( needValidate & ~( PSGL_VALIDATE_TEXTURES_USED |
PSGL_VALIDATE_VERTEX_PROGRAM |
PSGL_VALIDATE_VERTEX_CONSTANTS |
PSGL_VALIDATE_VERTEX_TEXTURES_USED |
PSGL_VALIDATE_FRAGMENT_PROGRAM ) ) == 0 ) )
{
LContext->needValidate = 0;
return dirty;
}
if ( RGL_UNLIKELY( needValidate & PSGL_VALIDATE_BLENDING ) )
{
if ((LContext->Blending || LContext->BlendingMrt[0] || LContext->BlendingMrt[1] || LContext->BlendingMrt[2]))
{
GLuint hwColor;
cellGcmSetBlendEnableInline( &_RGLState.fifo, LContext->Blending);
cellGcmSetBlendEnableMrtInline( &_RGLState.fifo, LContext->BlendingMrt[0], LContext->BlendingMrt[1], LContext->BlendingMrt[2] );
RGL_CALC_COLOR_LE_ARGB8( &hwColor, RGL_CLAMPF_01(LContext->BlendColor.R), RGL_CLAMPF_01(LContext->BlendColor.G), RGL_CLAMPF_01(LContext->BlendColor.B), RGL_CLAMPF_01(LContext->BlendColor.A) );
cellGcmSetBlendColorInline( &_RGLState.fifo, hwColor, hwColor);
cellGcmSetBlendEquationInline( &_RGLState.fifo, (RGLEnum)LContext->BlendEquationRGB, (RGLEnum)LContext->BlendEquationAlpha );
cellGcmSetBlendFuncInline( &_RGLState.fifo, (RGLEnum)LContext->BlendFactorSrcRGB, (RGLEnum)LContext->BlendFactorDestRGB, (RGLEnum)LContext->BlendFactorSrcAlpha, (RGLEnum)LContext->BlendFactorDestAlpha);
}
else
{
cellGcmSetBlendEnableInline( &_RGLState.fifo, CELL_GCM_FALSE);
cellGcmSetBlendEnableMrtInline( &_RGLState.fifo, CELL_GCM_FALSE, CELL_GCM_FALSE, CELL_GCM_FALSE );
}
}
if ( RGL_UNLIKELY( needValidate & PSGL_VALIDATE_SHADER_SRGB_REMAP ) )
{
cellGcmSetFragmentProgramGammaEnableInline( &_RGLState.fifo, LContext->ShaderSRGBRemap ? CELL_GCM_TRUE : CELL_GCM_FALSE);
LContext->needValidate &= ~PSGL_VALIDATE_SHADER_SRGB_REMAP;
}
LContext->needValidate = 0;
return dirty;
}
PSGLcontext *psglGetCurrentContext()
{
return _CurrentContext;
}
static void _RGLResetContext( PSGLcontext *LContext )
{
_RGLTexNameSpaceResetNames( &LContext->textureNameSpace );
_RGLTexNameSpaceResetNames( &LContext->bufferObjectNameSpace );
_RGLTexNameSpaceResetNames( &LContext->framebufferNameSpace );
_RGLTexNameSpaceResetNames( &LContext->attribSetNameSpace );
LContext->ViewPort.X = 0;
LContext->ViewPort.Y = 0;
LContext->ViewPort.XSize = 0;
LContext->ViewPort.YSize = 0;
LContext->ClearColor.R = 0.f;
LContext->ClearColor.G = 0.f;
LContext->ClearColor.B = 0.f;
LContext->ClearColor.A = 0.f;
LContext->ShaderSRGBRemap = GL_FALSE;
LContext->Blending = GL_FALSE;
LContext->BlendingMrt[0] = GL_FALSE;
LContext->BlendingMrt[1] = GL_FALSE;
LContext->BlendingMrt[2] = GL_FALSE;
LContext->BlendColor.R = 0.0f;
LContext->BlendColor.G = 0.0f;
LContext->BlendColor.B = 0.0f;
LContext->BlendColor.A = 0.0f;
LContext->BlendEquationRGB = GL_FUNC_ADD;
LContext->BlendEquationAlpha = GL_FUNC_ADD;
LContext->BlendFactorSrcRGB = GL_ONE;
LContext->BlendFactorDestRGB = GL_ZERO;
LContext->BlendFactorSrcAlpha = GL_ONE;
LContext->BlendFactorDestAlpha = GL_ZERO;
for ( int i = 0;i < MAX_TEXTURE_IMAGE_UNITS;++i )
{
jsTextureImageUnit *tu = LContext->TextureImageUnits + i;
tu->bound2D = 0;
tu->fragmentTarget = 0;
tu->envMode = GL_MODULATE;
tu->envColor.R = 0.f;
tu->envColor.G = 0.f;
tu->envColor.B = 0.f;
tu->envColor.A = 0.f;
tu->currentTexture = NULL;
}
for(int i = 0; i < MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i)
LContext->VertexTextureImages[i] = NULL;
LContext->ActiveTexture = 0;
LContext->CurrentImageUnit = LContext->TextureImageUnits;
LContext->packAlignment = 4;
LContext->unpackAlignment = 4;
LContext->CS_ActiveTexture = 0;
_RGLResetAttributeState( &LContext->defaultAttribs0 );
LContext->attribs = &LContext->defaultAttribs0;
LContext->attribSetName = 0;
LContext->attribSetDirty = GL_FALSE;
LContext->framebuffer = 0;
LContext->VertexProgram = GL_FALSE;
LContext->BoundVertexProgram = 0;
LContext->FragmentProgram = GL_FALSE;
LContext->BoundFragmentProgram = 0;
LContext->ArrayBuffer = 0;
LContext->PixelUnpackBuffer = 0;
LContext->TextureBuffer = 0;
LContext->VSync = GL_FALSE;
LContext->AllowTXPDemotion = GL_FALSE;
}
static jsTexture *_RGLAllocateTexture (void)
{
GLuint size = sizeof( jsTexture ) + sizeof( RGLTexture);
jsTexture *texture = ( jsTexture * )malloc( size );
memset( texture, 0, size );
texture->target = 0;
texture->minFilter = GL_NEAREST_MIPMAP_LINEAR;
texture->magFilter = GL_LINEAR;
texture->gammaRemap = 0;
texture->usage = 0;
texture->isRenderTarget = GL_FALSE;
texture->image = NULL;
texture->isComplete = GL_FALSE;
texture->imageCount = 0;
texture->revalidate = 0;
texture->referenceBuffer = NULL;
new( &texture->framebuffers ) RGL::Vector<jsFramebuffer *>();
RGLTexture *gcmTexture = ( RGLTexture * )texture->platformTexture;
memset( gcmTexture, 0, sizeof( RGLTexture ) );
gcmTexture->gpuAddressId = GMM_ERROR;
return texture;
}
static void _RGLFreeTexture( jsTexture *texture )
{
_RGLTextureTouchFBOs( texture );
texture->framebuffers.~Vector<jsFramebuffer *>();
if ( texture->image )
{
for ( GLuint i = 0;i < texture->imageCount;++i )
{
jsImage *image = texture->image + i;
_RGLImageFreeCPUStorage( image );
}
if(texture->image != NULL)
free( texture->image );
}
if ( texture->referenceBuffer )
texture->referenceBuffer->textureReferences.removeElement( texture );
_RGLPlatformDestroyTexture( texture );
if(texture != NULL)
free( texture );
}
PSGLcontext* psglCreateContext (void)
{
PSGLcontext* LContext = ( PSGLcontext* )malloc( sizeof( PSGLcontext ) );
if ( !LContext ) return NULL;
memset( LContext, 0, sizeof( PSGLcontext ) );
LContext->error = GL_NO_ERROR;
_RGLTexNameSpaceInit( &LContext->textureNameSpace, ( jsTexNameSpaceCreateFunction )_RGLAllocateTexture, ( jsTexNameSpaceDestroyFunction )_RGLFreeTexture );
for ( int i = 0;i < MAX_TEXTURE_IMAGE_UNITS;++i )
{
jsTextureImageUnit *tu = LContext->TextureImageUnits + i;
tu->default2D = _RGLAllocateTexture();
if ( !tu->default2D )
{
psglDestroyContext( LContext );
return NULL;
}
tu->default2D->target = GL_TEXTURE_2D;
}
_RGLTexNameSpaceInit( &LContext->bufferObjectNameSpace, ( jsTexNameSpaceCreateFunction )_RGLCreateBufferObject, ( jsTexNameSpaceDestroyFunction )_RGLFreeBufferObject );
_RGLTexNameSpaceInit( &LContext->framebufferNameSpace, ( jsTexNameSpaceCreateFunction )_RGLCreateFramebuffer, ( jsTexNameSpaceDestroyFunction )_RGLDestroyFramebuffer );
_RGLTexNameSpaceInit( &LContext->attribSetNameSpace, ( jsTexNameSpaceCreateFunction )_RGLCreateAttribSet, ( jsTexNameSpaceDestroyFunction )_RGLDestroyAttribSet );
LContext->needValidate = 0;
LContext->everAttached = 0;
LContext->RGLcgLastError = CG_NO_ERROR;
LContext->RGLcgErrorCallbackFunction = NULL;
LContext->RGLcgContextHead = ( CGcontext )NULL;
LContext->cgProgramNameSpace.data = NULL;
LContext->cgProgramNameSpace.firstFree = NULL;
LContext->cgProgramNameSpace.capacity = 0;
LContext->cgParameterNameSpace.data = NULL;
LContext->cgParameterNameSpace.firstFree = NULL;
LContext->cgParameterNameSpace.capacity = 0;
LContext->cgContextNameSpace.data = NULL;
LContext->cgContextNameSpace.firstFree = NULL;
LContext->cgContextNameSpace.capacity = 0;
_RGLResetContext( LContext );
if ( _RGLContextCreateHook )
_RGLContextCreateHook( LContext );
return( LContext );
}
void psglResetCurrentContext (void)
{
PSGLcontext *context = _CurrentContext;
_RGLResetContext( context );
context->needValidate |= PSGL_VALIDATE_ALL;
}
static bool context_shutdown = false;
void psglDestroyContext( PSGLcontext* LContext )
{
context_shutdown = true;
if ( _CurrentContext == LContext )
{
cellGcmSetInvalidateVertexCache( &_RGLState.fifo);
_RGLFifoFinish( &_RGLState.fifo );
}
while ( LContext->RGLcgContextHead != ( CGcontext )NULL )
{
PSGLcontext* current = _CurrentContext;
_CurrentContext = LContext;
cgDestroyContext( LContext->RGLcgContextHead );
_CurrentContext = current;
}
if (LContext->cgProgramNameSpace.data)
free( LContext->cgProgramNameSpace.data );
LContext->cgProgramNameSpace.data = NULL;
LContext->cgProgramNameSpace.capacity = 0;
LContext->cgProgramNameSpace.firstFree = NULL;
if (LContext->cgParameterNameSpace.data)
free( LContext->cgParameterNameSpace.data );
LContext->cgParameterNameSpace.data = NULL;
LContext->cgParameterNameSpace.capacity = 0;
LContext->cgParameterNameSpace.firstFree = NULL;
if (LContext->cgContextNameSpace.data)
free( LContext->cgContextNameSpace.data );
LContext->cgContextNameSpace.data = NULL;
LContext->cgContextNameSpace.capacity = 0;
LContext->cgContextNameSpace.firstFree = NULL;
if ( _RGLContextDestroyHook ) _RGLContextDestroyHook( LContext );
for ( int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i )
{
jsTextureImageUnit* tu = LContext->TextureImageUnits + i;
if ( tu->default2D ) _RGLFreeTexture( tu->default2D );
}
_RGLTexNameSpaceFree( &LContext->textureNameSpace );
_RGLTexNameSpaceFree( &LContext->bufferObjectNameSpace );
_RGLTexNameSpaceFree( &LContext->framebufferNameSpace );
_RGLTexNameSpaceFree( &LContext->attribSetNameSpace );
if ( _CurrentContext == LContext )
psglMakeCurrent( NULL, NULL );
if(LContext != NULL)
free( LContext );
}
void _RGLAttachContext( PSGLdevice *device, PSGLcontext* context )
{
if ( !context->everAttached )
{
context->ViewPort.XSize = device->deviceParameters.width;
context->ViewPort.YSize = device->deviceParameters.height;
context->everAttached = GL_TRUE;
_RGLFifoGlViewport(context->ViewPort.X, context->ViewPort.Y,
context->ViewPort.XSize, context->ViewPort.YSize, 0.0f, 1.0f);
}
context->needValidate = PSGL_VALIDATE_ALL;
context->attribs->DirtyMask = ( 1 << MAX_VERTEX_ATTRIBS ) - 1;
}
GLAPI void APIENTRY glEnable( GLenum cap )
{
PSGLcontext* LContext = _CurrentContext;
switch (cap)
{
case GL_SHADER_SRGB_REMAP_SCE:
LContext->ShaderSRGBRemap = GL_TRUE;
LContext->needValidate |= PSGL_VALIDATE_SHADER_SRGB_REMAP;
break;
case GL_BLEND:
LContext->Blending = GL_TRUE;
LContext->BlendingMrt[0] = GL_TRUE;
LContext->BlendingMrt[1] = GL_TRUE;
LContext->BlendingMrt[2] = GL_TRUE;
LContext->needValidate |= PSGL_VALIDATE_BLENDING;
break;
case GL_BLEND_MRT0_SCE:
LContext->Blending = GL_TRUE;
LContext->needValidate |= PSGL_VALIDATE_BLENDING;
break;
case GL_BLEND_MRT1_SCE:
LContext->BlendingMrt[0] = GL_TRUE;
LContext->needValidate |= PSGL_VALIDATE_BLENDING;
break;
case GL_BLEND_MRT2_SCE:
LContext->BlendingMrt[1] = GL_TRUE;
LContext->needValidate |= PSGL_VALIDATE_BLENDING;
break;
case GL_BLEND_MRT3_SCE:
LContext->BlendingMrt[2] = GL_TRUE;
LContext->needValidate |= PSGL_VALIDATE_BLENDING;
break;
case GL_POINT_SMOOTH:
break;
case GL_DITHER:
break;
case GL_POINT_SPRITE_OES:
case GL_VERTEX_PROGRAM_POINT_SIZE_ARB:
break;
case GL_VSYNC_SCE:
LContext->VSync = GL_TRUE;
break;
case GL_FRAGMENT_PROGRAM_CONTROL_CONTROLTXP_SCE:
LContext->AllowTXPDemotion = GL_TRUE;
LContext->needValidate |= PSGL_VALIDATE_FRAGMENT_PROGRAM;
break;
default:
_RGLSetError( GL_INVALID_ENUM );
return;
}
}
GLAPI void APIENTRY glDisable(GLenum cap)
{
PSGLcontext* LContext = _CurrentContext;
switch ( cap )
{
case GL_SHADER_SRGB_REMAP_SCE:
LContext->ShaderSRGBRemap = GL_FALSE;
LContext->needValidate |= PSGL_VALIDATE_SHADER_SRGB_REMAP;
break;
case GL_BLEND:
LContext->Blending = GL_FALSE;
LContext->BlendingMrt[0] = GL_FALSE;
LContext->BlendingMrt[1] = GL_FALSE;
LContext->BlendingMrt[2] = GL_FALSE;
LContext->needValidate |= PSGL_VALIDATE_BLENDING;
break;
case GL_BLEND_MRT0_SCE:
LContext->Blending = GL_FALSE;
LContext->needValidate |= PSGL_VALIDATE_BLENDING;
break;
case GL_BLEND_MRT1_SCE:
LContext->BlendingMrt[0] = GL_FALSE;
LContext->needValidate |= PSGL_VALIDATE_BLENDING;
break;
case GL_BLEND_MRT2_SCE:
LContext->BlendingMrt[1] = GL_FALSE;
LContext->needValidate |= PSGL_VALIDATE_BLENDING;
break;
case GL_BLEND_MRT3_SCE:
LContext->BlendingMrt[2] = GL_FALSE;
LContext->needValidate |= PSGL_VALIDATE_BLENDING;
break;
case GL_POINT_SMOOTH:
case GL_LINE_SMOOTH:
break;
case GL_DITHER:
break;
case GL_POINT_SPRITE_OES:
case GL_VERTEX_PROGRAM_POINT_SIZE_ARB:
break;
case GL_VSYNC_SCE:
LContext->VSync = GL_FALSE;
break;
case GL_FRAGMENT_PROGRAM_CONTROL_CONTROLTXP_SCE:
LContext->AllowTXPDemotion = GL_FALSE;
LContext->needValidate |= PSGL_VALIDATE_FRAGMENT_PROGRAM;
break;
default:
_RGLSetError( GL_INVALID_ENUM );
return;
}
}
GLAPI void APIENTRY glEnableClientState(GLenum array)
{
PSGLcontext* LContext = _CurrentContext;
switch(array)
{
case GL_VERTEX_ARRAY:
_RGLEnableVertexAttribArrayNV( _RGL_ATTRIB_POSITION_INDEX );
break;
case GL_COLOR_ARRAY:
_RGLEnableVertexAttribArrayNV( _RGL_ATTRIB_PRIMARY_COLOR_INDEX );
break;
case GL_NORMAL_ARRAY:
_RGLEnableVertexAttribArrayNV( _RGL_ATTRIB_NORMAL_INDEX );
break;
case GL_TEXTURE_COORD_ARRAY:
_RGLEnableVertexAttribArrayNV( _RGL_ATTRIB_TEX_COORD0_INDEX + LContext->CS_ActiveTexture );
break;
default:
_RGLSetError( GL_INVALID_ENUM );
return;
}
}
GLAPI void APIENTRY glDisableClientState(GLenum array)
{
PSGLcontext* LContext = _CurrentContext;
switch ( array )
{
case GL_VERTEX_ARRAY:
_RGLDisableVertexAttribArrayNV( _RGL_ATTRIB_POSITION_INDEX );
break;
case GL_COLOR_ARRAY:
_RGLDisableVertexAttribArrayNV( _RGL_ATTRIB_PRIMARY_COLOR_INDEX );
break;
case GL_NORMAL_ARRAY:
_RGLDisableVertexAttribArrayNV( _RGL_ATTRIB_NORMAL_INDEX );
break;
case GL_TEXTURE_COORD_ARRAY:
_RGLDisableVertexAttribArrayNV( _RGL_ATTRIB_TEX_COORD0_INDEX + LContext->CS_ActiveTexture );
break;
default:
_RGLSetError( GL_INVALID_ENUM );
return;
}
}
GLAPI void APIENTRY glFlush(void)
{
PSGLcontext *LContext = _CurrentContext;
RGLFifo *fifo = &_RGLState.fifo;
if ( RGL_UNLIKELY( LContext->needValidate ) )
_RGLValidateStates();
cellGcmSetInvalidateVertexCache( &_RGLState.fifo);
_RGLFifoFlush( fifo );
}
GLAPI void APIENTRY glFinish(void)
{
glFlush();
cellGcmSetInvalidateVertexCache( &_RGLState.fifo);
_RGLFifoFinish( &_RGLState.fifo );
}
GLAPI const GLubyte* APIENTRY glGetString( GLenum name )
{
switch ( name )
{
case GL_VENDOR:
return(( GLubyte* )_RGLVendorString );
case GL_RENDERER:
return(( GLubyte* )_RGLRendererString );
case GL_VERSION:
return(( GLubyte* )_RGLVersionNumber );
case GL_EXTENSIONS:
return(( GLubyte* )_RGLExtensionsString );
default:
{
_RGLSetError( GL_INVALID_ENUM );
return(( GLubyte* )NULL );
}
}
}
void psglInit( PSGLinitOptions* options )
{
if ( !_RGLInitCompleted )
{
int ret = cellSysmoduleLoadModule( CELL_SYSMODULE_GCM_SYS );
ret = cellSysmoduleLoadModule( CELL_SYSMODULE_RESC );
_RGLDeviceInit( options );
_CurrentContext = NULL;
_CurrentDevice = NULL;
}
_RGLInitCompleted = 1;
}
void psglExit (void)
{
PSGLcontext* LContext = _CurrentContext;
if ( LContext )
{
glFlush();
cellGcmSetInvalidateVertexCache ( &_RGLState.fifo);
_RGLFifoFinish( &_RGLState.fifo );
psglMakeCurrent( NULL, NULL );
_RGLDeviceExit();
_CurrentContext = NULL;
_RGLInitCompleted = 0;
}
}
#undef __STRICT_ANSI__
GLAPI void APIENTRY glVertexPointer( GLint size, GLenum type, GLsizei stride, const GLvoid* pointer )
{
_RGLVertexAttribPointerNV( _RGL_ATTRIB_POSITION_INDEX, size, type, GL_FALSE, stride, pointer );
}
GLAPI void APIENTRY glTexCoordPointer( GLint size, GLenum type, GLsizei stride, const GLvoid* pointer )
{
PSGLcontext* LContext = _CurrentContext;
_RGLVertexAttribPointerNV(
_RGL_ATTRIB_TEX_COORD0_INDEX + LContext->CS_ActiveTexture,
size,
type,
GL_FALSE,
stride,
pointer );
}
GLAPI void APIENTRY glColorPointer( GLint size, GLenum type, GLsizei stride, const GLvoid* pointer )
{
_RGLVertexAttribPointerNV( _RGL_ATTRIB_PRIMARY_COLOR_INDEX, size, type, GL_TRUE, stride, pointer );
}
static GLboolean _RGLPlatformNeedsConversion( const jsAttributeState* as, GLuint index )
{
const jsAttribute* attrib = as->attrib + index;
switch ( attrib->clientType )
{
case GL_SHORT:
case GL_HALF_FLOAT_ARB:
case GL_FLOAT:
case GL_FIXED_11_11_10_SCE:
return GL_FALSE;
case GL_UNSIGNED_BYTE:
if ( attrib->normalized ||
attrib->clientSize == 4 )
return GL_FALSE;
break;
default:
break;
}
RARCH_WARN("Attribute %d needs conversion. Slow path ahead.\n", index);
return GL_TRUE;
}
static int _RGLGetTypeSize( GLenum type )
{
switch ( type )
{
#define DECLARE_PACKED_TYPE(REALTYPE,TYPE,N,S1,S2,S3,S4,REV) \
case TYPE: \
return sizeof(type_##REALTYPE);
DECLARE_PACKED_TYPES
#undef DECLARE_PACKED_TYPE
#define DECLARE_UNPACKED_TYPE(TYPE) \
case TYPE: \
return sizeof(type_##TYPE);
DECLARE_UNPACKED_TYPES
#undef DECLARE_UNPACKED_TYPE
default:
return 0;
}
}
void _RGLVertexAttribPointerNV(
GLuint index,
GLint fsize,
GLenum type,
GLboolean normalized,
GLsizei stride,
const GLvoid* pointer )
{
PSGLcontext* LContext = _CurrentContext;
GLsizei defaultStride = 0;
switch ( type )
{
case GL_FLOAT:
case GL_HALF_FLOAT_ARB:
case GL_BYTE:
case GL_UNSIGNED_BYTE:
case GL_SHORT:
case GL_FIXED:
defaultStride = fsize * _RGLGetTypeSize( type );
break;
case GL_FIXED_11_11_10_SCE:
defaultStride = 4;
break;
default:
_RGLSetError( GL_INVALID_ENUM );
return;
}
jsAttributeState* as = LContext->attribs;
jsAttribute* attrib = as->attrib + index;
attrib->clientSize = fsize;
attrib->clientType = type;
attrib->clientStride = stride ? stride : defaultStride;
attrib->clientData = ( void* )pointer;
GLuint oldArrayBuffer = attrib->arrayBuffer;
attrib->arrayBuffer = LContext->ArrayBuffer;
attrib->normalized = normalized;
RGLBIT_ASSIGN( as->HasVBOMask, index, attrib->arrayBuffer != 0 );
GLboolean needConvert = _RGLPlatformNeedsConversion( as, index );
RGLBIT_ASSIGN( as->NeedsConversionMask, index, needConvert );
RGLBIT_TRUE( as->DirtyMask, index );
if ( LContext->attribSetName )
{
jsAttribSet* attribSet = (jsAttribSet*)LContext->attribSetNameSpace.data[LContext->attribSetName];
if ( oldArrayBuffer )
{
int refcount = 0;
for(unsigned int i = 0; i < MAX_VERTEX_ATTRIBS; ++i )
{
if ( attribSet->attribs.attrib[i].arrayBuffer == oldArrayBuffer ) ++refcount;
}
if(refcount == 1)
{
jsBufferObject *buffer = (jsBufferObject *)LContext->bufferObjectNameSpace.data[oldArrayBuffer];
buffer->attribSets.removeElement(attribSet);
}
}
if ( attrib->arrayBuffer )
{
jsBufferObject *buffer = (jsBufferObject *)LContext->bufferObjectNameSpace.data[attrib->arrayBuffer];
buffer->attribSets.appendUnique(attribSet);
}
attribSet->dirty = GL_TRUE;
LContext->attribSetDirty = GL_TRUE;
}
}
void _RGLEnableVertexAttribArrayNV( GLuint index )
{
PSGLcontext *LContext = _CurrentContext;
jsAttribSet* attribSet = (jsAttribSet*)LContext->attribSetNameSpace.data[LContext->attribSetName];
RGLBIT_TRUE( LContext->attribs->EnabledMask, index );
RGLBIT_TRUE( LContext->attribs->DirtyMask, index );
if ( LContext->attribSetName )
{
attribSet->dirty = GL_TRUE;
LContext->attribSetDirty = GL_TRUE;
}
}
void _RGLDisableVertexAttribArrayNV( GLuint index )
{
PSGLcontext *LContext = _CurrentContext;
jsAttribSet* attribSet = (jsAttribSet*)LContext->attribSetNameSpace.data[LContext->attribSetName];
RGLBIT_FALSE( LContext->attribs->EnabledMask, index );
RGLBIT_TRUE( LContext->attribs->DirtyMask, index );
if ( LContext->attribSetName )
{
attribSet->dirty = GL_TRUE;
LContext->attribSetDirty = GL_TRUE;
}
}
static GLuint _RGLValidateAttributesSlow( jsDrawParams *dparams)
{
PSGLcontext* LContext = _CurrentContext;
RGLDriver *driver= (RGLDriver *)_CurrentDevice->rasterDriver;
jsAttributeState* as = LContext->attribs;
void* xferBuffer = NULL;
GLuint xferId = GMM_ERROR;
GLuint VBOId = GMM_ERROR;
GLuint gpuOffset;
if(RGL_UNLIKELY( dparams->xferTotalSize))
{
xferId = gmmAlloc(0, dparams->xferTotalSize);
xferBuffer = gmmIdToAddress(xferId);
}
unsigned int needsUpdateMask = (as->DirtyMask | (as->EnabledMask & ~as->HasVBOMask));
LContext->attribSetDirty = GL_FALSE;
if ( needsUpdateMask )
{
for ( GLuint i = 0; i < MAX_VERTEX_ATTRIBS; ++i )
{
if(!RGLBIT_GET(needsUpdateMask, i))
continue;
jsAttribute* attrib = as->attrib + i;
if ( RGLBIT_GET( as->EnabledMask, i ) )
{
GLsizei stride = attrib->clientStride;
const GLuint freq = attrib->frequency;
if ( RGL_UNLIKELY( dparams->attribXferSize[i] ) )
{
GmmBaseBlock *pBaseBlock = (GmmBaseBlock *)xferId;
GLuint maxElements = dparams->firstVertex + dparams->vertexCount;
GLuint offset;
if(RGLBIT_GET( as->ModuloMask, i))
offset = ( maxElements > freq ) ? 0 : dparams->firstVertex * stride;
else
offset = ( dparams->firstVertex / freq ) * stride;
char *b = (char *)xferBuffer + dparams->attribXferOffset[i];
memcpy( b + offset, ( char * )attrib->clientData + offset,
dparams->attribXferSize[i] - offset );
gpuOffset = gmmAddressToOffset(pBaseBlock->address, pBaseBlock->isMain) + (b - ( char * )xferBuffer);
}
else
{
VBOId = _RGLGetBufferObjectOrigin( attrib->arrayBuffer );
GmmBaseBlock *pBaseBlock = (GmmBaseBlock *)VBOId;
gpuOffset = gmmAddressToOffset(pBaseBlock->address, pBaseBlock->isMain) + (( const GLubyte* )attrib->clientData - ( const GLubyte* )NULL );
}
if(attrib->clientSize == 0)
{
stride = 0;
attrib->normalized = 0;
attrib->clientType = RGL_FLOAT;
gpuOffset = 0;
}
uint8_t gcmType = 0;
switch ( (RGLEnum)attrib->clientType )
{
case RGL_UNSIGNED_BYTE:
gcmType = attrib->normalized ? CELL_GCM_VERTEX_UB : CELL_GCM_VERTEX_UB256;
break;
case RGL_SHORT:
gcmType = attrib->normalized ? CELL_GCM_VERTEX_S1 : CELL_GCM_VERTEX_S32K;
break;
case RGL_FLOAT:
gcmType = CELL_GCM_VERTEX_F;
break;
case RGL_HALF_FLOAT:
gcmType = CELL_GCM_VERTEX_SF;
break;
case RGL_CMP:
attrib->clientSize = 1;
gcmType = CELL_GCM_VERTEX_CMP;
break;
default:
break;
}
cellGcmSetVertexDataArrayInline( &_RGLState.fifo, i, freq, stride, attrib->clientSize, gcmType, CELL_GCM_LOCATION_LOCAL, gpuOffset );
}
else
{
cellGcmSetVertexDataArrayInline( &_RGLState.fifo, i, 0, 0, 0, CELL_GCM_VERTEX_F, CELL_GCM_LOCATION_LOCAL, 0);
cellGcmSetVertexData4fInline( &_RGLState.fifo, i,attrib->value);
}
}
cellGcmSetFrequencyDividerOperationInline( &_RGLState.fifo, as->ModuloMask);
driver->invalidateVertexCache = GL_TRUE;
}
as->DirtyMask = 0;
if ( xferId != GMM_ERROR )
gmmFree( xferId );
return 0;
}
GLAPI void APIENTRY glDrawArrays( GLenum mode, GLint first, GLsizei count )
{
static uint8_t s_dparams_buff[ (sizeof(jsDrawParams) + 0x7f) & ~0x7f ] __attribute__((aligned(128)));
PSGLcontext* LContext = _CurrentContext;
jsAttributeState* as = LContext->attribs;
RGLDriver *driver= (RGLDriver *)_CurrentDevice->rasterDriver;
const GLuint clientSideMask = as->EnabledMask & ~as->HasVBOMask;
if ( RGL_UNLIKELY( ! RGLBIT_GET( LContext->attribs->EnabledMask, _RGL_ATTRIB_POSITION_INDEX ) ) ) return;
uint32_t _tmp_clear_loop = ((sizeof(jsDrawParams) + 0x7f) & ~0x7f) >> 7;
do{
--_tmp_clear_loop;
__dcbz(s_dparams_buff+(_tmp_clear_loop << 7));
}while(_tmp_clear_loop);
jsDrawParams *dparams = (jsDrawParams *)s_dparams_buff;
dparams->mode = mode;
dparams->firstVertex = first;
dparams->vertexCount = count;
GLuint maxElements = dparams->firstVertex + dparams->vertexCount;
if ( LContext->needValidate )
_RGLValidateStates();
if ( RGL_UNLIKELY( clientSideMask ) )
{
for ( int i = 0; i < MAX_VERTEX_ATTRIBS; ++i )
{
dparams->attribXferOffset[i] = 0;
dparams->attribXferSize[i] = 0;
if(clientSideMask & (1 << i))
{
jsAttribute* attrib = as->attrib + i;
const GLuint freq = attrib->frequency;
GLuint count;
if (RGLBIT_GET(as->ModuloMask, i))
count = maxElements > freq ? freq : maxElements;
else
count = ( maxElements + freq - 1 ) / freq;
const GLuint numBytes = attrib->clientStride * count;
dparams->attribXferOffset[i] = dparams->xferTotalSize;
dparams->attribXferSize[i] = numBytes;
const GLuint numBytesPadded = _RGLPad( numBytes, 128 );
dparams->xferTotalSize += numBytesPadded;
dparams->attribXferTotalSize += numBytesPadded;
}
}
}
if ( driver->flushBufferCount != 0 )
driver->invalidateVertexCache = GL_TRUE;
uint32_t totalXfer = 0;
for (GLuint i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
totalXfer += dparams->attribXferSize[i];
GLuint gpuOffset = _RGLValidateAttributesSlow( dparams);
(void)gpuOffset;
if(driver->invalidateVertexCache)
{
driver->invalidateVertexCache = GL_FALSE;
cellGcmSetInvalidateVertexCache ( &_RGLState.fifo);
}
GmmBaseBlock *pBaseBlock = (GmmBaseBlock *)driver->fpLoadProgramId;
cellGcmSetUpdateFragmentProgramParameterInline( &_RGLState.fifo, gmmAddressToOffset(pBaseBlock->address, pBaseBlock->isMain) +driver->fpLoadProgramOffset );
cellGcmSetDrawArraysInline( &_RGLState.fifo, CELL_GCM_PRIMITIVE_QUADS, dparams->firstVertex, dparams->vertexCount);
}
GLAPI void APIENTRY glGenTextures( GLsizei n, GLuint *textures )
{
PSGLcontext* LContext = _CurrentContext;
_RGLTexNameSpaceGenNames( &LContext->textureNameSpace, n, textures );
}
static void _RGLTextureUnbind( PSGLcontext* context, GLuint name )
{
int unit;
for (unit = 0; unit < MAX_TEXTURE_IMAGE_UNITS; ++unit)
{
jsTextureImageUnit *tu = context->TextureImageUnits + unit;
GLboolean dirty = GL_FALSE;
if ( tu->bound2D == name )
{
tu->bound2D = 0;
dirty = GL_TRUE;
}
if ( dirty )
{
tu->currentTexture = _RGLGetCurrentTexture( tu, GL_TEXTURE_2D );
context->needValidate |= PSGL_VALIDATE_TEXTURES_USED;
}
}
if(_RGLTexNameSpaceIsName( &context->textureNameSpace, name))
{
jsTexture*texture = ( jsTexture * )context->textureNameSpace.data[name];
for ( unit = 0;unit < MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++unit )
{
if ( context->VertexTextureImages[unit] == texture )
{
context->VertexTextureImages[unit] = NULL;
context->needValidate |= PSGL_VALIDATE_VERTEX_TEXTURES_USED;
}
}
}
}
GLAPI void APIENTRY glDeleteTextures( GLsizei n, const GLuint *textures )
{
PSGLcontext* LContext = _CurrentContext;
for(int i = 0;i < n; ++i)
if(textures[i])
_RGLTextureUnbind(LContext, textures[i]);
_RGLTexNameSpaceDeleteNames( &LContext->textureNameSpace, n, textures );
}
GLAPI void APIENTRY glTexParameteri( GLenum target, GLenum pname, GLint param )
{
PSGLcontext* LContext = _CurrentContext;
jsTexture *texture = _RGLGetCurrentTexture( LContext->CurrentImageUnit, target );
switch ( pname )
{
case GL_TEXTURE_MIN_FILTER:
texture->minFilter = param;
if ( texture->referenceBuffer == 0 )
texture->revalidate |= TEXTURE_REVALIDATE_LAYOUT;
break;
case GL_TEXTURE_MAG_FILTER:
texture->magFilter = param;
break;
case GL_TEXTURE_MAX_LEVEL:
case GL_TEXTURE_WRAP_S:
case GL_TEXTURE_WRAP_T:
case GL_TEXTURE_WRAP_R:
case GL_TEXTURE_FROM_VERTEX_PROGRAM_SCE:
break;
case GL_TEXTURE_ALLOCATION_HINT_SCE:
texture->usage = param;
texture->revalidate |= TEXTURE_REVALIDATE_LAYOUT;
break;
case GL_TEXTURE_MIN_LOD:
case GL_TEXTURE_MAX_LOD:
case GL_TEXTURE_LOD_BIAS:
case GL_TEXTURE_MAX_ANISOTROPY_EXT:
case GL_DEPTH_TEXTURE_MODE_ARB:
case GL_TEXTURE_COMPARE_MODE_ARB:
case GL_TEXTURE_COMPARE_FUNC_ARB:
break;
case GL_TEXTURE_GAMMA_REMAP_R_SCE:
case GL_TEXTURE_GAMMA_REMAP_G_SCE:
case GL_TEXTURE_GAMMA_REMAP_B_SCE:
case GL_TEXTURE_GAMMA_REMAP_A_SCE:
{
GLuint bit = 1 << ( pname - GL_TEXTURE_GAMMA_REMAP_R_SCE );
if(param)
texture->gammaRemap |= bit;
else
texture->gammaRemap &= ~bit;
}
break;
default:
_RGLSetError( GL_INVALID_ENUM );
return;
}
texture->revalidate |= TEXTURE_REVALIDATE_PARAMETERS;
LContext->needValidate |= PSGL_VALIDATE_TEXTURES_USED | PSGL_VALIDATE_VERTEX_TEXTURES_USED;
}
GLAPI void APIENTRY glBindTexture( GLenum target, GLuint name )
{
PSGLcontext* LContext = _CurrentContext;
jsTextureImageUnit *unit = LContext->CurrentImageUnit;
_RGLBindTextureInternal( unit, name);
}
static void _RGLReallocateImages( jsTexture *texture, GLsizei dimension )
{
GLuint oldCount = texture->imageCount;
if ( dimension <= 0 )
dimension = 1;
GLuint n = 1 + _RGLLog2( dimension );
n = MAX( n, oldCount );
jsImage *images = ( jsImage * )realloc( texture->image, n * sizeof( jsImage ) );
memset( images + oldCount, 0, ( n - oldCount )*sizeof( jsImage ) );
texture->image = images;
texture->imageCount = n;
}
GLAPI void APIENTRY glTexImage2D( GLenum target, GLint level, GLint internalFormat,
GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels )
{
PSGLcontext* LContext = _CurrentContext;
jsTexture *texture;
jsImage *image;
jsTextureImageUnit *unit = LContext->CurrentImageUnit;
jsTexture *tex = _RGLGetCurrentTexture(unit, GL_TEXTURE_2D);
if(0 >= (int)tex->imageCount)
_RGLReallocateImages(tex, MAX(width, height));
image = tex->image;
texture = tex;
image->dataState = IMAGE_DATASTATE_UNSET;
GLboolean directPBO = GL_FALSE;
if ( LContext->PixelUnpackBuffer != 0 )
{
directPBO = _RGLPlatformTexturePBOImage(
texture,
image,
internalFormat,
width, height,
format, type,
pixels );
}
if ( !directPBO )
{
jsBufferObject* bufferObject = NULL;
if ( LContext->PixelUnpackBuffer != 0 )
{
bufferObject = (jsBufferObject *)LContext->bufferObjectNameSpace.data[LContext->PixelUnpackBuffer];
pixels = _RGLPlatformBufferObjectMap( bufferObject, GL_READ_ONLY ) +
(( const GLubyte* )pixels - ( const GLubyte* )NULL );
}
_RGLSetImage(image, internalFormat, width, height, 1, LContext->unpackAlignment,
format, type, pixels);
if ( LContext->PixelUnpackBuffer != 0 )
{
RGLBufferObject *jsBuffer = ( RGLBufferObject * )bufferObject->platformBufferObject;
if ( --jsBuffer->mapCount == 0 )
{
if ( jsBuffer->mapAccess != GL_READ_ONLY )
{
RGLDriver *driver= (RGLDriver *)_CurrentDevice->rasterDriver;
--driver->flushBufferCount;
driver->invalidateVertexCache = GL_TRUE;
}
jsBuffer->mapAccess = GL_NONE;
GmmBaseBlock *pBaseBlock = (GmmBaseBlock *)jsBuffer->bufferId;
if (!pBaseBlock->isTile)
{
GmmBlock *pBlock = (GmmBlock *)jsBuffer->bufferId;
pBlock->isPinned = 0;
}
}
}
texture->revalidate |= TEXTURE_REVALIDATE_IMAGES;
}
_RGLTextureTouchFBOs( texture );
LContext->needValidate |= PSGL_VALIDATE_TEXTURES_USED | PSGL_VALIDATE_VERTEX_TEXTURES_USED;
}
GLAPI void APIENTRY glActiveTexture(GLenum texture)
{
PSGLcontext* LContext = _CurrentContext;
int unit = texture - GL_TEXTURE0;
LContext->ActiveTexture = unit;
LContext->CurrentImageUnit = unit < MAX_TEXTURE_IMAGE_UNITS ? LContext->TextureImageUnits + unit : NULL;
}
GLAPI void APIENTRY glClientActiveTexture(GLenum texture)
{
PSGLcontext* LContext = _CurrentContext;
LContext->CS_ActiveTexture = texture - GL_TEXTURE0;
}
GLAPI void APIENTRY glPixelStorei(GLenum pname, GLint param)
{
PSGLcontext* LContext = _CurrentContext;
switch ( pname )
{
case GL_PACK_ALIGNMENT:
LContext->packAlignment = param;
break;
case GL_UNPACK_ALIGNMENT:
LContext->unpackAlignment = param;
break;
default:
_RGLSetError( GL_INVALID_ENUM );
return;
}
}
GLAPI void APIENTRY glTextureReferenceSCE( GLenum target, GLuint levels, GLuint baseWidth, GLuint baseHeight, GLuint baseDepth, GLenum internalFormat, GLuint pitch, GLintptr offset )
{
PSGLcontext* LContext = _CurrentContext;
jsTexture *texture = _RGLGetCurrentTexture( LContext->CurrentImageUnit, GL_TEXTURE_2D);
jsBufferObject *bufferObject = (jsBufferObject *)LContext->bufferObjectNameSpace.data[LContext->TextureBuffer];
_RGLReallocateImages( texture, MAX( baseWidth, MAX( baseHeight, baseDepth ) ) );
GLuint width = baseWidth;
GLuint height = baseHeight;
_RGLSetImage(texture->image, GL_RGB5_A1, width, height, 0, LContext->unpackAlignment,
0, 0, NULL );
width = MAX( 1U, width / 2 );
height = MAX( 1U, height / 2 );
texture->usage = GL_TEXTURE_LINEAR_GPU_SCE;
GLboolean r = _RGLPlatformTextureReference( texture, pitch, bufferObject, offset );
if(!r)
return;
bufferObject->textureReferences.pushBack( texture );
texture->referenceBuffer = bufferObject;
texture->offset = offset;
_RGLTextureTouchFBOs( texture );
LContext->needValidate |= PSGL_VALIDATE_TEXTURES_USED | PSGL_VALIDATE_VERTEX_TEXTURES_USED ;
}
GLAPI void APIENTRY glViewport( GLint x, GLint y, GLsizei width, GLsizei height )
{
PSGLcontext* LContext = _CurrentContext;
LContext->ViewPort.X = x;
LContext->ViewPort.Y = y;
LContext->ViewPort.XSize = width;
LContext->ViewPort.YSize = height;
_RGLFifoGlViewport(LContext->ViewPort.X, LContext->ViewPort.Y,
LContext->ViewPort.XSize, LContext->ViewPort.YSize, 0.0f, 1.0f);
}
jsTexture *_RGLGetCurrentTexture( const jsTextureImageUnit *unit, GLenum target )
{
PSGLcontext* LContext = _CurrentContext;
GLuint name = unit->bound2D;
jsTexture *defaultTexture = unit->default2D;
if ( name )
return ( jsTexture * )LContext->textureNameSpace.data[name];
else
return defaultTexture;
}
CgprogramHookFunction _cgProgramCreateHook = NULL;
CgprogramHookFunction _cgProgramDestroyHook = NULL;
CgprogramCopyHookFunction _cgProgramCopyHook = NULL;
cgRTCgcCompileHookFunction _cgRTCgcCompileProgramHook = NULL;
cgRTCgcFreeHookFunction _cgRTCgcFreeCompiledProgramHook;
CgcontextHookFunction _cgContextCreateHook = NULL;
CgcontextHookFunction _cgContextDestroyHook = NULL;
CgparameterHookFunction _cgParameterCreateHook = NULL;
CgparameterHookFunction _cgParameterDestroyHook = NULL;
typedef struct RGLcgProfileMapType
{
CGprofile id;
char* string;
int is_vertex_program;
} RGLcgProfileMapType;
static void _RGLCgProgramPushFront( _CGcontext* ctx, _CGprogram* prog )
{
prog->next = ctx->programList;
ctx->programList = prog;
prog->parentContext = ctx;
ctx->programCount++;
}
static _CGprogram* _RGLCgProgramFindPrev( _CGcontext* ctx, _CGprogram* prog )
{
_CGprogram* ptr = ctx->programList;
while ( ptr != NULL && prog != ptr->next )
ptr = ptr->next;
return ptr;
}
void _RGLCgProgramErase( _CGprogram* prog )
{
if ( _cgProgramDestroyHook ) _cgProgramDestroyHook( prog );
switch ( prog->header.profile )
{
case CG_PROFILE_SCE_VP_TYPEB:
case CG_PROFILE_SCE_VP_RSX:
case CG_PROFILE_SCE_FP_TYPEB:
case CG_PROFILE_SCE_FP_RSX:
_RGLPlatformProgramErase( prog );
break;
default:
break;
}
if ( prog->id )
_RGLEraseName( &_CurrentContext->cgProgramNameSpace, ( jsName )prog->id );
if ( prog->runtimeElf )
free( prog->runtimeElf );
memset( prog, 0, sizeof( _CGprogram ) );
}
bool _RGLCgCreateProgramChecks( CGcontext ctx, CGprofile profile, CGenum program_type )
{
if ( !CG_IS_CONTEXT( ctx ) )
{
_RGLCgRaiseError( CG_INVALID_CONTEXT_HANDLE_ERROR );
return false;
}
switch ( profile )
{
case CG_PROFILE_SCE_VP_TYPEB:
case CG_PROFILE_SCE_FP_TYPEB:
case CG_PROFILE_SCE_VP_RSX:
case CG_PROFILE_SCE_FP_RSX:
break;
default:
_RGLCgRaiseError( CG_UNKNOWN_PROFILE_ERROR );
return false;
}
switch ( program_type )
{
case CG_BINARY:
case CG_SOURCE:
break;
default:
_RGLCgRaiseError( CG_INVALID_ENUMERANT_ERROR );
return false;
}
return true;
}
typedef struct
{
const char* elfFile;
size_t elfFileSize;
const char *symtab;
size_t symbolSize;
size_t symbolCount;
const char *symbolstrtab;
const char* shadertab;
size_t shadertabSize;
const char* strtab;
size_t strtabSize;
const char* consttab;
size_t consttabSize;
} CGELFBinary;
typedef struct
{
const char *texttab;
size_t texttabSize;
const char *paramtab;
size_t paramtabSize;
int index;
} CGELFProgram;
static bool cgOpenElf( const void *ptr, size_t size, CGELFBinary *elfBinary )
{
while(1)
{
size_t shadertabSize;
size_t consttabSize;
size_t strtabSize;
size_t symbolSize;
size_t symbolCount;
const char *symbolstrtab;
const char *symtab = findSymbolSectionInPlace(( const char * )ptr, size, &symbolSize, &symbolCount, &symbolstrtab );
if ( !symtab )
break;
const char *shadertab = findSectionInPlace(( const char* )ptr, size, ".shadertab", &shadertabSize );
if ( !shadertab )
break;
const char *strtab = findSectionInPlace(( const char* )ptr, size, ".strtab", &strtabSize );
if ( !strtab )
break;
const char *consttab = findSectionInPlace(( const char* )ptr, size, ".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;
}
static bool cgGetElfProgramByIndex( CGELFBinary *elfBinary, int index, CGELFProgram *elfProgram )
{
while(1)
{
char sectionName[64];
snprintf( sectionName, sizeof(sectionName), ".text%04i", index );
size_t texttabSize;
const char *texttab = findSectionInPlace( elfBinary->elfFile, elfBinary->elfFileSize, sectionName, &texttabSize );
if ( !texttab )
break;
snprintf( sectionName, sizeof(sectionName), ".paramtab%04i", index );
size_t paramtabSize;
const char *paramtab = findSectionInPlace( elfBinary->elfFile, elfBinary->elfFileSize, sectionName, &paramtabSize );
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 ret;
if ( name == NULL || name[0] == '\0' )
ret = 0;
else
ret = lookupSymbolValueInPlace( elfBinary->symtab, elfBinary->symbolSize, elfBinary->symbolCount, elfBinary->symbolstrtab, name );
if (ret != -1)
return cgGetElfProgramByIndex( elfBinary, ret, elfProgram );
else
return false;
}
static 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(prog == NULL)
{
_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;
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_TYPEB:
//case CG_PROFILE_SCE_VP_TYPEC:
case CG_PROFILE_SCE_VP_RSX:
// TODO ************** need to include the entry symbol too
success = _RGLGenerateProgram( prog, VERTEX_PROFILE_INDEX, programHeader,
ucode, parameterHeader, NULL, stringTable, defaultValues );
break;
case CG_PROFILE_SCE_FP_TYPEB:
//case CG_PROFILE_SCE_FP_TYPEC:
case CG_PROFILE_SCE_FP_RSX:
success = _RGLGenerateProgram( prog, FRAGMENT_PROFILE_INDEX, programHeader, ucode, parameterHeader, NULL, 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, ( jsName )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;
}
static CGprogram _RGLCgUpdateProgramAtIndex( CGprogramGroup group, int index, int refcount );
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.
if ( profile == ( CGprofile )7005 )
profile = CG_PROFILE_SCE_VP_RSX;
if ( profile == ( CGprofile )7006 )
profile = CG_PROFILE_SCE_FP_RSX;
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, cgGetProfileString(profile), entry, args, &compiled_program );
if(!compiled_program)
{
_RGLCgRaiseError( CG_COMPILER_ERROR );
return NULL;
}
binaryBuffer = compiled_program;
}
else
{
RARCH_ERR("The CG runtime compiler hasn't been setup. cgRTCgcInit() should be called prior to this function.\n" );
_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))
{
//convert NV file to the runtime format
if ( program_type == CG_BINARY )
{
RARCH_WARN("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.\n");
}
//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 != CG_PROFILE_SCE_FP_TYPEB ) && ( nvProgram->profile != CG_PROFILE_SCE_VP_TYPEB ) &&
( 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 )
{
RARCH_ERR("Invalid CG binary program.\n");
_RGLCgRaiseError( CG_COMPILER_ERROR );
if ( compiled_program )
_cgRTCgcFreeCompiledProgramHook( compiled_program );
return NULL;
}
if ( compiled_program )
_cgRTCgcFreeCompiledProgramHook( compiled_program );
size_t stringTableSize = stringTableArray.size() * sizeof( stringTable[0] );
size_t defaultTableSize = defaultValuesArray.size() * sizeof( defaultValues[0] );
int paddedSize = _RGLPad( compiled_program_size, 4 );
char *runtimeElf = (char*)memalign( 16, paddedSize + stringTableSize + defaultTableSize );
if ( !runtimeElf )
{
_RGLCgRaiseError( CG_MEMORY_ALLOC_ERROR );
return NULL;
}
bConvertedToElf = true;
memcpy( runtimeElf, runtimeElfShader, compiled_program_size );
convertNvToElfFreeBinaryShader( runtimeElfShader );
float* pDefaultValues = ( float* )(( char* )runtimeElf + paddedSize );
defaultValues = pDefaultValues;
if ( defaultTableSize )
memcpy( pDefaultValues, &defaultValuesArray[0], defaultTableSize );
char *pStringTable = ( char* )runtimeElf + paddedSize + defaultTableSize;
stringTable = pStringTable;
if ( stringTableSize )
memcpy( pStringTable, &stringTableArray[0], stringTableSize );
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
{
CGELFBinary elfBinary;
CGELFProgram elfProgram;
if ((( intptr_t )binaryBuffer ) & 15 )
{
RARCH_ERR("CG Binary not aligned on 16 bytes, needed for ucode section.\n");
_RGLCgRaiseError( CG_PROGRAM_LOAD_ERROR );
return NULL;
}
bool res = cgOpenElf( binaryBuffer, 0, &elfBinary );
if(!res)
{
RARCH_ERR("Not a valid ELF.\n");
_RGLCgRaiseError( CG_PROGRAM_LOAD_ERROR );
return NULL;
}
if(!cgGetElfProgramByName( &elfBinary, entry, &elfProgram))
{
RARCH_ERR("Couldn't find the shader entry in the CG binary.\n");
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(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 )
{
if ( profile == ( CGprofile )7005 )
profile = CG_PROFILE_SCE_VP_RSX;
if ( profile == ( CGprofile )7006 )
profile = CG_PROFILE_SCE_FP_RSX;
if ( program_type == CG_ROW_MAJOR )
program_type = CG_BINARY;
if ( !_RGLCgCreateProgramChecks( ctx, profile, program_type ) )
return NULL;
FILE* fp = NULL;
if ( RGL_LIKELY( program_type == CG_BINARY ) )
{
CGprogram ret = NULL;
_CGcontext *context = _cgGetContextPtr( ctx );
CGprogramGroup group = NULL;
group = context->groupList;
while ( group )
{
const char *groupName = _RGLCgGetProgramGroupName( group );
if ( groupName && !strcmp( groupName, program_file ) )
{
int index;
if ( entry == NULL )
index = 0;
else
index = _RGLCgGetProgramIndex( group, entry );
if ( index >= 0 )
{
ret = _RGLCgUpdateProgramAtIndex( group, index, 1 );
break;
}
else
{
return ( CGprogram )NULL;
}
}
group = group->next;
}
if ( ret )
return ret;
else
{
fp = fopen( program_file, "rb");
if ( fp == NULL )
{
_RGLCgRaiseError( CG_FILE_READ_ERROR );
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;
if ( filetag == ElfTag )
{
fclose( fp );
group = _RGLCgCreateProgramGroupFromFile( ctx, program_file );
if ( group )
{
_CGprogramGroup *_group = ( _CGprogramGroup * )group;
_group->userCreated = false;
if ( entry == NULL )
{
if ( group->programCount == 1 )
ret = _RGLCgUpdateProgramAtIndex( group, 0, 1 );
}
else
{
int index = _RGLCgGetProgramIndex( group, entry );
if ( index == -1 )
{
RARCH_ERR("Couldn't find the shader entry in the CG binary.\n");
}
else
ret = _RGLCgUpdateProgramAtIndex( group, index, 1 );
}
}
return ret;
}
}
}
if ( !fp )
{
fp = fopen( program_file, "rb" );
if ( fp == NULL )
{
_RGLCgRaiseError( CG_FILE_READ_ERROR );
return ( CGprogram )NULL;
}
}
size_t file_size = 0;
fseek(fp, 0, SEEK_END);
file_size = ftell(fp);
rewind(fp);
char* ptr = (char*)malloc( file_size + 1 );
if (ptr == NULL)
{
_RGLCgRaiseError( CG_MEMORY_ALLOC_ERROR );
fclose( fp );
return ( CGprogram )NULL;
}
fread( ptr, file_size, 1, fp );
fclose( fp );
if ( program_type == CG_SOURCE )
ptr[file_size] = '\0';
CGprogram ret = cgCreateProgram( ctx, program_type, ptr, profile, entry, args );
free( ptr );
return ret;
}
CG_API CGprogram cgCopyProgram( CGprogram program )
{
if ( !CG_IS_PROGRAM( program ) )
{
_RGLCgRaiseError( CG_INVALID_PROGRAM_HANDLE_ERROR );
return NULL;
}
_CGprogram* prog = _cgGetProgPtr( program );
if ( prog == NULL )
{
_RGLCgRaiseError( CG_INVALID_PROGRAM_HANDLE_ERROR );
return ( CGprogram )NULL;
}
_CGprogram* newprog;
size_t paddedProgramSize = 0;
size_t ucodeSize = 0;
if (prog->header.profile == CG_PROFILE_SCE_FP_TYPEB || 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(newprog == NULL)
{
_RGLCgRaiseError( CG_MEMORY_ALLOC_ERROR );
return ( CGprogram )NULL;
}
memset( newprog, 0, sizeof( _CGprogram ) );
newprog->header.profile = prog->header.profile;
newprog->parentContext = prog->parentContext;
newprog->id = ( CGprogram )_RGLCreateName( &_CurrentContext->cgProgramNameSpace, newprog );
int success = 0;
switch ( prog->header.profile )
{
case CG_PROFILE_SCE_VP_TYPEB:
case CG_PROFILE_SCE_VP_RSX:
case CG_PROFILE_SCE_FP_TYPEB:
case CG_PROFILE_SCE_FP_RSX:
success = _RGLPlatformCopyProgram( prog, newprog );
break;
default:
_RGLCgRaiseError( CG_UNKNOWN_PROFILE_ERROR );
success = 0;
break;
}
if ( success == 0 )
{
free( newprog );
_RGLEraseName( &_CurrentContext->cgProgramNameSpace, ( jsName )newprog->id );
return ( CGprogram )NULL;
}
if (prog->header.profile == CG_PROFILE_SCE_FP_TYPEB || prog->header.profile == CG_PROFILE_SCE_FP_RSX)
{
newprog->ucode = (char*)newprog + paddedProgramSize;
memcpy((char*)newprog->ucode, (char*)prog->ucode, ucodeSize);
}
if ( prog->programGroup )
{
newprog->programGroup = prog->programGroup;
newprog->programIndexInGroup = -1;
_RGLCgUpdateProgramAtIndex( newprog->programGroup, -1, 1 );
}
_RGLCgProgramPushFront(newprog->parentContext, newprog);
if(_cgProgramCopyHook)
_cgProgramCopyHook(newprog, prog);
return newprog->id;
}
CG_API void cgDestroyProgram( CGprogram program )
{
if ( !CG_IS_PROGRAM( program ) )
{
_RGLCgRaiseError( CG_INVALID_PROGRAM_HANDLE_ERROR );
return;
}
_CGprogram* ptr = _cgGetProgPtr( program );
if ( ptr == NULL )
{
_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 )
{
_RGLCgRaiseError( CG_INVALID_PROGRAM_HANDLE_ERROR );
return;
}
else
{
bool isGroupMember = ( ptr->programIndexInGroup != -1 );
_RGLCgUpdateProgramAtIndex( ptr->programGroup, ptr->programIndexInGroup, -1 );
if ( isGroupMember )
return;
}
}
}
_CGcontext* ctx = ptr->parentContext;
if ( ptr == ctx->programList )
{
_CGprogram* p = ctx->programList;
ctx->programList = p->next;
_RGLCgProgramErase( p );
if(p != NULL)
free( p );
}
else
{
_CGprogram* p = _RGLCgProgramFindPrev( ctx, ptr );
_CGprogram* next = p->next;
if ( next )
{
p->next = next->next;
_RGLCgProgramErase( next );
if(next != NULL)
free( next );
}
}
return;
}
static CGprogram _RGLCgUpdateProgramAtIndex( CGprogramGroup group, int index, int refcount )
{
if ( index < ( int )group->programCount )
{
if ( index >= 0 )
{
if ( refcount == 1 && group->programs[index].refCount == 1 )
{
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 void _RGLCgAddGroup( CGcontext ctx, CGprogramGroup group )
{
_CGcontext *context = _cgGetContextPtr( ctx );
if ( !context->groupList )
context->groupList = group;
else
{
_CGprogramGroup *current = context->groupList;
while ( current->next )
current = current->next;
current->next = group;
}
}
static void _RGLCgRemoveGroup( CGcontext ctx, CGprogramGroup group )
{
_CGcontext *context = _cgGetContextPtr( 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;
}
}
CGprogramGroup _RGLCgCreateProgramGroupFromFile( CGcontext ctx, const char *group_file )
{
FILE *fp = fopen(group_file, "rb");
if(fp == NULL)
{
_RGLCgRaiseError( CG_FILE_READ_ERROR );
return ( CGprogramGroup )NULL;
}
size_t file_size = 0;
fseek( fp, 0, SEEK_END );
file_size = ftell( fp );
rewind( fp );
char *ptr = ( char* )malloc(file_size + 1);
if(ptr == NULL)
{
_RGLCgRaiseError( CG_MEMORY_ALLOC_ERROR );
return ( CGprogramGroup )NULL;
}
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;
int programCount = elfBinary.shadertabSize / sizeof( CgProgramHeader );
int i;
size_t nvProgramNamesOffset = _RGLPad( sizeof( _CGprogramGroup ), sizeof( _CGnamedProgram ) );
size_t nvDefaultValuesTableOffset = _RGLPad( nvProgramNamesOffset + programCount * sizeof( _CGnamedProgram ), 16 );
size_t nvStringTableOffset = nvDefaultValuesTableOffset + elfConstTableSize;
size_t structureSize = nvStringTableOffset + elfStringTableSize;
group = ( CGprogramGroup )malloc( structureSize );
if ( !group )
break;
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 )
break;
strlcpy( group->name, name, sizeof(group->name));
}
else
group->name = NULL;
if ( elfConstTableSize )
memcpy(( char* )group + nvDefaultValuesTableOffset, elfBinary.consttab, elfConstTableSize );
if ( elfStringTableSize )
memcpy(( char* )group + nvStringTableOffset, elfBinary.strtab, elfStringTableSize );
_RGLCgAddGroup( ctx, group );
for ( i = 0;i < ( int )group->programCount;i++ )
{
CgProgramHeader *cgShader = ( CgProgramHeader* )elfBinary.shadertab + i;
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;
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++ )
{
_CGprogram *cgProgram = _cgGetProgPtr( group->programs[i].program );
cgProgram->programGroup = NULL;
cgDestroyProgram( _group->programs[i].program );
}
if(_group->filedata != NULL)
free( _group->filedata );
if ( _group->name )
free( _group->name );
_RGLCgRemoveGroup( group->ctx, group );
if(_group != NULL)
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;
}
CGprogram _RGLCgGetProgramAtIndex( CGprogramGroup group, unsigned int index )
{
return _RGLCgUpdateProgramAtIndex( group, index, 0 );
}
int _RGLCgGetProgramCount( CGprogramGroup group )
{
return group->programCount;
}
static const RGLcgProfileMapType RGLcgProfileMap[] =
{
{( CGprofile )6144, "CG_PROFILE_START", 1 },
{( CGprofile )6145, "unknown", 1 },
#define CG_PROFILE_MACRO(name, compiler_id, compiler_id_caps, compiler_opt,int_id,vertex_profile) \
{CG_PROFILE_ ## compiler_id_caps, compiler_opt, vertex_profile},
#include <Cg/cg_profiles.h>
{( CGprofile )0, "", 0 }
};
CG_API const char* cgGetProfileString( CGprofile profile )
{
const size_t arraysize = sizeof( RGLcgProfileMap ) / sizeof( RGLcgProfileMapType );
unsigned int i = 0;
while ( i < arraysize )
{
if ( profile == RGLcgProfileMap[i].id )
{
return RGLcgProfileMap[i].string;
}
++i;
}
return "";
}
CG_API CGerror cgGetError(void)
{
CGerror err = _CurrentContext->RGLcgLastError;
_CurrentContext->RGLcgLastError = CG_NO_ERROR;
return err;
}
CG_API const char* cgGetErrorString( CGerror error )
{
static char strbuf[256];
snprintf(strbuf, sizeof(strbuf), "%d", error);
return strbuf;
}
void _RGLCgDestroyContextParam( CgRuntimeParameter* ptr )
{
if ( _cgParameterDestroyHook ) _cgParameterDestroyHook( ptr );
_RGLEraseName( &_CurrentContext->cgParameterNameSpace, ( jsName )( 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 == NULL )
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;
bool bWasUnrolled = false;
const char *prevStructureStart = structureStart;
while (( !done ) && ( *structureStart ) && ( containerCount != -1 ) )
{
structureEnd = strpbrk( structureStart, ".[" );
if ( structureEnd == NULL )
{
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;
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 )
{
int skipCount = 1;
while ( skipCount && currentEntry < lastEntry )
{
if ( currentEntry->flags & CGP_STRUCTURE )
{
const CgParameterStructure *parameterStructure = _RGLGetParameterStructure( program, currentEntry );
skipCount += parameterStructure->memberCount;
}
else if ( currentEntry->flags & CGP_ARRAY )
{
if ( currentEntry->flags & CGP_UNROLLED )
{
const CgParameterArray *parameterArray = _RGLGetParameterArray( program, currentEntry );
skipCount += _RGLGetSizeofSubArray(( short* )parameterArray->dimensions, parameterArray->dimensionCount );
}
else
skipCount++;
}
currentEntry++;
skipCount--;
}
}
if ( containerCount != -2 )
containerCount--;
}
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' )
{
itemIndex = ( int )( currentEntry - program->parametersEntries );
break;
}
currentEntry++;
if ( currentEntry->flags &CGP_STRUCTURE )
{
bWasUnrolled = true;
containerCount = _RGLGetSizeofSubArray(( short* )parameterArray->dimensions, parameterArray->dimensionCount );
break;
}
else
{
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 )
{
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 )
{
( *arrayIndex ) = arrayCellIndex;
itemIndex = ( int )( currentEntry - program->parametersEntries );
}
}
}
break;
case CGP_STRUCTURE:
if ( done )
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;
}
if ( itemIndex != -1 )
return ( _CGparameter* )( program->runtimeParameters + itemIndex );
else
return NULL;
}
CG_API CGparameter cgGetNamedParameter( CGprogram prog, const char* name )
{
if ( !CG_IS_PROGRAM( prog ) )
{
_RGLCgRaiseError( CG_INVALID_PROGRAM_HANDLE_ERROR );
return ( CGparameter )NULL;
}
_CGprogram* progPtr = _cgGetProgPtr( prog );
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;
}
static CGbool _RGLPlatformSupportsVertexProgram( CGprofile p )
{
if ( p == CG_PROFILE_SCE_VP_TYPEB )
return CG_TRUE;
if ( p == CG_PROFILE_SCE_VP_TYPEC )
return CG_TRUE;
if ( p == CG_PROFILE_SCE_VP_RSX )
return CG_TRUE;
return CG_FALSE;
}
CGGL_API CGbool cgGLIsProfileSupported( CGprofile profile )
{
if ( profile == ( CGprofile )7005 )
profile = CG_PROFILE_SCE_VP_RSX;
if ( profile == ( CGprofile )7006 )
profile = CG_PROFILE_SCE_FP_RSX;
switch ( profile )
{
case CG_PROFILE_SCE_VP_TYPEB:
case CG_PROFILE_SCE_VP_RSX:
return ( CGbool ) _RGLPlatformSupportsVertexProgram( profile );
case CG_PROFILE_SCE_FP_TYPEB:
case CG_PROFILE_SCE_FP_RSX:
return ( CGbool ) _RGLPlatformSupportsFragmentProgram( profile );
default:
return CG_FALSE;
}
}
CGGL_API void cgGLEnableProfile( CGprofile profile )
{
if ( profile == ( CGprofile )7005 )
profile = CG_PROFILE_SCE_VP_RSX;
if ( profile == ( CGprofile )7006 )
profile = CG_PROFILE_SCE_FP_RSX;
PSGLcontext* LContext = _CurrentContext;
struct _CGprogram* current = LContext->BoundFragmentProgram;
switch ( profile )
{
case CG_PROFILE_SCE_VP_TYPEB:
case CG_PROFILE_SCE_VP_RSX:
LContext->VertexProgram = GL_TRUE;
LContext->needValidate |= PSGL_VALIDATE_VERTEX_PROGRAM | PSGL_VALIDATE_VERTEX_TEXTURES_USED;
break;
case CG_PROFILE_SCE_FP_TYPEB:
case CG_PROFILE_SCE_FP_RSX:
LContext->FragmentProgram = GL_TRUE;
if ( current )
{
for (GLuint i = 0; i < current->samplerCount; ++i)
{
int unit = current->samplerUnits[i];
_CurrentContext->TextureImageUnits[unit].currentTexture = _RGLGetCurrentTexture( &_CurrentContext->TextureImageUnits[unit], GL_TEXTURE_2D );
}
}
LContext->needValidate |= PSGL_VALIDATE_FRAGMENT_PROGRAM | PSGL_VALIDATE_TEXTURES_USED;
break;
default:
_RGLCgRaiseError( CG_INVALID_PROFILE_ERROR );
break;
}
}
CGGL_API void cgGLDisableProfile( CGprofile profile )
{
if ( profile == ( CGprofile )7005 )
profile = CG_PROFILE_SCE_VP_RSX;
if ( profile == ( CGprofile )7006 )
profile = CG_PROFILE_SCE_FP_RSX;
PSGLcontext* LContext = _CurrentContext;
switch ( profile )
{
case CG_PROFILE_SCE_VP_TYPEB:
case CG_PROFILE_SCE_VP_RSX:
LContext->VertexProgram = GL_FALSE;
LContext->needValidate |= PSGL_VALIDATE_VERTEX_PROGRAM ;
break;
case CG_PROFILE_SCE_FP_TYPEB:
case CG_PROFILE_SCE_FP_RSX:
LContext->FragmentProgram = GL_FALSE;
for (GLuint unit = 0; unit < MAX_TEXTURE_UNITS; ++unit)
LContext->TextureImageUnits[unit].currentTexture = _RGLGetCurrentTexture( &LContext->TextureImageUnits[unit], GL_TEXTURE_2D );
LContext->needValidate |= PSGL_VALIDATE_FFX_FRAGMENT_PROGRAM | PSGL_VALIDATE_TEXTURES_USED;
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 _RGLPlatformGetLatestProfile( profile_type );
default:
_RGLCgRaiseError( CG_INVALID_ENUMERANT_ERROR );
return CG_PROFILE_UNKNOWN;
}
}
CGGL_API void cgGLSetOptimalOptions( CGprofile profile )
{
}
CGGL_API void cgGLLoadProgram( CGprogram program )
{
}
CGGL_API void cgGLBindProgram( CGprogram program )
{
_CGprogram* ptr = _cgGetProgPtr( program );
switch ( ptr->header.profile )
{
case CG_PROFILE_SCE_VP_TYPEB:
case 7005:
case CG_PROFILE_SCE_VP_RSX:
_CurrentContext->BoundVertexProgram = ptr;
_CurrentContext->needValidate |= PSGL_VALIDATE_VERTEX_PROGRAM | PSGL_VALIDATE_VERTEX_TEXTURES_USED;
break;
case CG_PROFILE_SCE_FP_TYPEB:
case 7006:
case CG_PROFILE_SCE_FP_RSX:
_CurrentContext->BoundFragmentProgram = ptr;
_CurrentContext->needValidate |= PSGL_VALIDATE_FRAGMENT_PROGRAM | PSGL_VALIDATE_TEXTURES_USED;
for ( GLuint index = 0; index < ptr->samplerCount; ++index )
{
CgRuntimeParameter *rtParameter = ptr->runtimeParameters + ptr->samplerIndices[index];
CgParameterResource *parameter = ( CgParameterResource * )( ptr->parameterResources + rtParameter->parameterEntry->typeIndex );
unsigned int unit = parameter->resource - CG_TEXUNIT0;
_CurrentContext->TextureImageUnits[unit].fragmentTarget = rtParameter->glType;
_CurrentContext->TextureImageUnits[unit].currentTexture = _RGLGetCurrentTexture( &_CurrentContext->TextureImageUnits[unit], GL_TEXTURE_2D );
}
break;
default:
_RGLCgRaiseError( CG_INVALID_PROFILE_ERROR );
return;
}
}
CGGL_API void cgGLUnbindProgram( CGprofile profile )
{
switch ( profile )
{
case CG_PROFILE_SCE_VP_TYPEB:
case CG_PROFILE_SCE_VP_RSX:
case 7005:
_CurrentContext->BoundVertexProgram = NULL;
_CurrentContext->needValidate |= PSGL_VALIDATE_VERTEX_PROGRAM;
break;
case CG_PROFILE_SCE_FP_TYPEB:
case CG_PROFILE_SCE_FP_RSX:
case 7006:
_CurrentContext->BoundFragmentProgram = NULL;
for (GLuint unit = 0; unit < MAX_TEXTURE_UNITS; ++unit)
_CurrentContext->TextureImageUnits[unit].currentTexture = _RGLGetCurrentTexture( &_CurrentContext->TextureImageUnits[unit], GL_TEXTURE_2D );
_CurrentContext->needValidate |= PSGL_VALIDATE_FFX_FRAGMENT_PROGRAM | PSGL_VALIDATE_TEXTURES_USED;
break;
default:
_RGLCgRaiseError( CG_INVALID_PROFILE_ERROR );
return;
}
}
CGGL_API void cgGLSetParameter1f( CGparameter param, float x )
{
CgRuntimeParameter *ptr = _cgGetParamPtr( param );
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 = _cgGetParamPtr( param );
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 = _cgGetParamPtr( param );
const CgParameterResource *parameterResource = _RGLGetParameterResource( _ptr->program, _ptr->parameterEntry );
GLuint index = ( GLuint )( parameterResource->resource - CG_ATTR0 );
_RGLVertexAttribPointerNV(
index,
fsize,
type,
( _ptr->parameterEntry->flags & CGP_NORMALIZE ) ? 1 : 0,
stride,
pointer );
}
CGGL_API void cgGLEnableClientState( CGparameter param )
{
CgRuntimeParameter *_ptr = _cgGetParamPtr( 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 = _cgGetParamPtr( param );
const CgParameterResource *parameterResource = _RGLGetParameterResource( _ptr->program, _ptr->parameterEntry );
GLuint index = ( GLuint )( parameterResource->resource - CG_ATTR0 );
_RGLDisableVertexAttribArrayNV( index );
}
CGGL_API void cgGLSetTextureParameter( CGparameter param, GLuint texobj )
{
CgRuntimeParameter* ptr = _cgGetParamPtr(param);
ptr->samplerSetter( ptr, &texobj, 0 );
}
CGGL_API void cgGLEnableTextureParameter( CGparameter param )
{
CgRuntimeParameter* ptr = _cgGetParamPtr(param);
ptr->samplerSetter( ptr, NULL, 0 );
}
static void _RGLCgContextPushFront(_CGcontext* ctx)
{
if(_CurrentContext->RGLcgContextHead)
{
_CGcontext* head = _cgGetContextPtr( _CurrentContext->RGLcgContextHead );
ctx->next = head;
}
_CurrentContext->RGLcgContextHead = ctx->id;
}
static void destroy_context(_CGcontext*ctx)
{
if (_cgContextDestroyHook)
_cgContextDestroyHook(ctx);
_RGLEraseName( &_CurrentContext->cgContextNameSpace, ( jsName )ctx->id );
memset(ctx, 0, sizeof( *ctx ) );
ctx->compileType = CG_UNKNOWN;
free( ctx );
}
CG_API CGcontext cgCreateContext(void)
{
_CGcontext* ptr = NULL;
ptr = ( _CGcontext* )malloc( sizeof( _CGcontext ) );
if ( ptr == NULL )
{
_RGLCgRaiseError( CG_MEMORY_ALLOC_ERROR );
return ( CGcontext )NULL;
}
memset( ptr, 0, sizeof( *ptr ) );
ptr->compileType = CG_UNKNOWN;
CGcontext result = ( CGcontext )_RGLCreateName( &_CurrentContext->cgContextNameSpace, ptr );
if ( !result )
{
free( ptr );
return NULL;
}
ptr->id = result;
ptr->defaultProgram.parentContext = ptr;
_RGLCgContextPushFront( ptr );
if ( _cgContextCreateHook ) _cgContextCreateHook( ptr );
return result;
}
CG_API void cgDestroyContext(CGcontext c)
{
if(!CG_IS_CONTEXT(c))
{
_RGLCgRaiseError( CG_INVALID_CONTEXT_HANDLE_ERROR );
return;
}
_CGcontext* ctx = _cgGetContextPtr( c );
_RGLCgProgramErase( &ctx->defaultProgram );
while ( ctx->programList )
{
_CGprogram * p = ctx->programList;
ctx->programList = p->next;
_RGLCgProgramErase( p );
if(p != NULL)
free( p );
}
_CGcontext * const head = _cgGetContextPtr( _CurrentContext->RGLcgContextHead );
if ( head != ctx )
{
_CGcontext* ptr = head;
while ( ptr->next != ctx ) ptr = ptr->next;
ptr->next = ctx->next;
destroy_context( ctx );
}
else
{
_CGcontext* second = head->next;
destroy_context( head );
if ( second )
_CurrentContext->RGLcgContextHead = second->id;
else
_CurrentContext->RGLcgContextHead = 0;
}
}
CG_API const char* cgGetLastListing( CGcontext c )
{
if ( !CG_IS_CONTEXT( c ) )
{
_RGLCgRaiseError( CG_INVALID_CONTEXT_HANDLE_ERROR );
return NULL;
}
return NULL;
}
void _RGLCgRaiseError( CGerror error )
{
_CurrentContext->RGLcgLastError = error;
if(!context_shutdown)
{
RARCH_ERR("Cg error: %d.\n", 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:
size = 1;
break;
case CG_FLOAT2:
case CG_FLOAT2x1:
case CG_FLOAT1x2:
size = 2;
break;
case CG_FLOAT3:
case CG_FLOAT3x1:
case CG_FLOAT1x3:
size = 3;
break;
case CG_FLOAT4:
case CG_FLOAT4x1:
case CG_FLOAT1x4:
case CG_FLOAT2x2:
size = 4;
break;
case CG_FLOAT2x3:
case CG_FLOAT3x2:
size = 6;
break;
case CG_FLOAT2x4:
case CG_FLOAT4x2:
size = 8;
break;
case CG_FLOAT3x3:
size = 9;
break;
case CG_FLOAT3x4:
case CG_FLOAT4x3:
size = 12;
break;
case CG_FLOAT4x4:
size = 16;
break;
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:
size = 1;
break;
case CG_HALF2:
case CG_HALF2x1:
case CG_HALF1x2:
size = 2;
break;
case CG_HALF3:
case CG_HALF3x1:
case CG_HALF1x3:
size = 3;
break;
case CG_HALF4:
case CG_HALF4x1:
case CG_HALF1x4:
case CG_HALF2x2:
size = 4;
break;
case CG_HALF2x3:
case CG_HALF3x2:
size = 6;
break;
case CG_HALF2x4:
case CG_HALF4x2:
size = 8;
break;
case CG_HALF3x3:
size = 9;
break;
case CG_HALF3x4:
case CG_HALF4x3:
size = 12;
break;
case CG_HALF4x4:
size = 16;
break;
case CG_INT:
case CG_INT1:
case CG_INT1x1:
size = 1;
break;
case CG_INT2:
case CG_INT2x1:
case CG_INT1x2:
size = 2;
break;
case CG_INT3:
case CG_INT3x1:
case CG_INT1x3:
size = 3;
break;
case CG_INT4:
case CG_INT4x1:
case CG_INT1x4:
case CG_INT2x2:
size = 4;
break;
case CG_INT2x3:
case CG_INT3x2:
size = 6;
break;
case CG_INT2x4:
case CG_INT4x2:
size = 8;
break;
case CG_INT3x3:
size = 9;
break;
case CG_INT3x4:
case CG_INT4x3:
size = 12;
break;
case CG_INT4x4:
size = 16;
break;
case CG_BOOL1:
case CG_BOOL1x1:
size = 1;
break;
case CG_BOOL2:
case CG_BOOL2x1:
case CG_BOOL1x2:
size = 2;
break;
case CG_BOOL3:
case CG_BOOL3x1:
case CG_BOOL1x3:
size = 3;
break;
case CG_BOOL4:
case CG_BOOL4x1:
case CG_BOOL1x4:
case CG_BOOL2x2:
size = 4;
break;
case CG_BOOL2x3:
case CG_BOOL3x2:
size = 6;
break;
case CG_BOOL2x4:
case CG_BOOL4x2:
size = 8;
break;
case CG_BOOL3x3:
size = 9;
break;
case CG_BOOL3x4:
case CG_BOOL4x3:
size = 12;
break;
case CG_BOOL4x4:
size = 16;
break;
case CG_FIXED:
case CG_FIXED1:
case CG_FIXED1x1:
size = 1;
break;
case CG_FIXED2:
case CG_FIXED2x1:
case CG_FIXED1x2:
size = 2;
break;
case CG_FIXED3:
case CG_FIXED3x1:
case CG_FIXED1x3:
size = 3;
break;
case CG_FIXED4:
case CG_FIXED4x1:
case CG_FIXED1x4:
case CG_FIXED2x2:
size = 4;
break;
case CG_FIXED2x3:
case CG_FIXED3x2:
size = 6;
break;
case CG_FIXED2x4:
case CG_FIXED4x2:
size = 8;
break;
case CG_FIXED3x3:
size = 9;
break;
case CG_FIXED3x4:
case CG_FIXED4x3:
size = 12;
break;
case CG_FIXED4x4:
size = 16;
break;
default:
size = 0;
break;
}
return size;
}
void _cgRaiseInvalidParam( CgRuntimeParameter*p, const void*v )
{
_RGLCgRaiseError( CG_INVALID_PARAMETER_ERROR );
}
void _cgRaiseInvalidParamIndex( CgRuntimeParameter*p, const void*v, const int index )
{
_RGLCgRaiseError( CG_INVALID_PARAMETER_ERROR );
}
void _cgRaiseNotMatrixParam( CgRuntimeParameter*p, const void*v )
{
_RGLCgRaiseError( CG_NOT_MATRIX_PARAM_ERROR );
}
void _cgRaiseNotMatrixParamIndex( CgRuntimeParameter*p, const void*v, const int index )
{
_RGLCgRaiseError( CG_NOT_MATRIX_PARAM_ERROR );
}
void _cgIgnoreSetParam( CgRuntimeParameter*p, const void*v ) {}
void _cgIgnoreSetParamIndex( CgRuntimeParameter*p, const void*v, const int index ) {}
#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];
}
CGGL_API void cgGLSetMatrixParameterfc( CGparameter param, const float *matrix )
{
CgRuntimeParameter* ptr = _cgGetParamPtr( param );
ptr->settercIndex( ptr, matrix, CG_GETINDEX( param ) );
}