Beispiel #1
0
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
}
Beispiel #10
0
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);
}