#include #include #include #include #include #include #include #include "rgl.h" #include "private.h" #include #include "cg.h" #include #include #include "readelf.h" #include "cgnv2rt.h" #include #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; ish_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 inline void _RGLFifoGlVertexAttribPointer ( GLuint index, GLint size, RGLEnum type, GLboolean normalized, GLsizei stride, GLushort frequency, GLuint offset ) { switch(size) { case 0: stride = 0; normalized = 0; type = RGL_FLOAT; offset = 0; break; case 1: case 2: case 3: case 4: break; default: break; } uint8_t gcmType = 0; switch ( type ) { case RGL_UNSIGNED_BYTE: if (normalized) gcmType = CELL_GCM_VERTEX_UB; else gcmType = CELL_GCM_VERTEX_UB256; break; case RGL_SHORT: gcmType = 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: size = 1; gcmType = CELL_GCM_VERTEX_CMP; break; default: break; } cellGcmSetVertexDataArrayInline( &_RGLState.fifo, index, frequency, stride, size, gcmType, CELL_GCM_LOCATION_LOCAL, offset ); } 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(); new( &buffer->attribSets ) RGL::Vector(); 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(); buffer->attribSets.~Vector(); 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: cellGcmSetInvalidateVertexCacheInline( &_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: cellGcmSetInvalidateVertexCacheInline( &_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;iR = 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 ); cellGcmSetInvalidateVertexCacheInline( &_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((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; _RGLFifoGlVertexAttribPointer( 0, 3, RGL_FLOAT, CELL_GCM_FALSE, 3*sizeof( GLfloat ), 1, gmmAddressToOffset(pBaseBlock->address, pBaseBlock->isMain)); RGLBIT_TRUE( LContext->attribs->DirtyMask, 0 ); for(int i = 1; i < MAX_VERTEX_ATTRIBS; ++i) { _RGLFifoGlVertexAttribPointer( i, 0, RGL_FLOAT, 0, 0, 0, 0 ); 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 ); } cellGcmSetInvalidateVertexCacheInline( &_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; jppFreeBlockList[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; ipBlocksUsed[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; ippFreeBlockList[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; iBlockListCount[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; ipFreeHead[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 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 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(program->header.instructionCount*16, program->loadProgramId, program->loadProgramOffset, ec, (unsigned int *)data); } } template static void setVectorTypeSharedfpIndex( CgRuntimeParameter* __restrict ptr, const void* __restrict v, const int ) {} template static void setVectorTypeSharedfpIndexArray( CgRuntimeParameter* __restrict ptr, const void* __restrict v, const int index ) {} template 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 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 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 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 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( program->header.instructionCount*16, program->loadProgramId, program->loadProgramOffset, ec, ( unsigned int * )data ); } } template 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( program->header.instructionCount*16, program->loadProgramId, program->loadProgramOffset, ec, ( unsigned int * )data ); } } template 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 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 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 static void setMatrixSharedfpIndex( CgRuntimeParameter* __restrict ptr, const void* __restrict v, const int /*index*/ ) { } template static void setMatrixSharedfpIndexArray( CgRuntimeParameter* __restrict ptr, const void* __restrict v, const int index ) { } template 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 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( program->header.instructionCount*16, program->loadProgramId, program->loadProgramOffset, ec, ( unsigned int * )dst + row * 4 ); } ec += count + 2; } } template 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( 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, ¶meterHeader, 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 { cellGcmSetInvalidateVertexCacheInline( &_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 ); } #include 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] = CELL_GCM_METHOD_DATA_TEXTURE_BORDER_COLOR(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 = ¤t[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(); 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(); 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 ) { cellGcmSetInvalidateVertexCacheInline( &_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(); cellGcmSetInvalidateVertexCacheInline( &_RGLState.fifo); _RGLFifoFlush( fifo ); } GLAPI void APIENTRY glFinish(void) { glFlush(); cellGcmSetInvalidateVertexCacheInline( &_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(); cellGcmSetInvalidateVertexCacheInline ( &_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 ) ) { const 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 ); } _RGLFifoGlVertexAttribPointer( i, attrib->clientSize, ( RGLEnum )attrib->clientType, attrib->normalized, stride, freq, gpuOffset ); } else { _RGLFifoGlVertexAttribPointer( i, 0, RGL_FLOAT, 0, 0, 0, 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; cellGcmSetInvalidateVertexCacheInline ( &_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, ¶mtabSize ); if ( !paramtab ) break; elfProgram->texttab = texttab; elfProgram->texttabSize = texttabSize; elfProgram->paramtab = paramtab; elfProgram->paramtabSize = paramtabSize; elfProgram->index = index; return true; } return false; } static bool cgGetElfProgramByName( CGELFBinary *elfBinary, const char *name, CGELFProgram *elfProgram ) { //if no name try to return the first program int 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 stringTableArray; std::vector 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 {( 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 ) ); }