DECLEXPORT(GLuint) STATE_APIENTRY crStateCreateProgram(GLuint hwid) { CRGLSLProgram *pProgram; CRContext *g = GetCurrentContext(); GLuint stateId = hwid; #ifdef IN_GUEST pProgram = crStateGetProgramObj(stateId); if (pProgram) { crWarning("Program object %d already exists!", stateId); crStateDeleteProgram(stateId); CRASSERT(!crStateGetProgramObj(stateId)); } #else /* the id may not necesserily be hwid after save state restoration */ while ((pProgram = crStateGetProgramObj(stateId)) != NULL) { GLuint newStateId = stateId + 7; crDebug("Program object %d already exists, generating a new one, %d", stateId, newStateId); stateId = newStateId; } #endif pProgram = (CRGLSLProgram *) crAlloc(sizeof(*pProgram)); if (!pProgram) { crWarning("crStateCreateShader: Out of memory!"); return 0; } pProgram->id = stateId; pProgram->hwid = hwid; pProgram->validated = GL_FALSE; pProgram->linked = GL_FALSE; pProgram->deleted = GL_FALSE; pProgram->activeState.attachedShaders = NULL; pProgram->currentState.attachedShaders = crAllocHashtable(); pProgram->activeState.cAttribs = 0; pProgram->activeState.pAttribs = NULL; pProgram->currentState.cAttribs = 0; pProgram->currentState.pAttribs = NULL; pProgram->pUniforms = NULL; pProgram->cUniforms = 0; #ifdef IN_GUEST pProgram->bUniformsSynced = GL_FALSE; #endif crHashtableAdd(g->glsl.programs, stateId, pProgram); return stateId; }
DECLEXPORT(GLuint) STATE_APIENTRY crStateCreateProgram(GLuint hwid) { CRGLSLProgram *pProgram; CRContext *g = GetCurrentContext(); GLuint stateId = hwid; #ifdef IN_GUEST pProgram = crStateGetProgramObj(stateId); if (pProgram) { crWarning("Program object %d already exists!", stateId); crStateDeleteProgram(stateId); CRASSERT(!crStateGetProgramObj(stateId)); } #else stateId = crHashtableAllocKeys(g->glsl.programs, 1); if (!stateId) { crWarning("failed to allocate program key"); return 0; } #endif pProgram = (CRGLSLProgram *) crAlloc(sizeof(*pProgram)); if (!pProgram) { crWarning("crStateCreateProgram: Out of memory!"); return 0; } pProgram->id = stateId; pProgram->hwid = hwid; pProgram->validated = GL_FALSE; pProgram->linked = GL_FALSE; pProgram->deleted = GL_FALSE; pProgram->activeState.attachedShaders = NULL; pProgram->currentState.attachedShaders = crAllocHashtable(); pProgram->activeState.cAttribs = 0; pProgram->activeState.pAttribs = NULL; pProgram->currentState.cAttribs = 0; pProgram->currentState.pAttribs = NULL; pProgram->pUniforms = NULL; pProgram->cUniforms = 0; #ifdef IN_GUEST pProgram->bUniformsSynced = GL_FALSE; #endif crHashtableAdd(g->glsl.programs, stateId, pProgram); return stateId; }
DECLEXPORT(GLint) STATE_APIENTRY crStateGetUniformLocation(GLuint program, const char * name) { #ifdef IN_GUEST CRGLSLProgram *pProgram = crStateGetProgramObj(program); GLint result=-1; GLuint i; if (!pProgram) { crWarning("Unknown program %d", program); return -1; } if (!pProgram->bUniformsSynced) { crWarning("crStateGetUniformLocation called for uncached uniforms"); return -1; } for (i=0; i<pProgram->cUniforms; ++i) { if (!crStrcmp(name, pProgram->pUniforms[i].name)) { result = pProgram->pUniforms[i].location; break; } } return result; #else crWarning("crStateGetUniformLocation called on host side!!"); return -1; #endif }
DECLEXPORT(void) STATE_APIENTRY crStateDetachShader(GLuint program, GLuint shader) { CRGLSLProgram *pProgram = crStateGetProgramObj(program); CRGLSLShader *pShader; if (!pProgram) { crWarning("Unknown program %d", program); return; } pShader = (CRGLSLShader *) crHashtableSearch(pProgram->currentState.attachedShaders, shader); if (!pShader) { crWarning("Shader %d isn't attached to program %d", shader, program); return; } crHashtableDelete(pProgram->currentState.attachedShaders, shader, NULL); CRASSERT(pShader->refCount>0); pShader->refCount--; if (0==pShader->refCount) { CRContext *g = GetCurrentContext(); crHashtableDelete(g->glsl.shaders, shader, crStateFreeGLSLShader); } }
DECLEXPORT(void) STATE_APIENTRY crStateAttachShader(GLuint program, GLuint shader) { CRGLSLProgram *pProgram = crStateGetProgramObj(program); CRGLSLShader *pShader; if (!pProgram) { crWarning("Unknown program %d", program); return; } if (crHashtableSearch(pProgram->currentState.attachedShaders, shader)) { /*shader already attached to this program*/ return; } pShader = crStateGetShaderObj(shader); if (!pShader) { crWarning("Unknown shader %d", shader); return; } pShader->refCount++; crHashtableAdd(pProgram->currentState.attachedShaders, shader, pShader); }
DECLEXPORT(GLuint) STATE_APIENTRY crStateGetProgramHWID(GLuint id) { CRGLSLProgram *pProgram = crStateGetProgramObj(id); #ifdef IN_GUEST CRASSERT(!pProgram || pProgram->hwid == id); #endif return pProgram ? pProgram->hwid : 0; }
DECLEXPORT(void) STATE_APIENTRY crStateValidateProgram(GLuint program) { CRGLSLProgram *pProgram = crStateGetProgramObj(program); if (!pProgram) { crWarning("Unknown program %d", program); return; } pProgram->validated = GL_TRUE; }
DECLEXPORT(void) STATE_APIENTRY crStateLinkProgram(GLuint program) { CRGLSLProgram *pProgram = crStateGetProgramObj(program); GLuint i; if (!pProgram) { crWarning("Unknown program %d", program); return; } pProgram->linked = GL_TRUE; /*Free program's active state*/ if (pProgram->activeState.attachedShaders) { crHashtableWalk(pProgram->activeState.attachedShaders, crStateFakeDecRefCountCB, NULL); crFreeHashtable(pProgram->activeState.attachedShaders, crStateFreeGLSLShader); pProgram->activeState.attachedShaders = NULL; } for (i=0; i<pProgram->activeState.cAttribs; ++i) { crFree(pProgram->activeState.pAttribs[i].name); } if (pProgram->activeState.pAttribs) crFree(pProgram->activeState.pAttribs); /*copy current state to active state*/ crMemcpy(&pProgram->activeState, &pProgram->currentState, sizeof(CRGLSLProgramState)); pProgram->activeState.attachedShaders = crAllocHashtable(); if (!pProgram->activeState.attachedShaders) { crWarning("crStateLinkProgram: Out of memory!"); return; } crHashtableWalk(pProgram->currentState.attachedShaders, crStateCopyShaderCB, pProgram); /*that's not a bug, note the memcpy above*/ if (pProgram->activeState.pAttribs) { pProgram->activeState.pAttribs = (CRGLSLAttrib *) crAlloc(pProgram->activeState.cAttribs * sizeof(CRGLSLAttrib)); } for (i=0; i<pProgram->activeState.cAttribs; ++i) { crMemcpy(&pProgram->activeState.pAttribs[i], &pProgram->currentState.pAttribs[i], sizeof(CRGLSLAttrib)); pProgram->activeState.pAttribs[i].name = crStrdup(pProgram->currentState.pAttribs[i].name); } crStateFreeProgramUniforms(pProgram); }
DECLEXPORT(GLboolean) STATE_APIENTRY crStateIsProgramUniformsCached(GLuint program) { CRGLSLProgram *pProgram = crStateGetProgramObj(program); if (!pProgram) { crWarning("Unknown program %d", program); return GL_FALSE; } #ifdef IN_GUEST return pProgram->bUniformsSynced; #else crWarning("crStateIsProgramUniformsCached called on host side!!"); return GL_FALSE; #endif }
DECLEXPORT(void) STATE_APIENTRY crStateBindAttribLocation(GLuint program, GLuint index, const char * name) { CRGLSLProgram *pProgram = crStateGetProgramObj(program); GLuint i; CRGLSLAttrib *pAttribs; if (!pProgram) { crWarning("Unknown program %d", program); return; } if (index>=CR_MAX_VERTEX_ATTRIBS) { crWarning("crStateBindAttribLocation: Index too big %d", index); return; } for (i=0; i<pProgram->currentState.cAttribs; ++i) { if (!crStrcmp(pProgram->currentState.pAttribs[i].name, name)) { crFree(pProgram->currentState.pAttribs[i].name); pProgram->currentState.pAttribs[i].name = crStrdup(name); return; } } pAttribs = (CRGLSLAttrib*) crAlloc((pProgram->currentState.cAttribs+1)*sizeof(CRGLSLAttrib)); if (!pAttribs) { crWarning("crStateBindAttribLocation: Out of memory!"); return; } if (pProgram->currentState.cAttribs) { crMemcpy(&pAttribs[0], &pProgram->currentState.pAttribs[0], pProgram->currentState.cAttribs*sizeof(CRGLSLAttrib)); } pAttribs[pProgram->currentState.cAttribs].index = index; pAttribs[pProgram->currentState.cAttribs].name = crStrdup(name); pProgram->currentState.cAttribs++; if (pProgram->currentState.pAttribs) crFree(pProgram->currentState.pAttribs); pProgram->currentState.pAttribs = pAttribs; }
DECLEXPORT(void) STATE_APIENTRY crStateDeleteProgram(GLuint program) { CRContext *g = GetCurrentContext(); CRGLSLProgram *pProgram = crStateGetProgramObj(program); if (!pProgram) { crWarning("Unknown program %d", program); return; } if (g->glsl.activeProgram == pProgram) { g->glsl.activeProgram = NULL; } crHashtableDelete(g->glsl.programs, program, crStateFreeGLSLProgram); }
DECLEXPORT(void) STATE_APIENTRY crStateUseProgram(GLuint program) { CRContext *g = GetCurrentContext(); if (program>0) { CRGLSLProgram *pProgram = crStateGetProgramObj(program); if (!pProgram) { crWarning("Unknown program %d", program); return; } g->glsl.activeProgram = pProgram; } else { g->glsl.activeProgram = NULL; } }
DECLEXPORT(void) STATE_APIENTRY crStateGLSLProgramCacheUniforms(GLuint program, GLsizei maxcbData, GLsizei *cbData, GLvoid *pData) { CRGLSLProgram *pProgram = crStateGetProgramObj(program); GLint maxUniformLen, activeUniforms=0, fakeUniformsCount, i, j; char *pCurrent = pData; GLsizei cbWritten; if (!pProgram) { crWarning("Unknown program %d", program); return; } diff_api.GetProgramiv(pProgram->hwid, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxUniformLen); diff_api.GetProgramiv(pProgram->hwid, GL_ACTIVE_UNIFORMS, &activeUniforms); *cbData = 0; cbWritten = sizeof(GLsizei); if (cbWritten>maxcbData) { crWarning("crStateGLSLProgramCacheUniforms: buffer too small"); return; } ((GLsizei*)pCurrent)[0] = activeUniforms; fakeUniformsCount = activeUniforms; pCurrent += sizeof(GLsizei); crDebug("crStateGLSLProgramCacheUniforms: %i active uniforms", activeUniforms); if (activeUniforms>0) { /*+8 to make sure our array uniforms with higher indices and [] will fit in as well*/ GLchar *name = (GLchar *) crAlloc(maxUniformLen+8); GLenum type; GLint size; GLsizei cbName; GLint location; if (!name) { crWarning("crStateGLSLProgramCacheUniforms: no memory"); return; } for (i=0; i<activeUniforms; ++i) { diff_api.GetActiveUniform(pProgram->hwid, i, maxUniformLen, &cbName, &size, &type, name); location = diff_api.GetUniformLocation(pProgram->hwid, name); if (!crStateGLSLProgramCacheOneUniform(location, cbName, name, &pCurrent, &cbWritten, maxcbData)) return; /* Only one active uniform variable will be reported for a uniform array by glGetActiveUniform, * so we insert fake elements for other array elements. */ if (size!=1) { char *pIndexStr = crStrchr(name, '['); GLint firstIndex=1; fakeUniformsCount += size; crDebug("crStateGLSLProgramCacheUniforms: expanding array uniform, size=%i", size); /*For array uniforms it's valid to query location of 1st element as both uniform and uniform[0]. *The name returned by glGetActiveUniform is driver dependent, *atleast it's with [0] on win/ati and without [0] on linux/nvidia. */ if (!pIndexStr) { pIndexStr = name+cbName; firstIndex=0; } else { cbName = pIndexStr-name; if (!crStateGLSLProgramCacheOneUniform(location, cbName, name, &pCurrent, &cbWritten, maxcbData)) return; } for (j=firstIndex; j<size; ++j) { sprintf(pIndexStr, "[%i]", j); cbName = crStrlen(name); location = diff_api.GetUniformLocation(pProgram->hwid, name); if (!crStateGLSLProgramCacheOneUniform(location, cbName, name, &pCurrent, &cbWritten, maxcbData)) return; } } } crFree(name); } if (fakeUniformsCount!=activeUniforms) { ((GLsizei*)pData)[0] = fakeUniformsCount; crDebug("FakeCount %i", fakeUniformsCount); } *cbData = cbWritten; CRASSERT((pCurrent-((char*)pData))==cbWritten); }
DECLEXPORT(void) STATE_APIENTRY crStateGLSLProgramCacheUniforms(GLuint program, GLsizei cbData, GLvoid *pData) { CRGLSLProgram *pProgram = crStateGetProgramObj(program); char *pCurrent = pData; GLsizei cbRead, cbName; GLuint i; if (!pProgram) { crWarning("Unknown program %d", program); return; } if (pProgram->bUniformsSynced) { crWarning("crStateGLSLProgramCacheUniforms: this shouldn't happen!"); crStateFreeProgramUniforms(pProgram); } if (cbData<sizeof(GLsizei)) { crWarning("crStateGLSLProgramCacheUniforms: data too short"); return; } pProgram->cUniforms = ((GLsizei*)pCurrent)[0]; pCurrent += sizeof(GLsizei); cbRead = sizeof(GLsizei); crDebug("crStateGLSLProgramCacheUniforms: %i active uniforms", pProgram->cUniforms); if (pProgram->cUniforms) { pProgram->pUniforms = crAlloc(pProgram->cUniforms*sizeof(CRGLSLUniform)); if (!pProgram->pUniforms) { crWarning("crStateGLSLProgramCacheUniforms: no memory"); pProgram->cUniforms = 0; return; } } for (i=0; i<pProgram->cUniforms; ++i) { cbRead += sizeof(GLuint)+sizeof(GLsizei); if (cbRead>cbData) { crWarning("crStateGLSLProgramCacheUniforms: out of data reading uniform %i", i); return; } pProgram->pUniforms[i].data = NULL; pProgram->pUniforms[i].location = ((GLint*)pCurrent)[0]; pCurrent += sizeof(GLint); cbName = ((GLsizei*)pCurrent)[0]; pCurrent += sizeof(GLsizei); cbRead += cbName; if (cbRead>cbData) { crWarning("crStateGLSLProgramCacheUniforms: out of data reading uniform's name %i", i); return; } pProgram->pUniforms[i].name = crStrndup(pCurrent, cbName); pCurrent += cbName; crDebug("crStateGLSLProgramCacheUniforms: uniform[%i]=%d, %s", i, pProgram->pUniforms[i].location, pProgram->pUniforms[i].name); } pProgram->bUniformsSynced = GL_TRUE; CRASSERT((pCurrent-((char*)pData))==cbRead); CRASSERT(cbRead==cbData); }