diff options
Diffstat (limited to 'src/VBox/GuestHost/OpenGL/state_tracker')
28 files changed, 6072 insertions, 965 deletions
diff --git a/src/VBox/GuestHost/OpenGL/state_tracker/dump.cpp b/src/VBox/GuestHost/OpenGL/state_tracker/dump.cpp new file mode 100644 index 00000000..8132d9f9 --- /dev/null +++ b/src/VBox/GuestHost/OpenGL/state_tracker/dump.cpp @@ -0,0 +1,1741 @@ +/* $Id: dump.cpp $ */ + +/** @file + * Blitter API implementation + */ +/* + * Copyright (C) 2013 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ +#include "cr_blitter.h" +#include "cr_spu.h" +#include "chromium.h" +#include "cr_error.h" +#include "cr_net.h" +#include "cr_rand.h" +#include "cr_mem.h" +#include "cr_string.h" +#include <cr_dump.h> +#include "cr_pixeldata.h" + +#include <iprt/cdefs.h> +#include <iprt/types.h> +#include <iprt/mem.h> + +#include <stdio.h> + +#ifdef VBOX_WITH_CRDUMPER + +static uint32_t g_CrDbgDumpRecTexInfo = 1; +static uint32_t g_CrDbgDumpAlphaData = 1; + +/* dump stuff */ +#pragma pack(1) +typedef struct VBOX_BITMAPFILEHEADER { + uint16_t bfType; + uint32_t bfSize; + uint16_t bfReserved1; + uint16_t bfReserved2; + uint32_t bfOffBits; +} VBOX_BITMAPFILEHEADER; + +typedef struct VBOX_BITMAPINFOHEADER { + uint32_t biSize; + int32_t biWidth; + int32_t biHeight; + uint16_t biPlanes; + uint16_t biBitCount; + uint32_t biCompression; + uint32_t biSizeImage; + int32_t biXPelsPerMeter; + int32_t biYPelsPerMeter; + uint32_t biClrUsed; + uint32_t biClrImportant; +} VBOX_BITMAPINFOHEADER; +#pragma pack() + +void crDmpImgBmp(CR_BLITTER_IMG *pImg, const char *pszFilename) +{ + static int sIdx = 0; + + if ( pImg->bpp != 16 + && pImg->bpp != 24 + && pImg->bpp != 32) + { + crWarning("not supported bpp %d", pImg->bpp); + return; + } + + FILE *f = fopen (pszFilename, "wb"); + if (!f) + { + crWarning("fopen failed"); + return; + } + + VBOX_BITMAPFILEHEADER bf; + + bf.bfType = 'MB'; + bf.bfSize = sizeof (VBOX_BITMAPFILEHEADER) + sizeof (VBOX_BITMAPINFOHEADER) + pImg->cbData; + bf.bfReserved1 = 0; + bf.bfReserved2 = 0; + bf.bfOffBits = sizeof (VBOX_BITMAPFILEHEADER) + sizeof (VBOX_BITMAPINFOHEADER); + + VBOX_BITMAPINFOHEADER bi; + + bi.biSize = sizeof (bi); + bi.biWidth = pImg->width; + bi.biHeight = pImg->height; + bi.biPlanes = 1; + bi.biBitCount = pImg->bpp; + bi.biCompression = 0; + bi.biSizeImage = pImg->cbData; + bi.biXPelsPerMeter = 0; + bi.biYPelsPerMeter = 0; + bi.biClrUsed = 0; + bi.biClrImportant = 0; + + fwrite (&bf, 1, sizeof (bf), f); + fwrite (&bi, 1, sizeof (bi), f); + fwrite (pImg->pvData, 1, pImg->cbData, f); + + fclose (f); +} + +typedef struct CRDUMPGETHWID_DATA +{ + GLuint hwid; + PFNCRDUMPGETHWID pfnGetHwid; + unsigned long Key; + void* pvObj; +} CRDUMPGETHWID_DATA; + +static void crDmpHashtableSearchByHwidCB(unsigned long key, void *pData1, void *pData2) +{ + CRDUMPGETHWID_DATA *pData = (CRDUMPGETHWID_DATA*)pData2; + if (pData->pvObj) + return; + + if (pData->hwid == pData->pfnGetHwid(pData1)) + { + pData->Key = key; + pData->pvObj = pData1; + } +} + +void* crDmpHashtableSearchByHwid(CRHashTable *pHash, GLuint hwid, PFNCRDUMPGETHWID pfnGetHwid, unsigned long *pKey) +{ + CRDUMPGETHWID_DATA Data = {0}; + Data.hwid = hwid; + Data.pfnGetHwid = pfnGetHwid; + crHashtableWalk(pHash, crDmpHashtableSearchByHwidCB, &Data); + + Assert(Data.pvObj); + + if (pKey) + *pKey = Data.Key; + return Data.pvObj; +} + +#if 0 +typedef struct CR_SERVER_DUMP_FIND_TEX +{ + GLint hwid; + CRTextureObj *pTobj +} CR_SERVER_DUMP_FIND_TEX; + +void crServerDumpFindTexCb(unsigned long key, void *pData1, void *pData2) +{ + CR_SERVER_DUMP_FIND_TEX *pTex = (CR_SERVER_DUMP_FIND_TEX*)pData2; + CRTextureObj *pTobj = (CRTextureObj *)pData1; + if (pTobj->hwid == pTex->hwid) + pTex->pTobj = pTobj; +} +#endif + +#define CR_DUMP_MAKE_CASE(_val) case _val: return #_val +#define CR_DUMP_MAKE_CASE_UNKNOWN(_val, _str, _pDumper) default: { \ + crWarning("%s %d", (_str), _val); \ + crDmpStrF((_pDumper), "WARNING: %s %d", (_str), _val); \ + return (_str); \ +} + +DECLINLINE(size_t) crDmpFormatVal(char *pString, size_t cbString, const char *pszElFormat, uint32_t cbVal, const void *pvVal) +{ + if (pszElFormat[0] != '%' || pszElFormat[1] == '\0') + { + crWarning("invalid format %s", pszElFormat); + return 0; + } + switch (cbVal) + { + case 8: + return sprintf_s(pString, cbString, pszElFormat, *((double*)pvVal)); + case 4: + { + /* we do not care only about type specifiers, all the rest is not accepted */ + switch (pszElFormat[1]) + { + case 'f': + /* float would be promoted to double */ + return sprintf_s(pString, cbString, pszElFormat, *((float*)pvVal)); + default: + return sprintf_s(pString, cbString, pszElFormat, *((uint32_t*)pvVal)); + } + } + case 2: + return sprintf_s(pString, cbString, pszElFormat, *((uint16_t*)pvVal)); + case 1: + return sprintf_s(pString, cbString, pszElFormat, *((uint8_t*)pvVal)); + default: + crWarning("unsupported size %d", cbVal); + return 0; + } +} + +VBOXDUMPDECL(size_t) crDmpFormatRawArray(char *pString, size_t cbString, const char *pszElFormat, uint32_t cbEl, const void *pvVal, uint32_t cVal) +{ + if (cbString < 2) + { + crWarning("too few buffer size"); + return 0; + } + + const size_t cbInitString = cbString; + *pString++ = '{'; + --cbString; + size_t cbWritten; + const uint8_t *pu8Val = (const uint8_t *)pvVal; + for (uint32_t i = 0; i < cVal; ++i) + { + cbWritten = crDmpFormatVal(pString, cbString, pszElFormat, cbEl, (const void *)pu8Val); + pu8Val += cbEl; + Assert(cbString >= cbWritten); + pString += cbWritten; + cbString -= cbWritten; + if (i != cVal - 1) + { + cbWritten = sprintf_s(pString, cbString, ", "); + Assert(cbString >= cbWritten); + pString += cbWritten; + cbString -= cbWritten; + } + } + + if (!cbString) + { + crWarning("too few buffer size"); + return 0; + } + *pString++ = '}'; + --cbString; + + if (!cbString) + { + crWarning("too few buffer size"); + return 0; + } + *pString++ = '\0'; + + return cbInitString - cbString; +} + +VBOXDUMPDECL(size_t) crDmpFormatMatrixArray(char *pString, size_t cbString, const char *pszElFormat, uint32_t cbEl, const void *pvVal, uint32_t cX, uint32_t cY) +{ + if (cbString < 2) + { + crWarning("too few buffer size"); + return 0; + } + + const size_t cbInitString = cbString; + *pString++ = '{'; + --cbString; + size_t cbWritten; + const uint8_t *pu8Val = (const uint8_t *)pvVal; + for (uint32_t i = 0; i < cY; ++i) + { + cbWritten = crDmpFormatRawArray(pString, cbString, pszElFormat, cbEl, (const void *)pu8Val, cX); + pu8Val += (cbEl * cX); + Assert(cbString >= cbWritten); + pString += cbWritten; + cbString -= cbWritten; + if (i != cY - 1) + { + if (cbString < 3) + { + crWarning("too few buffer size"); + return 0; + } + *pString++ = ','; + --cbString; + *pString++ = '\n'; + --cbString; + } + } + if (!cbString) + { + crWarning("too few buffer size"); + return 0; + } + *pString++ = '}'; + --cbString; + + if (!cbString) + { + crWarning("too few buffer size"); + return 0; + } + *pString++ = '\0'; + + return cbInitString - cbString; +} + +VBOXDUMPDECL(size_t) crDmpFormatArray(char *pString, size_t cbString, const char *pszElFormat, uint32_t cbEl, const void *pvVal, uint32_t cVal) +{ + switch(cVal) + { + case 1: + return crDmpFormatVal(pString, cbString, pszElFormat, cbEl, pvVal); + case 16: + return crDmpFormatMatrixArray(pString, cbString, pszElFormat, cbEl, pvVal, 4, 4); + case 9: + return crDmpFormatMatrixArray(pString, cbString, pszElFormat, cbEl, pvVal, 3, 3); + case 0: + crWarning("value array is empty"); + return 0; + default: + return crDmpFormatRawArray(pString, cbString, pszElFormat, cbEl, pvVal, cVal); + } +} + +VBOXDUMPDECL(void) crRecDumpVertAttrv(CR_RECORDER *pRec, CRContext *ctx, GLuint idx, const char*pszElFormat, uint32_t cbEl, const void *pvVal, uint32_t cVal) +{ + char aBuf[1024]; + crDmpFormatRawArray(aBuf, sizeof (aBuf), pszElFormat, cbEl, pvVal, cVal); + crDmpStrF(pRec->pDumper, "(%u, %s)", idx, aBuf); +} + +VBOXDUMPDECL(void) crRecDumpVertAttrV(CR_RECORDER *pRec, CRContext *ctx, const char*pszFormat, va_list pArgList) +{ + crDmpStrV(pRec->pDumper, pszFormat, pArgList); +} + +VBOXDUMPDECL(void) crRecDumpVertAttrF(CR_RECORDER *pRec, CRContext *ctx, const char*pszFormat, ...) +{ + va_list pArgList; + va_start(pArgList, pszFormat); + crRecDumpVertAttrV(pRec, ctx, pszFormat, pArgList); + va_end(pArgList); +} + +void crRecDumpBuffer(CR_RECORDER *pRec, CRContext *ctx, GLint idRedirFBO, VBOXVR_TEXTURE *pRedirTex) +{ + GLenum texTarget = 0; + GLint hwBuf = 0, hwDrawBuf = 0; + GLint hwTex = 0, hwObjType = 0, hwTexLevel = 0, hwCubeFace = 0; + GLint width = 0, height = 0, depth = 0; + GLint id = 0; + CR_BLITTER_IMG Img = {0}; + VBOXVR_TEXTURE Tex; + int rc; + + pRec->pDispatch->GetIntegerv(GL_DRAW_BUFFER, &hwDrawBuf); + pRec->pDispatch->GetIntegerv(GL_FRAMEBUFFER_BINDING, &hwBuf); + if (hwBuf) + { + pRec->pDispatch->GetFramebufferAttachmentParameterivEXT(GL_DRAW_FRAMEBUFFER, hwDrawBuf, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &hwTex); + pRec->pDispatch->GetFramebufferAttachmentParameterivEXT(GL_DRAW_FRAMEBUFFER, hwDrawBuf, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &hwObjType); + if (hwObjType == GL_TEXTURE) + { + pRec->pDispatch->GetFramebufferAttachmentParameterivEXT(GL_DRAW_FRAMEBUFFER, hwDrawBuf, GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL, &hwTexLevel); + pRec->pDispatch->GetFramebufferAttachmentParameterivEXT(GL_DRAW_FRAMEBUFFER, hwDrawBuf, GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE, &hwCubeFace); + if (hwCubeFace) + { + crWarning("cube face: unsupported"); + return; + } + + if (hwTexLevel) + { + crWarning("non-zero tex level attached, unsupported"); + return; + } + } + else + { + crWarning("unsupported"); + return; + } + } + else + { + crWarning("no buffer attached: unsupported"); + return; + } + + if (ctx->framebufferobject.drawFB) + { + GLuint iColor = (hwDrawBuf - GL_COLOR_ATTACHMENT0_EXT); + CRTextureObj *pTobj = (CRTextureObj *)crHashtableSearch(ctx->shared->textureTable, ctx->framebufferobject.drawFB->color[iColor].name); + CRTextureLevel *pTl = NULL; + + id = pTobj->id; + + Assert(iColor < RT_ELEMENTS(ctx->framebufferobject.drawFB->color)); + + if (!pTobj) + { + crWarning("no tobj"); + return; + } + Assert(pTobj->hwid == hwTex); + Assert(pTobj); + Assert(ctx->framebufferobject.drawFB->hwid); + Assert(ctx->framebufferobject.drawFB->hwid == hwBuf); + Assert(ctx->framebufferobject.drawFB->drawbuffer[0] == hwDrawBuf); + + Assert(ctx->framebufferobject.drawFB->color[iColor].level == hwTexLevel); + Assert(ctx->framebufferobject.drawFB->color[iColor].type == hwObjType); + + texTarget = pTobj->target; + + Assert(texTarget == GL_TEXTURE_2D); + + pTl = &pTobj->level[0][hwTexLevel]; + + rc = CrBltEnter(pRec->pBlitter); + if (!RT_SUCCESS(rc)) + { + crWarning("CrBltEnter failed, rc %d", rc); + return; + } + + pRec->pDispatch->BindTexture(texTarget, hwTex); + + pRec->pDispatch->GetTexLevelParameteriv(texTarget, hwTexLevel, GL_TEXTURE_WIDTH, &width); + pRec->pDispatch->GetTexLevelParameteriv(texTarget, hwTexLevel, GL_TEXTURE_HEIGHT, &height); + pRec->pDispatch->GetTexLevelParameteriv(texTarget, hwTexLevel, GL_TEXTURE_DEPTH, &depth); + + Assert(width == pTl->width); + Assert(height == pTl->height); + Assert(depth == pTl->depth); + + pRec->pDispatch->BindTexture(texTarget, 0); + } + else + { + Assert(hwBuf == idRedirFBO); + if (!pRedirTex) + { + crWarning("pRedirTex is expected for non-FBO state!"); + return; + } + + Assert(hwTex == pRedirTex->hwid); + + texTarget = pRedirTex->target; + + width = pRedirTex->width; + height = pRedirTex->height; + + rc = CrBltEnter(pRec->pBlitter); + if (!RT_SUCCESS(rc)) + { + crWarning("CrBltEnter failed, rc %d", rc); + return; + } + } + + Tex.width = width; + Tex.height = height; + Tex.target = texTarget; + Tex.hwid = hwTex; + + rc = CrBltImgGetTex(pRec->pBlitter, &Tex, GL_BGRA, &Img); + if (RT_SUCCESS(rc)) + { + crDmpImgF(pRec->pDumper, &Img, "ctx(%d), BUFFER: id(%d) hwid(%d), width(%d), height(%d)", ctx, id, Tex.hwid, width, height); + + if (g_CrDbgDumpAlphaData) + { + CR_BLITTER_IMG AlphaImg = {0}; + rc = crRecAlphaImgCreate(&Img, &AlphaImg); + if (RT_SUCCESS(rc)) + { + crDmpImgF(pRec->pDumper, &AlphaImg, "Buffer ALPHA Data"); + crRecAlphaImgDestroy(&AlphaImg); + } + else + { + crWarning("crRecAlphaImgCreate failed rc %d", rc); + } + } + + CrBltImgFree(pRec->pBlitter, &Img); + } + else + { + crWarning("CrBltImgGetTex failed, rc %d", rc); + } + + CrBltLeave(pRec->pBlitter); +} + +static const char *crRecDumpShaderTypeString(GLenum enmType, CR_DUMPER *pDumper) +{ + switch (enmType) + { + CR_DUMP_MAKE_CASE(GL_VERTEX_SHADER_ARB); + CR_DUMP_MAKE_CASE(GL_FRAGMENT_SHADER_ARB); + CR_DUMP_MAKE_CASE(GL_GEOMETRY_SHADER_ARB); + CR_DUMP_MAKE_CASE_UNKNOWN(enmType, "Unknown Shader Type", pDumper); + } +} + +static const char *crRecDumpVarTypeString(GLenum enmType, CR_DUMPER *pDumper) +{ + switch (enmType) + { + CR_DUMP_MAKE_CASE(GL_BYTE); + CR_DUMP_MAKE_CASE(GL_UNSIGNED_BYTE); + CR_DUMP_MAKE_CASE(GL_SHORT); + CR_DUMP_MAKE_CASE(GL_UNSIGNED_SHORT); + CR_DUMP_MAKE_CASE(GL_FLOAT); + CR_DUMP_MAKE_CASE(GL_DOUBLE); + CR_DUMP_MAKE_CASE(GL_FLOAT_VEC2); + CR_DUMP_MAKE_CASE(GL_FLOAT_VEC3); + CR_DUMP_MAKE_CASE(GL_FLOAT_VEC4); + CR_DUMP_MAKE_CASE(GL_INT); + CR_DUMP_MAKE_CASE(GL_UNSIGNED_INT); + CR_DUMP_MAKE_CASE(GL_INT_VEC2); + CR_DUMP_MAKE_CASE(GL_INT_VEC3); + CR_DUMP_MAKE_CASE(GL_INT_VEC4); + CR_DUMP_MAKE_CASE(GL_BOOL); + CR_DUMP_MAKE_CASE(GL_BOOL_VEC2); + CR_DUMP_MAKE_CASE(GL_BOOL_VEC3); + CR_DUMP_MAKE_CASE(GL_BOOL_VEC4); + CR_DUMP_MAKE_CASE(GL_FLOAT_MAT2); + CR_DUMP_MAKE_CASE(GL_FLOAT_MAT3); + CR_DUMP_MAKE_CASE(GL_FLOAT_MAT4); + CR_DUMP_MAKE_CASE(GL_SAMPLER_1D); + CR_DUMP_MAKE_CASE(GL_SAMPLER_2D); + CR_DUMP_MAKE_CASE(GL_SAMPLER_3D); + CR_DUMP_MAKE_CASE(GL_SAMPLER_CUBE); + CR_DUMP_MAKE_CASE(GL_SAMPLER_1D_SHADOW); + CR_DUMP_MAKE_CASE(GL_SAMPLER_2D_SHADOW); + CR_DUMP_MAKE_CASE(GL_SAMPLER_2D_RECT_ARB); + CR_DUMP_MAKE_CASE(GL_SAMPLER_2D_RECT_SHADOW_ARB); + CR_DUMP_MAKE_CASE(GL_FLOAT_MAT2x3); + CR_DUMP_MAKE_CASE(GL_FLOAT_MAT2x4); + CR_DUMP_MAKE_CASE(GL_FLOAT_MAT3x2); + CR_DUMP_MAKE_CASE(GL_FLOAT_MAT3x4); + CR_DUMP_MAKE_CASE(GL_FLOAT_MAT4x2); + CR_DUMP_MAKE_CASE(GL_FLOAT_MAT4x3); + CR_DUMP_MAKE_CASE_UNKNOWN(enmType, "Unknown Variable Type", pDumper); + } +} + +static char *crRecDumpGetLine(char **ppszStr, uint32_t *pcbStr) +{ + char *pszStr, *pNewLine; + const uint32_t cbStr = *pcbStr; + + if (!cbStr) + { + /* zero-length string */ + return NULL; + } + + if ((*ppszStr)[cbStr-1] != '\0') + { + crWarning("string should be null-rerminated, forcing it!"); + (*ppszStr)[cbStr-1] = '\0'; + } + pszStr = *ppszStr; + if (!*pszStr) + { + *pcbStr = 0; + return NULL; + } + + if (!(pNewLine = strstr(pszStr, "\n"))) + { + /* the string contains a single line! */ + *ppszStr += strlen(pszStr); + *pcbStr = 0; + return pszStr; + } + + *pNewLine = '\0'; + *pcbStr = cbStr - (((uintptr_t)pNewLine) - ((uintptr_t)pszStr)) - 1; + Assert((*pcbStr) < UINT32_MAX/2); + Assert((*pcbStr) < cbStr); + *ppszStr = pNewLine + 1; + + return pszStr; +} + +static void crRecDumpStrByLine(CR_DUMPER *pDumper, char *pszStr, uint32_t cbStr) +{ + char *pszCurLine; + while ((pszCurLine = crRecDumpGetLine(&pszStr, &cbStr)) != NULL) + { + crDmpStrF(pDumper, "%s", pszCurLine); + } +} + +static DECLCALLBACK(GLuint) crDmpGetHwidShaderCB(void *pvObj) +{ + return ((CRGLSLShader*)pvObj)->hwid; +} + +static DECLCALLBACK(GLuint) crDmpGetHwidProgramCB(void *pvObj) +{ + return ((CRGLSLProgram*)pvObj)->hwid; +} + +/* Context activation is done by the caller. */ +void crRecDumpLog(CR_RECORDER *pRec, GLint hwid) +{ + GLint cbLog = 0; + pRec->pDispatch->GetObjectParameterivARB(hwid, GL_OBJECT_INFO_LOG_LENGTH_ARB, &cbLog); + + crDmpStrF(pRec->pDumper, "Log===%d===", hwid); + + if (cbLog > 1) + { + GLchar *pszLog = (GLchar *) crAlloc(cbLog*sizeof (GLchar)); + + pRec->pDispatch->GetInfoLogARB(hwid, cbLog, NULL, pszLog); + + crRecDumpStrByLine(pRec->pDumper, pszLog, cbLog); + + crFree(pszLog); + } + crDmpStrF(pRec->pDumper, "End Log======"); +} + +void crRecDumpShader(CR_RECORDER *pRec, CRContext *ctx, GLint id, GLint hwid) +{ + GLint length = 0; + GLint type = 0; + GLint compileStatus = 0; + +#ifndef IN_GUEST + CRGLSLShader *pShad; + + if (!id) + { + unsigned long tstKey = 0; + Assert(hwid); + pShad = (CRGLSLShader *)crDmpHashtableSearchByHwid(ctx->glsl.shaders, hwid, crDmpGetHwidShaderCB, &tstKey); + Assert(pShad); + if (!pShad) + return; + id = pShad->id; + Assert(tstKey == id); + } + else + { + pShad = (CRGLSLShader *)crHashtableSearch(ctx->glsl.shaders, id); + Assert(pShad); + if (!pShad) + return; + } + + if (!hwid) + hwid = pShad->hwid; + + Assert(pShad->hwid == hwid); + Assert(pShad->id == id); +#else + if (!id) + id = hwid; + else if (!hwid) + hwid = id; + + Assert(id); + Assert(hwid); + Assert(hwid == id); +#endif + + pRec->pDispatch->GetObjectParameterivARB(hwid, GL_OBJECT_SUBTYPE_ARB, &type); + pRec->pDispatch->GetObjectParameterivARB(hwid, GL_OBJECT_COMPILE_STATUS_ARB, &compileStatus); + crDmpStrF(pRec->pDumper, "SHADER ctx(%d) id(%d) hwid(%d) type(%s) status(%d):", ctx->id, id, hwid, crRecDumpShaderTypeString(type, pRec->pDumper), compileStatus); + + crRecDumpLog(pRec, hwid); + + pRec->pDispatch->GetObjectParameterivARB(hwid, GL_OBJECT_SHADER_SOURCE_LENGTH_ARB, &length); + + char *pszSource = (char*)crCalloc(length + 1); + if (!pszSource) + { + crWarning("crCalloc failed"); + crDmpStrF(pRec->pDumper, "WARNING: crCalloc failed"); + return; + } + + pRec->pDispatch->GetShaderSource(hwid, length, NULL, pszSource); + crRecDumpStrByLine(pRec->pDumper, pszSource, length); + + crFree(pszSource); + + crDmpStr(pRec->pDumper, "===END SHADER===="); +} + +void crRecDumpProgram(CR_RECORDER *pRec, CRContext *ctx, GLint id, GLint hwid) +{ + GLint cShaders = 0, linkStatus = 0; + char *source = NULL; + CRGLSLProgram *pProg; + + if (!id) + { + unsigned long tstKey = 0; + Assert(hwid); + pProg = (CRGLSLProgram*)crDmpHashtableSearchByHwid(ctx->glsl.programs, hwid, crDmpGetHwidProgramCB, &tstKey); + Assert(pProg); + if (!pProg) + return; + id = pProg->id; + Assert(tstKey == id); + } + else + { + pProg = (CRGLSLProgram *) crHashtableSearch(ctx->glsl.programs, id); + Assert(pProg); + if (!pProg) + return; + } + + if (!hwid) + hwid = pProg->hwid; + + Assert(pProg->hwid == hwid); + Assert(pProg->id == id); + + pRec->pDispatch->GetObjectParameterivARB(hwid, GL_OBJECT_ATTACHED_OBJECTS_ARB, &cShaders); + pRec->pDispatch->GetObjectParameterivARB(hwid, GL_OBJECT_LINK_STATUS_ARB, &linkStatus); + + crDmpStrF(pRec->pDumper, "PROGRAM ctx(%d) id(%d) hwid(%d) status(%d) shaders(%d):", ctx->id, id, hwid, linkStatus, cShaders); + + crRecDumpLog(pRec, hwid); + + VBoxGLhandleARB *pShaders = (VBoxGLhandleARB*)crCalloc(cShaders * sizeof (*pShaders)); + if (!pShaders) + { + crWarning("crCalloc failed"); + crDmpStrF(pRec->pDumper, "WARNING: crCalloc failed"); + return; + } + + pRec->pDispatch->GetAttachedObjectsARB(hwid, cShaders, NULL, pShaders); + for (GLint i = 0; i < cShaders; ++i) + { + if (pShaders[i]) + crRecDumpShader(pRec, ctx, 0, pShaders[i]); + else + crDmpStrF(pRec->pDumper, "WARNING: Shader[%d] is null", i); + } + + crFree(pShaders); + + GLsizei cbLog = 0; + + pRec->pDispatch->GetObjectParameterivARB(hwid, GL_OBJECT_INFO_LOG_LENGTH_ARB, &cbLog); + if (cbLog) + { + char *pszLog = (char *)crCalloc(cbLog+1); + pRec->pDispatch->GetInfoLogARB(hwid, cbLog, NULL, pszLog); + crDmpStrF(pRec->pDumper, "==LOG=="); + crRecDumpStrByLine(pRec->pDumper, pszLog, cbLog); + crDmpStrF(pRec->pDumper, "==Done LOG=="); + crFree(pszLog); + } + else + { + crDmpStrF(pRec->pDumper, "==No LOG=="); + } + + crDmpStr(pRec->pDumper, "===END PROGRAM===="); +} + +void crRecRecompileShader(CR_RECORDER *pRec, CRContext *ctx, GLint id, GLint hwid) +{ + GLint length = 0; + GLint type = 0; + GLint compileStatus = 0; + CRGLSLShader *pShad; + + if (!id) + { + unsigned long tstKey = 0; + Assert(hwid); + pShad = (CRGLSLShader *)crDmpHashtableSearchByHwid(ctx->glsl.shaders, hwid, crDmpGetHwidShaderCB, &tstKey); + Assert(pShad); + if (!pShad) + return; + id = pShad->id; + Assert(tstKey == id); + } + else + { + pShad = (CRGLSLShader *)crHashtableSearch(ctx->glsl.shaders, id); + Assert(pShad); + if (!pShad) + return; + } + + if (!hwid) + hwid = pShad->hwid; + + Assert(pShad->hwid == hwid); + Assert(pShad->id == id); + + pRec->pDispatch->GetObjectParameterivARB(hwid, GL_OBJECT_SUBTYPE_ARB, &type); + pRec->pDispatch->GetObjectParameterivARB(hwid, GL_OBJECT_COMPILE_STATUS_ARB, &compileStatus); + crDmpStrF(pRec->pDumper, "==RECOMPILE SHADER ctx(%d) id(%d) hwid(%d) type(%s) status(%d)==", ctx->id, id, hwid, crRecDumpShaderTypeString(type, pRec->pDumper), compileStatus); + + compileStatus = 0; + GLenum status; + while ((status = pRec->pDispatch->GetError()) != GL_NO_ERROR) {/*Assert(0);*/} + pRec->pDispatch->CompileShader(hwid); + while ((status = pRec->pDispatch->GetError()) != GL_NO_ERROR) {Assert(0);} + pRec->pDispatch->GetObjectParameterivARB(hwid, GL_OBJECT_COMPILE_STATUS_ARB, &compileStatus); + + crDmpStrF(pRec->pDumper, "==Done RECOMPILE SHADER, status(%d)==", compileStatus); +} + +void crRecRecompileProgram(CR_RECORDER *pRec, CRContext *ctx, GLint id, GLint hwid) +{ + GLint cShaders = 0, linkStatus = 0; + char *source = NULL; + CRGLSLProgram *pProg; + + if (!id) + { + unsigned long tstKey = 0; + Assert(hwid); + pProg = (CRGLSLProgram*)crDmpHashtableSearchByHwid(ctx->glsl.programs, hwid, crDmpGetHwidProgramCB, &tstKey); + Assert(pProg); + if (!pProg) + return; + id = pProg->id; + Assert(tstKey == id); + } + else + { + pProg = (CRGLSLProgram *) crHashtableSearch(ctx->glsl.programs, id); + Assert(pProg); + if (!pProg) + return; + } + + if (!hwid) + hwid = pProg->hwid; + + Assert(pProg->hwid == hwid); + Assert(pProg->id == id); + + pRec->pDispatch->GetObjectParameterivARB(hwid, GL_OBJECT_ATTACHED_OBJECTS_ARB, &cShaders); + pRec->pDispatch->GetObjectParameterivARB(hwid, GL_OBJECT_LINK_STATUS_ARB, &linkStatus); + + crDmpStrF(pRec->pDumper, "==RECOMPILE PROGRAM ctx(%d) id(%d) hwid(%d) status(%d) shaders(%d)==", ctx->id, id, hwid, linkStatus, cShaders); + + VBoxGLhandleARB *pShaders = (VBoxGLhandleARB*)crCalloc(cShaders * sizeof (*pShaders)); + if (!pShaders) + { + crWarning("crCalloc failed"); + crDmpStrF(pRec->pDumper, "WARNING: crCalloc failed"); + return; + } + + pRec->pDispatch->GetAttachedObjectsARB(hwid, cShaders, NULL, pShaders); + for (GLint i = 0; i < cShaders; ++i) + { + crRecRecompileShader(pRec, ctx, 0, pShaders[i]); + } + + crFree(pShaders); + + linkStatus = 0; + GLenum status; + while ((status = pRec->pDispatch->GetError()) != GL_NO_ERROR) {/*Assert(0);*/} + pRec->pDispatch->LinkProgram(hwid); + while ((status = pRec->pDispatch->GetError()) != GL_NO_ERROR) {Assert(0);} + pRec->pDispatch->GetObjectParameterivARB(hwid, GL_OBJECT_LINK_STATUS_ARB, &linkStatus); + + crDmpStrF(pRec->pDumper, "==Done RECOMPILE PROGRAM, status(%d)==", linkStatus); +} + +VBOXDUMPDECL(void) crRecDumpCurrentProgram(CR_RECORDER *pRec, CRContext *ctx) +{ + GLint curProgram = 0; + pRec->pDispatch->GetIntegerv(GL_CURRENT_PROGRAM, &curProgram); + if (curProgram) + { + Assert(ctx->glsl.activeProgram); + if (!ctx->glsl.activeProgram) + crWarning("no active program state with active hw program"); + else + Assert(ctx->glsl.activeProgram->hwid == curProgram); + crRecDumpProgram(pRec, ctx, 0, curProgram); + } + else + { + Assert(!ctx->glsl.activeProgram); + crDmpStrF(pRec->pDumper, "--no active program"); + } +} + +void crRecDumpProgramUniforms(CR_RECORDER *pRec, CRContext *ctx, GLint id, GLint hwid) +{ + CRGLSLProgram *pProg; + + if (!id) + { + unsigned long tstKey = 0; + Assert(hwid); + pProg = (CRGLSLProgram*)crDmpHashtableSearchByHwid(ctx->glsl.programs, hwid, crDmpGetHwidProgramCB, &tstKey); + Assert(pProg); + if (!pProg) + return; + id = pProg->id; + Assert(tstKey == id); + } + else + { + pProg = (CRGLSLProgram *) crHashtableSearch(ctx->glsl.programs, id); + Assert(pProg); + if (!pProg) + return; + } + + if (!hwid) + hwid = pProg->hwid; + + Assert(pProg->hwid == hwid); + Assert(pProg->id == id); + + GLint maxUniformLen = 0, activeUniforms = 0, i, j, uniformsCount = 0; + GLenum type; + GLint size, location; + GLchar *pszName = NULL; + pRec->pDispatch->GetProgramiv(hwid, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxUniformLen); + pRec->pDispatch->GetProgramiv(hwid, GL_ACTIVE_UNIFORMS, &activeUniforms); + + if (!maxUniformLen) + { + if (activeUniforms) + { + crWarning("activeUniforms (%d), while maxUniformLen is zero", activeUniforms); + activeUniforms = 0; + } + } + + if (activeUniforms>0) + { + pszName = (GLchar *) crAlloc((maxUniformLen+8)*sizeof(GLchar)); + + if (!pszName) + { + crWarning("crRecDumpProgramUniforms: out of memory"); + return; + } + } + + for (i=0; i<activeUniforms; ++i) + { + pRec->pDispatch->GetActiveUniform(hwid, i, maxUniformLen, NULL, &size, &type, pszName); + uniformsCount += size; + } + Assert(uniformsCount>=activeUniforms); + + if (activeUniforms>0) + { + GLfloat fdata[16]; + GLint idata[16]; + char *pIndexStr=NULL; + + for (i=0; i<activeUniforms; ++i) + { + bool fPrintBraketsWithName = false; + pRec->pDispatch->GetActiveUniform(hwid, i, maxUniformLen, NULL, &size, &type, pszName); + + if (size>1) + { + pIndexStr = crStrchr(pszName, '['); + if (!pIndexStr) + { + pIndexStr = pszName+crStrlen(pszName); + fPrintBraketsWithName = true; + } + } + + if (fPrintBraketsWithName) + { + crDmpStrF(pRec->pDumper, "%s %s[%d];", crRecDumpVarTypeString(type, pRec->pDumper), pszName, size); + Assert(size > 1); + } + else + crDmpStrF(pRec->pDumper, "%s %s;", crRecDumpVarTypeString(type, pRec->pDumper), pszName); + + GLint uniformTypeSize = crStateGetUniformSize(type); + Assert(uniformTypeSize >= 1); + + for (j=0; j<size; ++j) + { + if (size>1) + { + sprintf(pIndexStr, "[%i]", j); + } + location = pRec->pDispatch->GetUniformLocation(hwid, pszName); + + if (crStateIsIntUniform(type)) + { + pRec->pDispatch->GetUniformiv(hwid, location, &idata[0]); + switch (uniformTypeSize) + { + case 1: + crDmpStrF(pRec->pDumper, "%s = %d; //location %d", pszName, idata[0], location); + break; + case 2: + crDmpStrF(pRec->pDumper, "%s = {%d, %d}; //location %d", pszName, idata[0], idata[1], location); + break; + case 3: + crDmpStrF(pRec->pDumper, "%s = {%d, %d, %d}; //location %d", pszName, idata[0], idata[1], idata[2], location); + break; + case 4: + crDmpStrF(pRec->pDumper, "%s = {%d, %d, %d, %d}; //location %d", pszName, idata[0], idata[1], idata[2], idata[3], location); + break; + default: + for (GLint k = 0; k < uniformTypeSize; ++k) + { + crDmpStrF(pRec->pDumper, "%s[%d] = %d; //location %d", pszName, k, idata[k], location); + } + break; + } + } + else + { + pRec->pDispatch->GetUniformfv(hwid, location, &fdata[0]); + switch (uniformTypeSize) + { + case 1: + crDmpStrF(pRec->pDumper, "%s = %f; //location %d", pszName, fdata[0], location); + break; + case 2: + crDmpStrF(pRec->pDumper, "%s = {%f, %f}; //location %d", pszName, fdata[0], fdata[1], location); + break; + case 3: + crDmpStrF(pRec->pDumper, "%s = {%f, %f, %f}; //location %d", pszName, fdata[0], fdata[1], fdata[2], location); + break; + case 4: + crDmpStrF(pRec->pDumper, "%s = {%f, %f, %f, %f}; //location %d", pszName, fdata[0], fdata[1], fdata[2], fdata[3], location); + break; + default: + for (GLint k = 0; k < uniformTypeSize; ++k) + { + crDmpStrF(pRec->pDumper, "%s[%d] = %f; //location %d", pszName, k, fdata[k], location); + } + break; + } + } + } + } + + crFree(pszName); + } +} + +void crRecDumpProgramAttribs(CR_RECORDER *pRec, CRContext *ctx, GLint id, GLint hwid) +{ + CRGLSLProgram *pProg; + + if (!id) + { + unsigned long tstKey = 0; + Assert(hwid); + pProg = (CRGLSLProgram*)crDmpHashtableSearchByHwid(ctx->glsl.programs, hwid, crDmpGetHwidProgramCB, &tstKey); + Assert(pProg); + if (!pProg) + return; + id = pProg->id; + Assert(tstKey == id); + } + else + { + pProg = (CRGLSLProgram *) crHashtableSearch(ctx->glsl.programs, id); + Assert(pProg); + if (!pProg) + return; + } + + if (!hwid) + hwid = pProg->hwid; + + Assert(pProg->hwid == hwid); + Assert(pProg->id == id); + + GLint maxAttribLen = 0, activeAttrib = 0, i, j, attribCount = 0; + GLenum type; + GLint size, location; + GLchar *pszName = NULL; + pRec->pDispatch->GetProgramiv(hwid, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxAttribLen); + pRec->pDispatch->GetProgramiv(hwid, GL_ACTIVE_ATTRIBUTES, &activeAttrib); + + if (!maxAttribLen) + { + if (activeAttrib) + { + crWarning("activeAttrib (%d), while maxAttribLen is zero", activeAttrib); + activeAttrib = 0; + } + } + + if (activeAttrib>0) + { + pszName = (GLchar *) crAlloc((maxAttribLen+8)*sizeof(GLchar)); + + if (!pszName) + { + crWarning("crRecDumpProgramAttrib: out of memory"); + return; + } + } + + for (i=0; i<activeAttrib; ++i) + { + pRec->pDispatch->GetActiveAttrib(hwid, i, maxAttribLen, NULL, &size, &type, pszName); + attribCount += size; + } + Assert(attribCount>=activeAttrib); + + if (activeAttrib>0) + { + GLfloat fdata[16]; + GLint idata[16]; + char *pIndexStr=NULL; + + for (i=0; i<activeAttrib; ++i) + { + bool fPrintBraketsWithName = false; + pRec->pDispatch->GetActiveAttrib(hwid, i, maxAttribLen, NULL, &size, &type, pszName); + GLint arrayBufferBind = 0, arrayEnabled = 0, arraySize = 0, arrayStride = 0, arrayType = 0, arrayNormalized = 0, arrayInteger = 0/*, arrayDivisor = 0*/; + + pRec->pDispatch->GetVertexAttribivARB(i, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &arrayBufferBind); + pRec->pDispatch->GetVertexAttribivARB(i, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &arrayEnabled); + pRec->pDispatch->GetVertexAttribivARB(i, GL_VERTEX_ATTRIB_ARRAY_SIZE, &arraySize); + pRec->pDispatch->GetVertexAttribivARB(i, GL_VERTEX_ATTRIB_ARRAY_STRIDE, &arrayStride); + pRec->pDispatch->GetVertexAttribivARB(i, GL_VERTEX_ATTRIB_ARRAY_TYPE, &arrayType); + pRec->pDispatch->GetVertexAttribivARB(i, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, &arrayNormalized); + pRec->pDispatch->GetVertexAttribivARB(i, GL_VERTEX_ATTRIB_ARRAY_INTEGER, &arrayInteger); +// pRec->pDispatch->GetVertexAttribivARB(i, GL_VERTEX_ATTRIB_ARRAY_DIVISOR, &arrayDivisor); + + if (size>1) + { + pIndexStr = crStrchr(pszName, '['); + if (!pIndexStr) + { + pIndexStr = pszName+crStrlen(pszName); + fPrintBraketsWithName = true; + } + } + + if (fPrintBraketsWithName) + { + crDmpStrF(pRec->pDumper, "%s %s[%d];", crRecDumpVarTypeString(type, pRec->pDumper), pszName, size); + Assert(size > 1); + } + else + crDmpStrF(pRec->pDumper, "%s %s;", crRecDumpVarTypeString(type, pRec->pDumper), pszName); + + crDmpStrF(pRec->pDumper, "Array buff(%d), enabled(%d) size(%d), stride(%d), type(%s), normalized(%d), integer(%d)", arrayBufferBind, arrayEnabled, arraySize, arrayStride, crRecDumpVarTypeString(arrayType, pRec->pDumper), arrayNormalized, arrayInteger); + + GLint attribTypeSize = crStateGetUniformSize(type); + Assert(attribTypeSize >= 1); + + for (j=0; j<size; ++j) + { + if (size>1) + { + sprintf(pIndexStr, "[%i]", j); + } + location = pRec->pDispatch->GetAttribLocation(hwid, pszName); + + if (crStateIsIntUniform(type)) + { + pRec->pDispatch->GetVertexAttribivARB(location, GL_CURRENT_VERTEX_ATTRIB, &idata[0]); + switch (attribTypeSize) + { + case 1: + crDmpStrF(pRec->pDumper, "%s = %d; //location %d", pszName, idata[0], location); + break; + case 2: + crDmpStrF(pRec->pDumper, "%s = {%d, %d}; //location %d", pszName, idata[0], idata[1], location); + break; + case 3: + crDmpStrF(pRec->pDumper, "%s = {%d, %d, %d}; //location %d", pszName, idata[0], idata[1], idata[2], location); + break; + case 4: + crDmpStrF(pRec->pDumper, "%s = {%d, %d, %d, %d}; //location %d", pszName, idata[0], idata[1], idata[2], idata[3], location); + break; + default: + for (GLint k = 0; k < attribTypeSize; ++k) + { + crDmpStrF(pRec->pDumper, "%s[%d] = %d; //location %d", pszName, k, idata[k], location); + } + break; + } + } + else + { + pRec->pDispatch->GetVertexAttribfvARB(location, GL_CURRENT_VERTEX_ATTRIB, &fdata[0]); + switch (attribTypeSize) + { + case 1: + crDmpStrF(pRec->pDumper, "%s = %f; //location %d", pszName, fdata[0], location); + break; + case 2: + crDmpStrF(pRec->pDumper, "%s = {%f, %f}; //location %d", pszName, fdata[0], fdata[1], location); + break; + case 3: + crDmpStrF(pRec->pDumper, "%s = {%f, %f, %f}; //location %d", pszName, fdata[0], fdata[1], fdata[2], location); + break; + case 4: + crDmpStrF(pRec->pDumper, "%s = {%f, %f, %f, %f}; //location %d", pszName, fdata[0], fdata[1], fdata[2], fdata[3], location); + break; + default: + for (GLint k = 0; k < attribTypeSize; ++k) + { + crDmpStrF(pRec->pDumper, "%s[%d] = %f; //location %d", pszName, k, fdata[k], location); + } + break; + } + } + } + } + + crFree(pszName); + } +} + +VBOXDUMPDECL(void) crRecDumpCurrentProgramUniforms(CR_RECORDER *pRec, CRContext *ctx) +{ + GLint curProgram = 0; + pRec->pDispatch->GetIntegerv(GL_CURRENT_PROGRAM, &curProgram); + if (curProgram) + { + Assert(ctx->glsl.activeProgram); + if (!ctx->glsl.activeProgram) + crWarning("no active program state with active hw program"); + else + Assert(ctx->glsl.activeProgram->hwid == curProgram); + crRecDumpProgramUniforms(pRec, ctx, 0, curProgram); + } + else + { + Assert(!ctx->glsl.activeProgram); + crDmpStrF(pRec->pDumper, "--no active program"); + } +} + +VBOXDUMPDECL(void) crRecDumpCurrentProgramAttribs(CR_RECORDER *pRec, CRContext *ctx) +{ + GLint curProgram = 0; + pRec->pDispatch->GetIntegerv(GL_CURRENT_PROGRAM, &curProgram); + if (curProgram) + { + Assert(ctx->glsl.activeProgram); + if (!ctx->glsl.activeProgram) + crWarning("no active program state with active hw program"); + else + Assert(ctx->glsl.activeProgram->hwid == curProgram); + crRecDumpProgramAttribs(pRec, ctx, 0, curProgram); + } + else + { + Assert(!ctx->glsl.activeProgram); + crDmpStrF(pRec->pDumper, "--no active program"); + } +} + +VBOXDUMPDECL(void) crRecRecompileCurrentProgram(CR_RECORDER *pRec, CRContext *ctx) +{ + GLint curProgram = 0; + pRec->pDispatch->GetIntegerv(GL_CURRENT_PROGRAM, &curProgram); + if (curProgram) + { + Assert(ctx->glsl.activeProgram); + if (!ctx->glsl.activeProgram) + crWarning("no active program state with active hw program"); + else + Assert(ctx->glsl.activeProgram->hwid == curProgram); + crRecRecompileProgram(pRec, ctx, 0, curProgram); + } + else + { + Assert(!ctx->glsl.activeProgram); + crDmpStrF(pRec->pDumper, "--no active program"); + } +} + +int crRecAlphaImgCreate(const CR_BLITTER_IMG *pImg, CR_BLITTER_IMG *pAlphaImg) +{ + if (pImg->enmFormat != GL_RGBA + && pImg->enmFormat != GL_BGRA) + { + crWarning("unsupported format 0x%x", pImg->enmFormat); + return VERR_NOT_IMPLEMENTED; + } + + pAlphaImg->bpp = 32; + pAlphaImg->pitch = pImg->width * 4; + pAlphaImg->cbData = pAlphaImg->pitch * pImg->height; + pAlphaImg->enmFormat = GL_BGRA; + pAlphaImg->width = pImg->width; + pAlphaImg->height = pImg->height; + + pAlphaImg->pvData = RTMemAlloc(pAlphaImg->cbData); + if (!pAlphaImg->pvData) + { + crWarning("RTMemAlloc failed"); + return VERR_NO_MEMORY; + } + + uint8_t *pu8SrcBuf = (uint8_t*)pImg->pvData; + uint8_t *pu8DstBuf = (uint8_t*)pAlphaImg->pvData; + for (uint32_t ih = 0; ih < pAlphaImg->height; ++ih) + { + uint32_t *pu32SrcBuf = (uint32_t*)pu8SrcBuf; + uint32_t *pu32DstBuf = (uint32_t*)pu8DstBuf; + for (uint32_t iw = 0; iw < pAlphaImg->width; ++iw) + { + uint8_t alpha = (((*pu32SrcBuf) >> 24) & 0xff); + *pu32DstBuf = (0xff << 24) || (alpha << 16) || (alpha << 8) || alpha; + ++pu32SrcBuf; + ++pu32DstBuf; + } + pu8SrcBuf += pImg->pitch; + pu8DstBuf += pAlphaImg->pitch; + } + + return VINF_SUCCESS; +} + +void crRecAlphaImgDestroy(CR_BLITTER_IMG *pImg) +{ + RTMemFree(pImg->pvData); + pImg->pvData = NULL; +} + +void crRecDumpTextureV(CR_RECORDER *pRec, const VBOXVR_TEXTURE *pTex, const char *pszStr, va_list pArgList) +{ + CR_BLITTER_IMG Img = {0}; + int rc = CrBltEnter(pRec->pBlitter); + if (RT_SUCCESS(rc)) + { + rc = CrBltImgGetTex(pRec->pBlitter, pTex, GL_BGRA, &Img); + if (RT_SUCCESS(rc)) + { + crDmpImgV(pRec->pDumper, &Img, pszStr, pArgList); + if (g_CrDbgDumpAlphaData) + { + CR_BLITTER_IMG AlphaImg = {0}; + rc = crRecAlphaImgCreate(&Img, &AlphaImg); + if (RT_SUCCESS(rc)) + { + crDmpImgF(pRec->pDumper, &AlphaImg, "Texture ALPHA Data"); + crRecAlphaImgDestroy(&AlphaImg); + } + else + { + crWarning("crRecAlphaImgCreate failed rc %d", rc); + } + } + CrBltImgFree(pRec->pBlitter, &Img); + } + else + { + crWarning("CrBltImgGetTex failed, rc %d", rc); + } + CrBltLeave(pRec->pBlitter); + } + else + { + crWarning("CrBltEnter failed, rc %d", rc); + } +} + +void crRecDumpTextureF(CR_RECORDER *pRec, const VBOXVR_TEXTURE *pTex, const char *pszStr, ...) +{ + va_list pArgList; + va_start(pArgList, pszStr); + crRecDumpTextureV(pRec, pTex, pszStr, pArgList); + va_end(pArgList); +} + +void crRecDumpTextureByIdV(CR_RECORDER *pRec, CRContext *ctx, GLint id, const char *pszStr, va_list pArgList) +{ + CRTextureObj *pTobj = (CRTextureObj *)crHashtableSearch(ctx->shared->textureTable, id); + if (!pTobj) + { + crWarning("no texture of id %d", id); + return; + } + + CRTextureLevel *pTl = &pTobj->level[0][0 /* level */]; + VBOXVR_TEXTURE Tex; + Tex.width = pTl->width; + Tex.height = pTl->height; + Tex.target = pTobj->target; + Assert(Tex.target == GL_TEXTURE_2D); + Tex.hwid = pTobj->hwid; + if (!Tex.hwid) + { + crWarning("no texture hwid of id %d", id); + return; + } + + crRecDumpTextureV(pRec, &Tex, pszStr, pArgList); +} + +void crRecDumpTextureByIdF(CR_RECORDER *pRec, CRContext *ctx, GLint id, const char *pszStr, ...) +{ + va_list pArgList; + va_start(pArgList, pszStr); + crRecDumpTextureByIdV(pRec, ctx, id, pszStr, pArgList); + va_end(pArgList); +} + +void crRecDumpTextures(CR_RECORDER *pRec, CRContext *ctx) +{ + GLint maxUnits = 0; + GLint curTexUnit = 0; + GLint restoreTexUnit = 0; + GLint curProgram = 0; + int i; + + pRec->pDispatch->GetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxUnits); + maxUnits = RT_MIN(CR_MAX_TEXTURE_UNITS, maxUnits); + + pRec->pDispatch->GetIntegerv(GL_CURRENT_PROGRAM, &curProgram); + Assert(curProgram); + Assert(ctx->glsl.activeProgram && ctx->glsl.activeProgram->hwid == curProgram); + + Assert(maxUnits); + pRec->pDispatch->GetIntegerv(GL_ACTIVE_TEXTURE, &curTexUnit); + restoreTexUnit = curTexUnit; + Assert(curTexUnit >= GL_TEXTURE0); + Assert(curTexUnit < GL_TEXTURE0 + maxUnits); + + Assert(ctx->texture.curTextureUnit == restoreTexUnit - GL_TEXTURE0); + + for (i = 0; i < maxUnits; ++i) + { + GLboolean enabled1D; + GLboolean enabled2D; + GLboolean enabled3D; + GLboolean enabledCubeMap; + GLboolean enabledRect; + CRTextureUnit *tu = &ctx->texture.unit[i]; + + if (i > 1) + break; + + if (curTexUnit != i + GL_TEXTURE0) + { + pRec->pDispatch->ActiveTextureARB(i + GL_TEXTURE0); + curTexUnit = i + GL_TEXTURE0; + } + + enabled1D = pRec->pDispatch->IsEnabled(GL_TEXTURE_1D); + enabled2D = pRec->pDispatch->IsEnabled(GL_TEXTURE_2D); + enabled3D = pRec->pDispatch->IsEnabled(GL_TEXTURE_3D); + enabledCubeMap = pRec->pDispatch->IsEnabled(GL_TEXTURE_CUBE_MAP_ARB); + enabledRect = pRec->pDispatch->IsEnabled(GL_TEXTURE_RECTANGLE_NV); + + Assert(enabled1D == tu->enabled1D); + Assert(enabled2D == tu->enabled2D); + Assert(enabled3D == tu->enabled3D); + Assert(enabledCubeMap == tu->enabledCubeMap); + Assert(enabledRect == tu->enabledRect); + + if (enabled1D) + { + crWarning("GL_TEXTURE_1D: unsupported"); + } + +// if (enabled2D) + { + GLint hwTex = 0; + VBOXVR_TEXTURE Tex; + + GLint width = 0, height = 0, depth = 0; + CRTextureObj *pTobj = tu->currentTexture2D; + + pRec->pDispatch->GetIntegerv(GL_TEXTURE_BINDING_2D, &hwTex); + if (hwTex) + { + CRTextureLevel *pTl = &pTobj->level[0][0 /* level */]; + Assert(pTobj + && pTobj->hwid == hwTex); + + pRec->pDispatch->GetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width); + pRec->pDispatch->GetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &height); + pRec->pDispatch->GetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_DEPTH, &depth); + + Assert(width == pTl->width); + Assert(height == pTl->height); + Assert(depth == pTl->depth); + + Tex.width = width; + Tex.height = height; + Tex.target = GL_TEXTURE_2D; + Tex.hwid = hwTex; + + if (g_CrDbgDumpRecTexInfo) + { + crRecDumpTexParam(pRec, ctx, GL_TEXTURE_2D); + crRecDumpTexEnv(pRec, ctx); + crRecDumpTexGen(pRec, ctx); + } + + crRecDumpTextureF(pRec, &Tex, "ctx(%d), Unit %d: TEXTURE_2D id(%d) hwid(%d), width(%d), height(%d)", ctx, i, pTobj->id, pTobj->hwid, width, height); + } +// else +// { +// Assert(!pTobj || pTobj->hwid == 0); +// crWarning("no TEXTURE_2D bound!"); +// } + } +#if 0 + if (enabled3D) + { + crWarning("GL_TEXTURE_3D: unsupported"); + } + + if (enabledCubeMap) + { + crWarning("GL_TEXTURE_CUBE_MAP_ARB: unsupported"); + } + +// if (enabledRect) + { + GLint hwTex = 0; + CR_BLITTER_IMG Img = {0}; + VBOXVR_TEXTURE Tex; + + GLint width = 0, height = 0, depth = 0; + CRTextureObj *pTobj = tu->currentTextureRect; + + pRec->pDispatch->GetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_NV, &hwTex); + if (hwTex) + { + CRTextureLevel *pTl = &pTobj->level[0][0 /* level */]; + Assert(pTobj + && pTobj->hwid == hwTex); + + pRec->pDispatch->GetTexLevelParameteriv(GL_TEXTURE_RECTANGLE_NV, 0, GL_TEXTURE_WIDTH, &width); + pRec->pDispatch->GetTexLevelParameteriv(GL_TEXTURE_RECTANGLE_NV, 0, GL_TEXTURE_HEIGHT, &height); + pRec->pDispatch->GetTexLevelParameteriv(GL_TEXTURE_RECTANGLE_NV, 0, GL_TEXTURE_DEPTH, &depth); + + Assert(width == pTl->width); + Assert(height == pTl->height); + Assert(depth == pTl->depth); + + Tex.width = width; + Tex.height = height; + Tex.target = GL_TEXTURE_RECTANGLE_NV; + Tex.hwid = hwTex; + + rc = CrBltEnter(pRec->pBlitter); + if (RT_SUCCESS(rc)) + { + rc = CrBltImgGetTex(pRec->pBlitter, &Tex, GL_BGRA, &Img); + if (RT_SUCCESS(rc)) + { + crDmpImgF(pRec->pDumper, &Img, "Unit %d: TEXTURE_RECTANGLE data", i); + CrBltImgFree(pRec->pBlitter, &Img); + } + else + { + crWarning("CrBltImgGetTex failed, rc %d", rc); + } + CrBltLeave(pRec->pBlitter); + } + else + { + crWarning("CrBltEnter failed, rc %d", rc); + } + } +// else +// { +// Assert(!pTobj || pTobj->hwid == 0); +// crWarning("no TEXTURE_RECTANGLE bound!"); +// } + } +#endif + } + + if (curTexUnit != restoreTexUnit) + { + pRec->pDispatch->ActiveTextureARB(restoreTexUnit); + curTexUnit = restoreTexUnit; + } +} + +#ifdef RT_OS_WINDOWS +static void crDmpPrint(const char* szString, ...) +{ + char szBuffer[4096] = {0}; + va_list pArgList; + va_start(pArgList, szString); + RTStrPrintfV(szBuffer, sizeof (szBuffer), szString, pArgList); + va_end(pArgList); + + OutputDebugStringA(szBuffer); +} + +static void crDmpPrintDmlCmd(const char* pszDesc, const char* pszCmd) +{ + crDmpPrint("<?dml?><exec cmd=\"%s\">%s</exec>, ( %s )\n", pszCmd, pszDesc, pszCmd); +} + +void crDmpPrintDumpDmlCmd(const char* pszDesc, const void *pvData, uint32_t width, uint32_t height, uint32_t bpp, uint32_t pitch) +{ + char Cmd[1024]; + sprintf(Cmd, "!vbvdbg.ms 0x%p 0n%d 0n%d 0n%d 0n%d", pvData, width, height, bpp, pitch); + crDmpPrintDmlCmd(pszDesc, Cmd); +} + +DECLCALLBACK(void) crDmpDumpImgDmlBreak(struct CR_DUMPER * pDumper, CR_BLITTER_IMG *pImg, const char*pszEntryDesc) +{ + crDmpPrintDumpDmlCmd(pszEntryDesc, pImg->pvData, pImg->width, pImg->height, pImg->bpp, pImg->pitch); + RT_BREAKPOINT(); +} + +DECLCALLBACK(void) crDmpDumpStrDbgPrint(struct CR_DUMPER * pDumper, const char*pszStr) +{ + crDmpPrint("%s\n", pszStr); +} +#endif + +static void crDmpHtmlDumpStrExact(struct CR_HTML_DUMPER * pDumper, const char *pszStr) +{ + fprintf(pDumper->pFile, "%s", pszStr); + fflush(pDumper->pFile); +} + +static DECLCALLBACK(void) crDmpHtmlDumpStr(struct CR_DUMPER * pDumper, const char*pszStr) +{ + CR_HTML_DUMPER * pHtmlDumper = (CR_HTML_DUMPER*)pDumper; + fprintf(pHtmlDumper->pFile, "<pre>%s</pre>\n", pszStr); + fflush(pHtmlDumper->pFile); +} + +static DECLCALLBACK(void) crDmpHtmlDumpImg(struct CR_DUMPER * pDumper, CR_BLITTER_IMG *pImg, const char*pszEntryDesc) +{ + CR_HTML_DUMPER * pHtmlDumper = (CR_HTML_DUMPER*)pDumper; + char szBuffer[4096] = {0}; + size_t cbWritten = RTStrPrintf(szBuffer, sizeof(szBuffer), "%s/", pHtmlDumper->pszDir); + char *pszFileName = szBuffer + cbWritten; + RTStrPrintf(pszFileName, sizeof(szBuffer) - cbWritten, "img%d.bmp", ++pHtmlDumper->cImg); + crDmpImgBmp(pImg, szBuffer); + fprintf(pHtmlDumper->pFile, "<a href=\"%s\"><pre>%s</pre><img src=\"%s\" alt=\"%s\" width=\"150\" height=\"100\" /></a><br>\n", + pszFileName, pszEntryDesc, pszFileName, pszEntryDesc); + fflush(pHtmlDumper->pFile); +} + +static void crDmpHtmlPrintHeader(struct CR_HTML_DUMPER * pDumper) +{ + fprintf(pDumper->pFile, "<html><body>\n"); + fflush(pDumper->pFile); +} + +static void crDmpHtmlPrintFooter(struct CR_HTML_DUMPER * pDumper) +{ + fprintf(pDumper->pFile, "</body></html>\n"); + fflush(pDumper->pFile); +} + +DECLEXPORT(bool) crDmpHtmlIsInited(struct CR_HTML_DUMPER * pDumper) +{ + return !!pDumper->pFile; +} + +DECLEXPORT(void) crDmpHtmlTerm(struct CR_HTML_DUMPER * pDumper) +{ + crDmpHtmlPrintFooter(pDumper); + fclose (pDumper->pFile); + pDumper->pFile = NULL; +} + +DECLEXPORT(int) crDmpHtmlInit(struct CR_HTML_DUMPER * pDumper, const char *pszDir, const char *pszFile) +{ + int rc = VERR_NO_MEMORY; + pDumper->Base.pfnDumpImg = crDmpHtmlDumpImg; + pDumper->Base.pfnDumpStr = crDmpHtmlDumpStr; + pDumper->cImg = 0; + pDumper->pszDir = crStrdup(pszDir); + if (pDumper->pszDir) + { + pDumper->pszFile = crStrdup(pszFile); + if (pDumper->pszFile) + { + char szBuffer[4096] = {0}; + RTStrPrintf(szBuffer, sizeof(szBuffer), "%s/%s", pszDir, pszFile); + + pDumper->pszFile = crStrdup(pszFile); + pDumper->pFile = fopen(szBuffer, "w"); + if (pDumper->pFile) + { + crDmpHtmlPrintHeader(pDumper); + return VINF_SUCCESS; + } + else + { + crWarning("open failed"); + rc = VERR_OPEN_FAILED; + } + crFree((void*)pDumper->pszFile); + } + else + { + crWarning("open failed"); + } + crFree((void*)pDumper->pszDir); + } + else + { + crWarning("open failed"); + } + return rc; +} + +DECLEXPORT(int) crDmpHtmlInitV(struct CR_HTML_DUMPER * pDumper, const char *pszDir, const char *pszFile, va_list pArgList) +{ + char szBuffer[4096] = {0}; + vsprintf_s(szBuffer, sizeof (szBuffer), pszFile, pArgList); + return crDmpHtmlInit(pDumper, pszDir, szBuffer); +} + +DECLEXPORT(int) crDmpHtmlInitF(struct CR_HTML_DUMPER * pDumper, const char *pszDir, const char *pszFile, ...) +{ + int rc; + va_list pArgList; + va_start(pArgList, pszFile); + rc = crDmpHtmlInitV(pDumper, pszDir, pszFile, pArgList); + va_end(pArgList); + return rc; +} + +#endif diff --git a/src/VBox/GuestHost/OpenGL/state_tracker/dump_gen.py b/src/VBox/GuestHost/OpenGL/state_tracker/dump_gen.py new file mode 100644 index 00000000..7103ed4e --- /dev/null +++ b/src/VBox/GuestHost/OpenGL/state_tracker/dump_gen.py @@ -0,0 +1,257 @@ +import sys + +import apiutil + +import sys, re, string + + +line_re = re.compile(r'^(\S+)\s+(GL_\S+)\s+(.*)\s*$') +extensions_line_re = re.compile(r'^(\S+)\s+(GL_\S+)\s(\S+)\s+(.*)\s*$') + +params = {} +extended_params = {} + +input = open( sys.argv[2]+"/state_isenabled.txt", 'r' ) +for line in input.readlines(): + match = line_re.match( line ) + if match: + type = match.group(1) + pname = match.group(2) + fields = string.split( match.group(3) ) + params[pname] = ( type, fields ) + +input = open( sys.argv[2]+"/state_extensions_isenabled.txt", 'r' ) +for line in input.readlines(): + match = extensions_line_re.match( line ) + if match: + type = match.group(1) + pname = match.group(2) + ifdef = match.group(3) + fields = string.split( match.group(4) ) + extended_params[pname] = ( type, ifdef, fields ) + + +apiutil.CopyrightC() + +print """#include "cr_blitter.h" +#include "cr_spu.h" +#include "chromium.h" +#include "cr_error.h" +#include "cr_net.h" +#include "cr_rand.h" +#include "cr_mem.h" +#include "cr_string.h" +#include <cr_dump.h> +#include "cr_pixeldata.h" + +#include <iprt/cdefs.h> +#include <iprt/types.h> +#include <iprt/mem.h> + +#include <stdio.h> + +#ifdef VBOX_WITH_CRDUMPER +""" + +from get_sizes import *; + +getprops = apiutil.ParamProps("GetDoublev") +enableprops = apiutil.ParamProps("Enable") + +#print "//missing get props:" +#for prop in getprops: +# try: +# tmp = num_get_values[prop] +# except KeyError: +# try: +# keyvalues = extensions_num_get_values[prop] +# except KeyError: +# print "//%s" % prop +# +print """ +static void crRecDumpPrintVal(CR_DUMPER *pDumper, struct nv_struct *pDesc, float *pfData) +{ + char aBuf[4096]; + crDmpFormatArray(aBuf, sizeof (aBuf), "%f", sizeof (float), pfData, pDesc->num_values); + crDmpStrF(pDumper, "%s = %s;", pDesc->pszName, aBuf); +} + + +void crRecDumpGlGetState(CR_RECORDER *pRec, CRContext *ctx) +{ + float afData[CR_MAX_GET_VALUES]; + struct nv_struct *pDesc; + + for (pDesc = num_values_array; pDesc->num_values != 0 ; pDesc++) + { + memset(afData, 0, sizeof(afData)); + pRec->pDispatch->GetFloatv(pDesc->pname, afData); + crRecDumpPrintVal(pRec->pDumper, pDesc, afData); + } +} + +void crRecDumpGlEnableState(CR_RECORDER *pRec, CRContext *ctx) +{ + GLboolean fEnabled; +""" +keys = params.keys() +keys.sort(); + +for pname in keys: + print "\tfEnabled = pRec->pDispatch->IsEnabled(%s);" % pname + print "\tcrDmpStrF(pRec->pDumper, \"%s = %%d;\", fEnabled);" % pname + +keys = extended_params.keys(); +keys.sort() + +for pname in keys: + (srctype,ifdef,fields) = extended_params[pname] + ext = ifdef[3:] # the extension name with the "GL_" prefix removed + ext = ifdef + print '#ifdef CR_%s' % ext + print "\tfEnabled = pRec->pDispatch->IsEnabled(%s);" % pname + print "\tcrDmpStrF(pRec->pDumper, \"%s = %%d;\", fEnabled);" % pname + print '#endif /* CR_%s */' % ext + +#print "//missing enable props:" +#for prop in enableprops: +# try: +# keyvalues = params[prop] +# except KeyError: +# try: +# keyvalues = extended_params[prop] +# except KeyError: +# print "//%s" % prop +# +print """ +} +#endif +""" + +texenv_mappings = { + 'GL_TEXTURE_ENV' : [ + 'GL_TEXTURE_ENV_MODE', + 'GL_TEXTURE_ENV_COLOR', + 'GL_COMBINE_RGB', + 'GL_COMBINE_ALPHA', + 'GL_RGB_SCALE', + 'GL_ALPHA_SCALE', + 'GL_SRC0_RGB', + 'GL_SRC1_RGB', + 'GL_SRC2_RGB', + 'GL_SRC0_ALPHA', + 'GL_SRC1_ALPHA', + 'GL_SRC2_ALPHA' + ], + 'GL_TEXTURE_FILTER_CONTROL' : [ + 'GL_TEXTURE_LOD_BIAS' + ], + 'GL_POINT_SPRITE' : [ + 'GL_COORD_REPLACE' + ] +} + +texgen_coords = [ + 'GL_S', + 'GL_T', + 'GL_R', + 'GL_Q' +] + +texgen_names = [ + 'GL_TEXTURE_GEN_MODE', + 'GL_OBJECT_PLANE', + 'GL_EYE_PLANE' +] + +texparam_names = [ + 'GL_TEXTURE_MAG_FILTER', + 'GL_TEXTURE_MIN_FILTER', + 'GL_TEXTURE_MIN_LOD', + 'GL_TEXTURE_MAX_LOD', + 'GL_TEXTURE_BASE_LEVEL', + 'GL_TEXTURE_MAX_LEVEL', + 'GL_TEXTURE_WRAP_S', + 'GL_TEXTURE_WRAP_T', + 'GL_TEXTURE_WRAP_R', + 'GL_TEXTURE_BORDER_COLOR', + 'GL_TEXTURE_PRIORITY', + 'GL_TEXTURE_RESIDENT', + 'GL_TEXTURE_COMPARE_MODE', + 'GL_TEXTURE_COMPARE_FUNC', + 'GL_DEPTH_TEXTURE_MODE', + 'GL_GENERATE_MIPMAP' +] + +print """ +void crRecDumpTexParam(CR_RECORDER *pRec, CRContext *ctx, GLenum enmTarget) +{ + GLfloat afBuf[4]; + char acBuf[1024]; + unsigned int cComponents; + crDmpStrF(pRec->pDumper, "==TEX_PARAM for target(0x%x)==", enmTarget); +""" +for pname in texparam_names: + print "\tcComponents = crStateHlpComponentsCount(%s);" % pname + print "\tAssert(cComponents <= RT_ELEMENTS(afBuf));" + print "\tmemset(afBuf, 0, sizeof (afBuf));" + print "\tpRec->pDispatch->GetTexParameterfv(enmTarget, %s, afBuf);" % pname + print "\tcrDmpFormatArray(acBuf, sizeof (acBuf), \"%f\", sizeof (afBuf[0]), afBuf, cComponents);" + print "\tcrDmpStrF(pRec->pDumper, \"%s = %%s;\", acBuf);" % pname +print """ + crDmpStrF(pRec->pDumper, "==Done TEX_PARAM for target(0x%x)==", enmTarget); +} +""" + +print """ +void crRecDumpTexEnv(CR_RECORDER *pRec, CRContext *ctx) +{ + GLfloat afBuf[4]; + char acBuf[1024]; + unsigned int cComponents; + crDmpStrF(pRec->pDumper, "==TEX_ENV=="); +""" + +keys = texenv_mappings.keys() +keys.sort(); + +for target in keys: + print "\tcrDmpStrF(pRec->pDumper, \"===%s===\");" % target + values = texenv_mappings[target] + for pname in values: + print "\tcComponents = crStateHlpComponentsCount(%s);" % pname + print "\tAssert(cComponents <= RT_ELEMENTS(afBuf));" + print "\tmemset(afBuf, 0, sizeof (afBuf));" + print "\tpRec->pDispatch->GetTexEnvfv(%s, %s, afBuf);" % (target, pname) + print "\tcrDmpFormatArray(acBuf, sizeof (acBuf), \"%f\", sizeof (afBuf[0]), afBuf, cComponents);" + print "\tcrDmpStrF(pRec->pDumper, \"%s = %%s;\", acBuf);" % pname + print "\tcrDmpStrF(pRec->pDumper, \"===Done %s===\");" % target +print """ + crDmpStrF(pRec->pDumper, "==Done TEX_ENV=="); +} +""" + + +print """ +void crRecDumpTexGen(CR_RECORDER *pRec, CRContext *ctx) +{ + GLdouble afBuf[4]; + char acBuf[1024]; + unsigned int cComponents; + crDmpStrF(pRec->pDumper, "==TEX_GEN=="); +""" + +for coord in texgen_coords: + print "\tcrDmpStrF(pRec->pDumper, \"===%s===\");" % coord + for pname in texgen_names: + print "\tcComponents = crStateHlpComponentsCount(%s);" % pname + print "\tAssert(cComponents <= RT_ELEMENTS(afBuf));" + print "\tmemset(afBuf, 0, sizeof (afBuf));" + print "\tpRec->pDispatch->GetTexGendv(%s, %s, afBuf);" % (coord, pname) + print "\tcrDmpFormatArray(acBuf, sizeof (acBuf), \"%f\", sizeof (afBuf[0]), afBuf, cComponents);" + print "\tcrDmpStrF(pRec->pDumper, \"%s = %%s;\", acBuf);" % pname + print "\tcrDmpStrF(pRec->pDumper, \"===Done %s===\");" % coord +print """ + crDmpStrF(pRec->pDumper, "==Done TEX_GEN=="); +} +""" diff --git a/src/VBox/GuestHost/OpenGL/state_tracker/get_components.py b/src/VBox/GuestHost/OpenGL/state_tracker/get_components.py new file mode 100644 index 00000000..c9a32452 --- /dev/null +++ b/src/VBox/GuestHost/OpenGL/state_tracker/get_components.py @@ -0,0 +1,144 @@ +# Copyright (c) 2001, Stanford University +# All rights reserved. +# +# See the file LICENSE.txt for information on redistributing this software. + +num_components = { + 'GL_AMBIENT' : 4, + 'GL_DIFFUSE' : 4, + 'GL_SPECULAR' : 4, + 'GL_POSITION' : 4, + 'GL_SPOT_DIRECTION' : 3, + 'GL_SPOT_EXPONENT' : 1, + 'GL_SPOT_CUTOFF' : 1, + 'GL_CONSTANT_ATTENUATION' : 1, + 'GL_LINEAR_ATTENUATION' : 1, + 'GL_QUADRATIC_ATTENUATION' : 1, + 'GL_EMISSION' : 4, + 'GL_SHININESS' : 1, + 'GL_COLOR_INDEXES' : 3, + 'GL_TEXTURE_ENV_MODE' : 1, + 'GL_TEXTURE_ENV_COLOR' : 4, + 'GL_TEXTURE_GEN_MODE' : 1, + 'GL_OBJECT_PLANE' : 4, + 'GL_EYE_PLANE' : 4, + 'GL_TEXTURE_MAG_FILTER' : 1, + 'GL_TEXTURE_MIN_FILTER' : 1, + 'GL_TEXTURE_WRAP_S' : 1, + 'GL_TEXTURE_WRAP_T' : 1, + 'GL_TEXTURE_BORDER_COLOR' : 4, + 'GL_TEXTURE_WIDTH': 1, + 'GL_TEXTURE_HEIGHT': 1, + 'GL_TEXTURE_DEPTH': 1, + # 'GL_TEXTURE_INTERNAL_FORMAT': 1, THIS CONFLICTS WITH GL_TEXTURE_COMPONENTS! + 'GL_TEXTURE_BORDER': 1, + 'GL_TEXTURE_RED_SIZE': 1, + 'GL_TEXTURE_GREEN_SIZE': 1, + 'GL_TEXTURE_BLUE_SIZE': 1, + 'GL_TEXTURE_ALPHA_SIZE': 1, + 'GL_TEXTURE_LUMINANCE_SIZE': 1, + 'GL_TEXTURE_INTENSITY_SIZE': 1, + 'GL_TEXTURE_COMPONENTS': 1, + 'GL_TEXTURE_RESIDENT': 1 +} + +num_extended_components = { + 'GL_TEXTURE_MAX_ANISOTROPY_EXT': ( 1, 'CR_EXT_texture_filter_anisotropic' ), + 'GL_TEXTURE_WRAP_R': ( 1, 'CR_OPENGL_VERSION_1_2'), + 'GL_TEXTURE_PRIORITY': ( 1, 'CR_OPENGL_VERSION_1_2'), + 'GL_TEXTURE_MIN_LOD': ( 1, 'CR_OPENGL_VERSION_1_2'), + 'GL_TEXTURE_MAX_LOD': ( 1, 'CR_OPENGL_VERSION_1_2'), + 'GL_TEXTURE_BASE_LEVEL': ( 1, 'CR_OPENGL_VERSION_1_2'), + 'GL_TEXTURE_MAX_LEVEL': ( 1, 'CR_OPENGL_VERSION_1_2'), + 'GL_COMBINER_INPUT_NV': ( 1, 'CR_NV_register_combiners'), + 'GL_COMBINER_MAPPING_NV': ( 1, 'CR_NV_register_combiners'), + 'GL_COMBINER_COMPONENT_USAGE_NV': ( 1, 'CR_NV_register_combiners'), + 'GL_COMBINER_AB_DOT_PRODUCT_NV': ( 1, 'CR_NV_register_combiners'), + 'GL_COMBINER_CD_DOT_PRODUCT_NV': ( 1, 'CR_NV_register_combiners'), + 'GL_COMBINER_MUX_SUM_NV': ( 1, 'CR_NV_register_combiners'), + 'GL_COMBINER_SCALE_NV': ( 1, 'CR_NV_register_combiners'), + 'GL_COMBINER_BIAS_NV': ( 1, 'CR_NV_register_combiners'), + 'GL_COMBINER_AB_OUTPUT_NV': ( 1, 'CR_NV_register_combiners'), + 'GL_COMBINER_CD_OUTPUT_NV': ( 1, 'CR_NV_register_combiners'), + 'GL_COMBINER_SUM_OUTPUT_NV': ( 1, 'CR_NV_register_combiners'), + 'GL_COMBINER_INPUT_NV': ( 1, 'CR_NV_register_combiners'), + 'GL_COMBINER_INPUT_NV': ( 1, 'CR_NV_register_combiners'), + 'GL_COMBINER_MAPPING_NV': ( 1, 'CR_NV_register_combiners'), + 'GL_COMBINER_COMPONENT_USAGE_NV': ( 1, 'CR_NV_register_combiners'), + 'GL_CONSTANT_COLOR0_NV': ( 4, 'CR_NV_register_combiners'), + 'GL_CONSTANT_COLOR1_NV': ( 4, 'CR_NV_register_combiners'), + 'GL_COMBINE_RGB_ARB': (1, 'CR_ARB_texture_env_combine'), + 'GL_COMBINE_ALPHA_ARB': (1, 'CR_ARB_texture_env_combine'), + 'GL_SOURCE0_RGB_ARB': (1, 'CR_ARB_texture_env_combine'), + 'GL_SOURCE1_RGB_ARB': (1, 'CR_ARB_texture_env_combine'), + 'GL_SOURCE2_RGB_ARB': (1, 'CR_ARB_texture_env_combine'), + 'GL_SOURCE0_ALPHA_ARB': (1, 'CR_ARB_texture_env_combine'), + 'GL_SOURCE1_ALPHA_ARB': (1, 'CR_ARB_texture_env_combine'), + 'GL_SOURCE2_ALPHA_ARB': (1, 'CR_ARB_texture_env_combine'), + 'GL_OPERAND0_RGB_ARB': (1, 'CR_ARB_texture_env_combine'), + 'GL_OPERAND1_RGB_ARB': (1, 'CR_ARB_texture_env_combine'), + 'GL_OPERAND2_RGB_ARB': (1, 'CR_ARB_texture_env_combine'), + 'GL_OPERAND0_ALPHA_ARB': (1, 'CR_ARB_texture_env_combine'), + 'GL_OPERAND1_ALPHA_ARB': (1, 'CR_ARB_texture_env_combine'), + 'GL_OPERAND2_ALPHA_ARB': (1, 'CR_ARB_texture_env_combine'), + 'GL_RGB_SCALE_ARB': (1, 'CR_ARB_texture_env_combine'), + 'GL_ALPHA_SCALE': (1, 'CR_ARB_texture_env_combine'), + 'GL_DEPTH_TEXTURE_MODE_ARB': (1, 'CR_ARB_depth_texture'), + 'GL_TEXTURE_DEPTH_SIZE_ARB': (1, 'CR_ARB_depth_texture'), + 'GL_TEXTURE_COMPARE_MODE_ARB': (1, 'CR_ARB_shadow'), + 'GL_TEXTURE_COMPARE_FUNC_ARB': (1, 'CR_ARB_shadow'), + 'GL_TEXTURE_COMPARE_FAIL_VALUE_ARB': (1, 'CR_ARB_shadow_ambient'), + 'GL_GENERATE_MIPMAP_SGIS': (1, 'CR_SGIS_generate_mipmap'), + 'GL_TEXTURE_LOD_BIAS_EXT': (1, 'CR_EXT_texture_lod_bias'), + 'GL_VERTEX_ATTRIB_ARRAY_POINTER_ARB': (1, 'CR_any_vertex_program'), + 'GL_CURRENT_VERTEX_ATTRIB_ARB': (4, 'CR_any_vertex_program'), + 'GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB': (1, 'CR_any_vertex_program'), + 'GL_VERTEX_ATTRIB_ARRAY_SIZE_ARB': (1, 'CR_any_vertex_program'), + 'GL_VERTEX_ATTRIB_ARRAY_STRIDE_ARB': (1, 'CR_any_vertex_program'), + 'GL_VERTEX_ATTRIB_ARRAY_TYPE_ARB': (1, 'CR_any_vertex_program'), + 'GL_VERTEX_ATTRIB_ARRAY_NORMALIZED_ARB': (1, 'CR_any_vertex_program'), + 'GL_TRACK_MATRIX_NV': (24, 'CR_any_vertex_program'), + 'GL_TRACK_MATRIX_TRANSFORM_NV': (24, 'CR_any_vertex_program'), + 'GL_BUFFER_SIZE_ARB': (1, 'CR_ARB_vertex_buffer_object'), + 'GL_BUFFER_USAGE_ARB': (1, 'CR_ARB_vertex_buffer_object'), + 'GL_BUFFER_ACCESS_ARB': (1, 'CR_ARB_vertex_buffer_object'), + 'GL_BUFFER_MAPPED_ARB': (1, 'CR_ARB_vertex_buffer_object'), + 'GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB': (1, 'CR_ARB_vertex_buffer_object'), + 'GL_QUERY_COUNTER_BITS_ARB': (1, 'CR_ARB_occlusion_query'), + 'GL_QUERY_RESULT_AVAILABLE_ARB': (1, 'CR_ARB_occlusion_query'), + 'GL_QUERY_RESULT_ARB': (1, 'CR_ARB_occlusion_query'), + 'GL_CURRENT_QUERY_ARB': (1, 'CR_ARB_occlusion_query'), + 'GL_TEXTURE_COMPRESSED_IMAGE_SIZE': (1, 'CR_ARB_texture_compression'), + 'GL_TEXTURE_COMPRESSED': (1, 'CR_ARB_texture_compression'), + 'GL_COORD_REPLACE_ARB': (1, 'CR_ARB_point_sprite'), +} + +print """unsigned int crStateHlpComponentsCount( GLenum pname ) +{ + switch( pname ) + { +""" +comps = num_components.keys(); +comps.sort(); +for comp in comps: + print '\t\t\tcase %s: return %d;' % (comp,num_components[comp]) + +comps = num_extended_components.keys(); +comps.sort(); +for comp in comps: + (nc, ifdef) = num_extended_components[comp] + print '#ifdef %s' % ifdef + print '\t\t\tcase %s: return %d;' % (comp,nc) + print '#endif /* %s */' % ifdef + +print """ + default: + crError( "Unknown parameter name in crStateHlpComponentsCount: %d", (int) pname ); + break; + } + /* NOTREACHED */ + return 0; +} +""" + + diff --git a/src/VBox/GuestHost/OpenGL/state_tracker/state.h b/src/VBox/GuestHost/OpenGL/state_tracker/state.h index c94525a1..07429aa9 100644 --- a/src/VBox/GuestHost/OpenGL/state_tracker/state.h +++ b/src/VBox/GuestHost/OpenGL/state_tracker/state.h @@ -9,6 +9,16 @@ #include "cr_glstate.h" +#define CRSTATE_CHECKERR_RET(expr, result, message, ret) \ + if (expr) { \ + crStateError(__LINE__, __FILE__, result, message); \ + return ret; \ + } + +#define CRSTATE_NO_RETURN + +#define CRSTATE_CHECKERR(expr, result, message) CRSTATE_CHECKERR_RET(expr, result, message, CRSTATE_NO_RETURN) + typedef struct _crCheckIDHWID { GLuint id, hwid; } crCheckIDHWID_t; @@ -33,6 +43,11 @@ extern CRContext *__currentContext; #define GetCurrentContext() __currentContext #endif +extern GLboolean g_bVBoxEnableDiffOnMakeCurrent; + +extern CRContext *g_pAvailableContexts[CR_MAX_CONTEXTS]; +extern uint32_t g_cContexts; + extern void crStateTextureInitTextureObj (CRContext *ctx, CRTextureObj *tobj, GLuint name, GLenum target); extern void crStateTextureInitTextureFormat( CRTextureLevel *tl, GLenum internalFormat ); @@ -55,10 +70,10 @@ void crStateClientDiff(CRClientBits *cb, CRbitvalue *bitID, CRContext *from, CRC void crStateClientSwitch(CRClientBits *cb, CRbitvalue *bitID, CRContext *from, CRContext *to); -void crStateGetTextureObjectAndImage(CRContext *g, GLenum texTarget, GLint level, - CRTextureObj **obj, CRTextureLevel **img); - void crStateFreeBufferObject(void *data); void crStateFreeFBO(void *data); void crStateFreeRBO(void *data); + +void crStateGenNames(CRContext *g, CRHashTable *table, GLsizei n, GLuint *names); +void crStateRegNames(CRContext *g, CRHashTable *table, GLsizei n, GLuint *names); #endif diff --git a/src/VBox/GuestHost/OpenGL/state_tracker/state_attrib.c b/src/VBox/GuestHost/OpenGL/state_tracker/state_attrib.c index 836c2221..68cbdb62 100644 --- a/src/VBox/GuestHost/OpenGL/state_tracker/state_attrib.c +++ b/src/VBox/GuestHost/OpenGL/state_tracker/state_attrib.c @@ -439,14 +439,17 @@ void STATE_APIENTRY crStatePushAttrib(GLbitfield mask) if (mask & GL_STENCIL_BUFFER_BIT) { a->stencilBufferStack[a->stencilBufferStackDepth].stencilTest = g->stencil.stencilTest; - a->stencilBufferStack[a->stencilBufferStackDepth].func = g->stencil.func; - a->stencilBufferStack[a->stencilBufferStackDepth].mask = g->stencil.mask; - a->stencilBufferStack[a->stencilBufferStackDepth].ref = g->stencil.ref; - a->stencilBufferStack[a->stencilBufferStackDepth].fail = g->stencil.fail; - a->stencilBufferStack[a->stencilBufferStackDepth].passDepthFail = g->stencil.passDepthFail; - a->stencilBufferStack[a->stencilBufferStackDepth].passDepthPass = g->stencil.passDepthPass; a->stencilBufferStack[a->stencilBufferStackDepth].clearValue = g->stencil.clearValue; a->stencilBufferStack[a->stencilBufferStackDepth].writeMask = g->stencil.writeMask; + for (i = 0; i < CRSTATE_STENCIL_BUFFER_COUNT; ++i) + { + a->stencilBufferStack[a->stencilBufferStackDepth].buffers[i].func = g->stencil.buffers[i].func; + a->stencilBufferStack[a->stencilBufferStackDepth].buffers[i].mask = g->stencil.buffers[i].mask; + a->stencilBufferStack[a->stencilBufferStackDepth].buffers[i].ref = g->stencil.buffers[i].ref; + a->stencilBufferStack[a->stencilBufferStackDepth].buffers[i].fail = g->stencil.buffers[i].fail; + a->stencilBufferStack[a->stencilBufferStackDepth].buffers[i].passDepthFail = g->stencil.buffers[i].passDepthFail; + a->stencilBufferStack[a->stencilBufferStackDepth].buffers[i].passDepthPass = g->stencil.buffers[i].passDepthPass; + } a->stencilBufferStackDepth++; } if (mask & GL_TEXTURE_BIT) @@ -1033,20 +1036,28 @@ void STATE_APIENTRY crStatePopAttrib(void) } a->stencilBufferStackDepth--; g->stencil.stencilTest = a->stencilBufferStack[a->stencilBufferStackDepth].stencilTest; - g->stencil.func = a->stencilBufferStack[a->stencilBufferStackDepth].func; - g->stencil.mask = a->stencilBufferStack[a->stencilBufferStackDepth].mask; - g->stencil.ref = a->stencilBufferStack[a->stencilBufferStackDepth].ref; - g->stencil.fail = a->stencilBufferStack[a->stencilBufferStackDepth].fail; - g->stencil.passDepthFail = a->stencilBufferStack[a->stencilBufferStackDepth].passDepthFail; - g->stencil.passDepthPass = a->stencilBufferStack[a->stencilBufferStackDepth].passDepthPass; g->stencil.clearValue = a->stencilBufferStack[a->stencilBufferStackDepth].clearValue; g->stencil.writeMask = a->stencilBufferStack[a->stencilBufferStackDepth].writeMask; + for (i = 0; i < CRSTATE_STENCIL_BUFFER_COUNT; ++i) + { + g->stencil.buffers[i].func = a->stencilBufferStack[a->stencilBufferStackDepth].buffers[i].func; + g->stencil.buffers[i].mask = a->stencilBufferStack[a->stencilBufferStackDepth].buffers[i].mask; + g->stencil.buffers[i].ref = a->stencilBufferStack[a->stencilBufferStackDepth].buffers[i].ref; + g->stencil.buffers[i].fail = a->stencilBufferStack[a->stencilBufferStackDepth].buffers[i].fail; + g->stencil.buffers[i].passDepthFail = a->stencilBufferStack[a->stencilBufferStackDepth].buffers[i].passDepthFail; + g->stencil.buffers[i].passDepthPass = a->stencilBufferStack[a->stencilBufferStackDepth].buffers[i].passDepthPass; + } + DIRTY(sb->stencil.dirty, g->neg_bitid); DIRTY(sb->stencil.enable, g->neg_bitid); - DIRTY(sb->stencil.func, g->neg_bitid); - DIRTY(sb->stencil.op, g->neg_bitid); DIRTY(sb->stencil.clearValue, g->neg_bitid); DIRTY(sb->stencil.writeMask, g->neg_bitid); + + for (i = 0; i < CRSTATE_STENCIL_BUFFER_REF_COUNT; ++i) + { + DIRTY(sb->stencil.bufferRefs[i].func, g->neg_bitid); + DIRTY(sb->stencil.bufferRefs[i].op, g->neg_bitid); + } } if (mask & GL_TEXTURE_BIT) { diff --git a/src/VBox/GuestHost/OpenGL/state_tracker/state_bits_globalop.h b/src/VBox/GuestHost/OpenGL/state_tracker/state_bits_globalop.h new file mode 100644 index 00000000..351a85a3 --- /dev/null +++ b/src/VBox/GuestHost/OpenGL/state_tracker/state_bits_globalop.h @@ -0,0 +1,338 @@ +/* $Id: state_bits_globalop.h $ */ + +/** @file + * Global State bits operation + */ + +/* + * Copyright (C) 2013 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +#include <iprt/cdefs.h> + +#include <cr_version.h> + +#ifndef CRSTATE_BITS_OP +# error "CRSTATE_BITS_OP must be defined!" +#endif + +#define _CRSTATE_BITS_OP_SIZEOF(_val) CRSTATE_BITS_OP(_val, RT_SIZEOFMEMB(CRStateBits, _val)) + +#ifndef CRSTATE_BITS_OP_VERSION +# define CRSTATE_BITS_OP_VERSION SHCROGL_SSM_VERSION +#endif + +do { +int i; +#ifdef _CRSTATE_BITS_OP_STENCIL_V_33 +# error "_CRSTATE_BITS_OP_STENCIL_V_33 must no be defined!" +#endif +#if CRSTATE_BITS_OP_VERSION < SHCROGL_SSM_VERSION_WITH_FIXED_STENCIL +# define _CRSTATE_BITS_OP_STENCIL_V_33 +#endif + +#ifdef _CRSTATE_BITS_OP_STENCIL_V_33 +# ifndef CRSTATE_BITS_OP_STENCIL_OP_V_33 +# error "CRSTATE_BITS_OP_STENCIL_OP_V_33 undefined!" +# endif +# ifndef CRSTATE_BITS_OP_STENCIL_FUNC_V_33 +# error "CRSTATE_BITS_OP_STENCIL_FUNC_V_33 undefined!" +# endif +#endif + +_CRSTATE_BITS_OP_SIZEOF(attrib.dirty); + +_CRSTATE_BITS_OP_SIZEOF(buffer.dirty); +_CRSTATE_BITS_OP_SIZEOF(buffer.enable); +_CRSTATE_BITS_OP_SIZEOF(buffer.alphaFunc); +_CRSTATE_BITS_OP_SIZEOF(buffer.depthFunc); +_CRSTATE_BITS_OP_SIZEOF(buffer.blendFunc); +_CRSTATE_BITS_OP_SIZEOF(buffer.logicOp); +_CRSTATE_BITS_OP_SIZEOF(buffer.indexLogicOp); +_CRSTATE_BITS_OP_SIZEOF(buffer.drawBuffer); +_CRSTATE_BITS_OP_SIZEOF(buffer.readBuffer); +_CRSTATE_BITS_OP_SIZEOF(buffer.indexMask); +_CRSTATE_BITS_OP_SIZEOF(buffer.colorWriteMask); +_CRSTATE_BITS_OP_SIZEOF(buffer.clearColor); +_CRSTATE_BITS_OP_SIZEOF(buffer.clearIndex); +_CRSTATE_BITS_OP_SIZEOF(buffer.clearDepth); +_CRSTATE_BITS_OP_SIZEOF(buffer.clearAccum); +_CRSTATE_BITS_OP_SIZEOF(buffer.depthMask); +#ifdef CR_EXT_blend_color +_CRSTATE_BITS_OP_SIZEOF(buffer.blendColor); +#endif +#if defined(CR_EXT_blend_minmax) || defined(CR_EXT_blend_subtract) || defined(CR_EXT_blend_logic_op) +_CRSTATE_BITS_OP_SIZEOF(buffer.blendEquation); +#endif +#if defined(CR_EXT_blend_func_separate) +_CRSTATE_BITS_OP_SIZEOF(buffer.blendFuncSeparate); +#endif + +#ifdef CR_ARB_vertex_buffer_object +_CRSTATE_BITS_OP_SIZEOF(bufferobject.dirty); +_CRSTATE_BITS_OP_SIZEOF(bufferobject.arrayBinding); +_CRSTATE_BITS_OP_SIZEOF(bufferobject.elementsBinding); +# ifdef CR_ARB_pixel_buffer_object +_CRSTATE_BITS_OP_SIZEOF(bufferobject.packBinding); +_CRSTATE_BITS_OP_SIZEOF(bufferobject.unpackBinding); +# endif +#endif + +_CRSTATE_BITS_OP_SIZEOF(client.dirty); +_CRSTATE_BITS_OP_SIZEOF(client.pack); +_CRSTATE_BITS_OP_SIZEOF(client.unpack); +_CRSTATE_BITS_OP_SIZEOF(client.enableClientState); +_CRSTATE_BITS_OP_SIZEOF(client.clientPointer); +CRSTATE_BITS_OP(client.v, GLCLIENT_BIT_ALLOC*sizeof(CRbitvalue)); +CRSTATE_BITS_OP(client.n, GLCLIENT_BIT_ALLOC*sizeof(CRbitvalue)); +CRSTATE_BITS_OP(client.c, GLCLIENT_BIT_ALLOC*sizeof(CRbitvalue)); +CRSTATE_BITS_OP(client.i, GLCLIENT_BIT_ALLOC*sizeof(CRbitvalue)); +CRSTATE_BITS_OP(client.e, GLCLIENT_BIT_ALLOC*sizeof(CRbitvalue)); +CRSTATE_BITS_OP(client.s, GLCLIENT_BIT_ALLOC*sizeof(CRbitvalue)); +CRSTATE_BITS_OP(client.f, GLCLIENT_BIT_ALLOC*sizeof(CRbitvalue)); +for (i=0; i<CR_MAX_TEXTURE_UNITS; i++) +{ + CRSTATE_BITS_OP(client.t[i], GLCLIENT_BIT_ALLOC*sizeof(CRbitvalue)); +} +#ifdef CR_NV_vertex_program +for (i=0; i<CR_MAX_VERTEX_ATTRIBS; i++) +{ + CRSTATE_BITS_OP(client.a[i], GLCLIENT_BIT_ALLOC*sizeof(CRbitvalue)); +} +#endif + +_CRSTATE_BITS_OP_SIZEOF(current.dirty); +for (i=0; i<CR_MAX_VERTEX_ATTRIBS; i++) +{ + _CRSTATE_BITS_OP_SIZEOF(current.vertexAttrib[i]); +} +_CRSTATE_BITS_OP_SIZEOF(current.edgeFlag); +_CRSTATE_BITS_OP_SIZEOF(current.colorIndex); +_CRSTATE_BITS_OP_SIZEOF(current.rasterPos); + + +_CRSTATE_BITS_OP_SIZEOF(eval.dirty); +for (i=0; i<GLEVAL_TOT; i++) +{ + _CRSTATE_BITS_OP_SIZEOF(eval.eval1D[i]); + _CRSTATE_BITS_OP_SIZEOF(eval.eval2D[i]); + _CRSTATE_BITS_OP_SIZEOF(eval.enable1D[i]); + _CRSTATE_BITS_OP_SIZEOF(eval.enable2D[i]); +} +_CRSTATE_BITS_OP_SIZEOF(eval.enable); +_CRSTATE_BITS_OP_SIZEOF(eval.grid1D); +_CRSTATE_BITS_OP_SIZEOF(eval.grid2D); +#ifdef CR_NV_vertex_program + /*@todo Those seems to be unused? +_CRSTATE_BITS_OP_SIZEOF(eval.enableAttrib1D); +_CRSTATE_BITS_OP_SIZEOF(eval.enableAttrib2D); + */ +#endif + +_CRSTATE_BITS_OP_SIZEOF(feedback.dirty); +_CRSTATE_BITS_OP_SIZEOF(selection.dirty); + +_CRSTATE_BITS_OP_SIZEOF(fog.dirty); +_CRSTATE_BITS_OP_SIZEOF(fog.color); +_CRSTATE_BITS_OP_SIZEOF(fog.index); +_CRSTATE_BITS_OP_SIZEOF(fog.density); +_CRSTATE_BITS_OP_SIZEOF(fog.start); +_CRSTATE_BITS_OP_SIZEOF(fog.end); +_CRSTATE_BITS_OP_SIZEOF(fog.mode); +_CRSTATE_BITS_OP_SIZEOF(fog.enable); +#ifdef CR_NV_fog_distance +_CRSTATE_BITS_OP_SIZEOF(fog.fogDistanceMode); +#endif +#ifdef CR_EXT_fog_coord +_CRSTATE_BITS_OP_SIZEOF(fog.fogCoordinateSource); +#endif + +_CRSTATE_BITS_OP_SIZEOF(hint.dirty); +_CRSTATE_BITS_OP_SIZEOF(hint.perspectiveCorrection); +_CRSTATE_BITS_OP_SIZEOF(hint.pointSmooth); +_CRSTATE_BITS_OP_SIZEOF(hint.lineSmooth); +_CRSTATE_BITS_OP_SIZEOF(hint.polygonSmooth); +_CRSTATE_BITS_OP_SIZEOF(hint.fog); +#ifdef CR_EXT_clip_volume_hint +_CRSTATE_BITS_OP_SIZEOF(hint.clipVolumeClipping); + +#endif +#ifdef CR_ARB_texture_compression +_CRSTATE_BITS_OP_SIZEOF(hint.textureCompression); +#endif +#ifdef CR_SGIS_generate_mipmap +_CRSTATE_BITS_OP_SIZEOF(hint.generateMipmap); +#endif + +_CRSTATE_BITS_OP_SIZEOF(lighting.dirty); +_CRSTATE_BITS_OP_SIZEOF(lighting.shadeModel); +_CRSTATE_BITS_OP_SIZEOF(lighting.colorMaterial); +_CRSTATE_BITS_OP_SIZEOF(lighting.lightModel); +_CRSTATE_BITS_OP_SIZEOF(lighting.material); +_CRSTATE_BITS_OP_SIZEOF(lighting.enable); +for (i=0; i<CR_MAX_LIGHTS; ++i) +{ + _CRSTATE_BITS_OP_SIZEOF(lighting.light[i].dirty); + _CRSTATE_BITS_OP_SIZEOF(lighting.light[i].enable); + _CRSTATE_BITS_OP_SIZEOF(lighting.light[i].ambient); + _CRSTATE_BITS_OP_SIZEOF(lighting.light[i].diffuse); + _CRSTATE_BITS_OP_SIZEOF(lighting.light[i].specular); + _CRSTATE_BITS_OP_SIZEOF(lighting.light[i].position); + _CRSTATE_BITS_OP_SIZEOF(lighting.light[i].attenuation); + _CRSTATE_BITS_OP_SIZEOF(lighting.light[i].spot); +} + +_CRSTATE_BITS_OP_SIZEOF(line.dirty); +_CRSTATE_BITS_OP_SIZEOF(line.enable); +_CRSTATE_BITS_OP_SIZEOF(line.width); +_CRSTATE_BITS_OP_SIZEOF(line.stipple); + +_CRSTATE_BITS_OP_SIZEOF(lists.dirty); +_CRSTATE_BITS_OP_SIZEOF(lists.base); + +_CRSTATE_BITS_OP_SIZEOF(multisample.dirty); +_CRSTATE_BITS_OP_SIZEOF(multisample.enable); +_CRSTATE_BITS_OP_SIZEOF(multisample.sampleAlphaToCoverage); +_CRSTATE_BITS_OP_SIZEOF(multisample.sampleAlphaToOne); +_CRSTATE_BITS_OP_SIZEOF(multisample.sampleCoverage); +_CRSTATE_BITS_OP_SIZEOF(multisample.sampleCoverageValue); + +#if CR_ARB_occlusion_query +_CRSTATE_BITS_OP_SIZEOF(occlusion.dirty); +#endif + +_CRSTATE_BITS_OP_SIZEOF(pixel.dirty); +_CRSTATE_BITS_OP_SIZEOF(pixel.transfer); +_CRSTATE_BITS_OP_SIZEOF(pixel.zoom); +_CRSTATE_BITS_OP_SIZEOF(pixel.maps); + +_CRSTATE_BITS_OP_SIZEOF(point.dirty); +_CRSTATE_BITS_OP_SIZEOF(point.enableSmooth); +_CRSTATE_BITS_OP_SIZEOF(point.size); +#ifdef CR_ARB_point_parameters +_CRSTATE_BITS_OP_SIZEOF(point.minSize); +_CRSTATE_BITS_OP_SIZEOF(point.maxSize); +_CRSTATE_BITS_OP_SIZEOF(point.fadeThresholdSize); +_CRSTATE_BITS_OP_SIZEOF(point.distanceAttenuation); +#endif +#ifdef CR_ARB_point_sprite +_CRSTATE_BITS_OP_SIZEOF(point.enableSprite); +for (i=0; i<CR_MAX_TEXTURE_UNITS; ++i) +{ + _CRSTATE_BITS_OP_SIZEOF(point.coordReplacement[i]); +} +#endif +#if CRSTATE_BITS_OP_VERSION >= SHCROGL_SSM_VERSION_WITH_SPRITE_COORD_ORIGIN +_CRSTATE_BITS_OP_SIZEOF(point.spriteCoordOrigin); +#endif + +_CRSTATE_BITS_OP_SIZEOF(polygon.dirty); +_CRSTATE_BITS_OP_SIZEOF(polygon.enable); +_CRSTATE_BITS_OP_SIZEOF(polygon.offset); +_CRSTATE_BITS_OP_SIZEOF(polygon.mode); +_CRSTATE_BITS_OP_SIZEOF(polygon.stipple); + +_CRSTATE_BITS_OP_SIZEOF(program.dirty); +_CRSTATE_BITS_OP_SIZEOF(program.vpEnable); +_CRSTATE_BITS_OP_SIZEOF(program.fpEnable); +_CRSTATE_BITS_OP_SIZEOF(program.vpBinding); +_CRSTATE_BITS_OP_SIZEOF(program.fpBinding); +for (i=0; i<CR_MAX_VERTEX_ATTRIBS; ++i) +{ + _CRSTATE_BITS_OP_SIZEOF(program.vertexAttribArrayEnable[i]); + _CRSTATE_BITS_OP_SIZEOF(program.map1AttribArrayEnable[i]); + _CRSTATE_BITS_OP_SIZEOF(program.map2AttribArrayEnable[i]); +} +for (i=0; i<CR_MAX_VERTEX_PROGRAM_ENV_PARAMS; ++i) +{ + _CRSTATE_BITS_OP_SIZEOF(program.vertexEnvParameter[i]); +} +for (i=0; i<CR_MAX_FRAGMENT_PROGRAM_ENV_PARAMS; ++i) +{ + _CRSTATE_BITS_OP_SIZEOF(program.fragmentEnvParameter[i]); +} +_CRSTATE_BITS_OP_SIZEOF(program.vertexEnvParameters); +_CRSTATE_BITS_OP_SIZEOF(program.fragmentEnvParameters); +for (i=0; i<CR_MAX_VERTEX_PROGRAM_ENV_PARAMS/4; ++i) +{ + _CRSTATE_BITS_OP_SIZEOF(program.trackMatrix[i]); +} + +_CRSTATE_BITS_OP_SIZEOF(regcombiner.dirty); +_CRSTATE_BITS_OP_SIZEOF(regcombiner.enable); +_CRSTATE_BITS_OP_SIZEOF(regcombiner.regCombinerVars); +_CRSTATE_BITS_OP_SIZEOF(regcombiner.regCombinerColor0); +_CRSTATE_BITS_OP_SIZEOF(regcombiner.regCombinerColor1); +for (i=0; i<CR_MAX_GENERAL_COMBINERS; ++i) +{ + _CRSTATE_BITS_OP_SIZEOF(regcombiner.regCombinerStageColor0[i]); + _CRSTATE_BITS_OP_SIZEOF(regcombiner.regCombinerStageColor1[i]); + _CRSTATE_BITS_OP_SIZEOF(regcombiner.regCombinerInput[i]); + _CRSTATE_BITS_OP_SIZEOF(regcombiner.regCombinerOutput[i]); +} +_CRSTATE_BITS_OP_SIZEOF(regcombiner.regCombinerFinalInput); + +_CRSTATE_BITS_OP_SIZEOF(stencil.dirty); +_CRSTATE_BITS_OP_SIZEOF(stencil.enable); +#ifdef _CRSTATE_BITS_OP_STENCIL_V_33 +_CRSTATE_BITS_OP_SIZEOF(stencil.bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT_AND_BACK].func); +_CRSTATE_BITS_OP_SIZEOF(stencil.bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT_AND_BACK].op); +for (i = CRSTATE_STENCIL_BUFFER_REF_ID_FRONT_AND_BACK + 1; i < CRSTATE_STENCIL_BUFFER_REF_COUNT; ++i) +{ + CRSTATE_BITS_OP_STENCIL_FUNC_V_33(i, stencil.bufferRefs[i].func); + CRSTATE_BITS_OP_STENCIL_OP_V_33(i, stencil.bufferRefs[i].op); +} +_CRSTATE_BITS_OP_SIZEOF(stencil.clearValue); +_CRSTATE_BITS_OP_SIZEOF(stencil.writeMask); +#else +_CRSTATE_BITS_OP_SIZEOF(stencil.enableTwoSideEXT); +_CRSTATE_BITS_OP_SIZEOF(stencil.activeStencilFace); +_CRSTATE_BITS_OP_SIZEOF(stencil.clearValue); +_CRSTATE_BITS_OP_SIZEOF(stencil.writeMask); +for (i = 0; i < CRSTATE_STENCIL_BUFFER_REF_COUNT; ++i) +{ + _CRSTATE_BITS_OP_SIZEOF(stencil.bufferRefs[i].func); + _CRSTATE_BITS_OP_SIZEOF(stencil.bufferRefs[i].op); +} +#endif + +_CRSTATE_BITS_OP_SIZEOF(texture.dirty); +for (i=0; i<CR_MAX_TEXTURE_UNITS; ++i) +{ + _CRSTATE_BITS_OP_SIZEOF(texture.enable[i]); + _CRSTATE_BITS_OP_SIZEOF(texture.current[i]); + _CRSTATE_BITS_OP_SIZEOF(texture.objGen[i]); + _CRSTATE_BITS_OP_SIZEOF(texture.eyeGen[i]); + _CRSTATE_BITS_OP_SIZEOF(texture.genMode[i]); + _CRSTATE_BITS_OP_SIZEOF(texture.envBit[i]); +} + +_CRSTATE_BITS_OP_SIZEOF(transform.dirty); +_CRSTATE_BITS_OP_SIZEOF(transform.matrixMode); +_CRSTATE_BITS_OP_SIZEOF(transform.modelviewMatrix); +_CRSTATE_BITS_OP_SIZEOF(transform.projectionMatrix); +_CRSTATE_BITS_OP_SIZEOF(transform.colorMatrix); +_CRSTATE_BITS_OP_SIZEOF(transform.textureMatrix); +_CRSTATE_BITS_OP_SIZEOF(transform.programMatrix); +_CRSTATE_BITS_OP_SIZEOF(transform.clipPlane); +_CRSTATE_BITS_OP_SIZEOF(transform.enable); +_CRSTATE_BITS_OP_SIZEOF(transform.base); + +_CRSTATE_BITS_OP_SIZEOF(viewport.dirty); +_CRSTATE_BITS_OP_SIZEOF(viewport.v_dims); +_CRSTATE_BITS_OP_SIZEOF(viewport.s_dims); +_CRSTATE_BITS_OP_SIZEOF(viewport.enable); +_CRSTATE_BITS_OP_SIZEOF(viewport.depth); + +} while (0); + +#undef CRSTATE_BITS_OP_VERSION +#undef _CRSTATE_BITS_OP_STENCIL_V_33 diff --git a/src/VBox/GuestHost/OpenGL/state_tracker/state_buffer.c b/src/VBox/GuestHost/OpenGL/state_tracker/state_buffer.c index 6214e889..90917ab5 100644 --- a/src/VBox/GuestHost/OpenGL/state_tracker/state_buffer.c +++ b/src/VBox/GuestHost/OpenGL/state_tracker/state_buffer.c @@ -483,6 +483,7 @@ void STATE_APIENTRY crStateDrawBuffer (GLenum mode) switch (mode) { case GL_NONE: + break; case GL_FRONT_LEFT: case GL_FRONT_RIGHT: case GL_BACK_LEFT: @@ -548,6 +549,7 @@ void STATE_APIENTRY crStateReadBuffer (GLenum mode) switch (mode) { case GL_NONE: + break; case GL_FRONT_LEFT: case GL_FRONT_RIGHT: case GL_BACK_LEFT: diff --git a/src/VBox/GuestHost/OpenGL/state_tracker/state_bufferobject.c b/src/VBox/GuestHost/OpenGL/state_tracker/state_bufferobject.c index 5a3d2e49..bd6a1e20 100644 --- a/src/VBox/GuestHost/OpenGL/state_tracker/state_bufferobject.c +++ b/src/VBox/GuestHost/OpenGL/state_tracker/state_bufferobject.c @@ -22,16 +22,25 @@ static CRBufferObject *AllocBufferObject(GLuint name) b->usage = GL_STATIC_DRAW_ARB; b->access = GL_READ_WRITE_ARB; b->bResyncOnRead = GL_FALSE; -#ifndef IN_GUEST CR_STATE_SHAREDOBJ_USAGE_INIT(b); -#endif } return b; } -GLboolean crStateIsBufferBound(GLenum target) +void STATE_APIENTRY crStateGenBuffersARB(GLsizei n, GLuint *buffers) +{ + CRContext *g = GetCurrentContext(); + crStateGenNames(g, g->shared->buffersTable, n, buffers); +} + +void crStateRegBuffers(GLsizei n, GLuint *buffers) { CRContext *g = GetCurrentContext(); + crStateRegNames(g, g->shared->buffersTable, n, buffers); +} + +GLboolean crStateIsBufferBoundForCtx(CRContext *g, GLenum target) +{ CRBufferObjectState *b = &(g->bufferobject); switch (target) @@ -51,6 +60,12 @@ GLboolean crStateIsBufferBound(GLenum target) } } +GLboolean crStateIsBufferBound(GLenum target) +{ + CRContext *g = GetCurrentContext(); + return crStateIsBufferBoundForCtx(g, target); +} + CRBufferObject *crStateGetBoundBufferObject(GLenum target, CRBufferObjectState *b) { switch (target) @@ -70,6 +85,21 @@ CRBufferObject *crStateGetBoundBufferObject(GLenum target, CRBufferObjectState * } } +DECLEXPORT(GLboolean) STATE_APIENTRY crStateIsBufferARB( GLuint buffer ) +{ + CRContext *g = GetCurrentContext(); + + FLUSH(); + + if (g->current.inBeginEnd) { + crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION, + "glIsBufferARB called in begin/end"); + return GL_FALSE; + } + + return buffer ? crHashtableIsKeyUsed(g->shared->buffersTable, buffer) : GL_FALSE; +} + void crStateBufferObjectInit (CRContext *ctx) { CRStateBits *sb = GetCurrentBits(); @@ -93,7 +123,7 @@ void crStateBufferObjectInit (CRContext *ctx) b->nullBuffer = AllocBufferObject(0); b->arrayBuffer = b->nullBuffer; b->elementsBuffer = b->nullBuffer; - b->nullBuffer->refCount = 3; + b->nullBuffer->refCount += 2; #ifdef CR_ARB_pixel_buffer_object b->packBuffer = b->nullBuffer; b->unpackBuffer = b->nullBuffer; @@ -184,17 +214,22 @@ crStateBindBufferARB (GLenum target, GLuint buffer) else { newObj = (CRBufferObject *) crHashtableSearch(g->shared->buffersTable, buffer); if (!newObj) { + CRSTATE_CHECKERR(!crHashtableIsKeyUsed(g->shared->buffersTable, buffer), GL_INVALID_OPERATION, "name is not a buffer object"); newObj = AllocBufferObject(buffer); - if (!newObj) { - crStateError(__LINE__, __FILE__, GL_OUT_OF_MEMORY, "glBindBuffer"); + CRSTATE_CHECKERR(!newObj, GL_OUT_OF_MEMORY, "glBindBuffer"); +#ifndef IN_GUEST + diff_api.GenBuffersARB(1, &newObj->hwid); + if (!newObj->hwid) + { + crWarning("GenBuffersARB failed!"); + crFree(newObj); return; } +#endif crHashtableAdd( g->shared->buffersTable, buffer, newObj ); } -#ifndef IN_GUEST CR_STATE_SHAREDOBJ_USAGE_SET(newObj, g); -#endif } newObj->refCount++; @@ -243,127 +278,124 @@ crStateBindBufferARB (GLenum target, GLuint buffer) #endif } -void STATE_APIENTRY -crStateDeleteBuffersARB(GLsizei n, const GLuint *buffers) +static void ctStateBuffersRefsCleanup(CRContext *ctx, CRBufferObject *obj, CRbitvalue *neg_bitid) { - CRContext *g = GetCurrentContext(); - CRBufferObjectState *b = &(g->bufferobject); + CRBufferObjectState *b = &(ctx->bufferobject); CRStateBits *sb = GetCurrentBits(); CRBufferObjectBits *bb = &(sb->bufferobject); - int i; + int j, k; - FLUSH(); - - if (g->current.inBeginEnd) { - crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION, - "glDeleteBuffersARB called in Begin/End"); - return; + if (obj == b->arrayBuffer) + { + b->arrayBuffer = b->nullBuffer; + b->arrayBuffer->refCount++; + DIRTY(bb->dirty, neg_bitid); + DIRTY(bb->arrayBinding, neg_bitid); } - - if (n < 0) { - crStateError(__LINE__, __FILE__, GL_INVALID_VALUE, - "glDeleteBuffersARB(n < 0)"); - return; + if (obj == b->elementsBuffer) + { + b->elementsBuffer = b->nullBuffer; + b->elementsBuffer->refCount++; + DIRTY(bb->dirty, neg_bitid); + DIRTY(bb->elementsBinding, neg_bitid); } - - for (i = 0; i < n; i++) { - if (buffers[i]) { - CRBufferObject *obj = (CRBufferObject *) - crHashtableSearch(g->shared->buffersTable, buffers[i]); - if (obj) { - if (obj == b->arrayBuffer) - { - b->arrayBuffer = b->nullBuffer; - b->arrayBuffer->refCount++; - DIRTY(bb->dirty, g->neg_bitid); - DIRTY(bb->arrayBinding, g->neg_bitid); - } - else if (obj == b->elementsBuffer) - { - b->elementsBuffer = b->nullBuffer; - b->elementsBuffer->refCount++; - DIRTY(bb->dirty, g->neg_bitid); - DIRTY(bb->elementsBinding, g->neg_bitid); - } #ifdef CR_ARB_pixel_buffer_object - else if (obj == b->packBuffer) - { - b->packBuffer = b->nullBuffer; - b->packBuffer->refCount++; - DIRTY(bb->dirty, g->neg_bitid); - DIRTY(bb->packBinding, g->neg_bitid); - } - else if (obj == b->unpackBuffer) - { - b->unpackBuffer = b->nullBuffer; - b->unpackBuffer->refCount++; - DIRTY(bb->dirty, g->neg_bitid); - DIRTY(bb->unpackBinding, g->neg_bitid); - } + if (obj == b->packBuffer) + { + b->packBuffer = b->nullBuffer; + b->packBuffer->refCount++; + DIRTY(bb->dirty, neg_bitid); + DIRTY(bb->packBinding, neg_bitid); + } + if (obj == b->unpackBuffer) + { + b->unpackBuffer = b->nullBuffer; + b->unpackBuffer->refCount++; + DIRTY(bb->dirty, neg_bitid); + DIRTY(bb->unpackBinding, neg_bitid); + } #endif - /* @todo check bindings with the vertex arrays */ - crHashtableDelete(g->shared->buffersTable, buffers[i], crStateFreeBufferObject); +#ifdef CR_ARB_vertex_buffer_object + for (j=0; j<CRSTATECLIENT_MAX_VERTEXARRAYS; ++j) + { + CRClientPointer *cp = crStateGetClientPointerByIndex(j, &ctx->client.array); + if (obj == cp->buffer) + { + cp->buffer = b->nullBuffer; + ++b->nullBuffer->refCount; + } + } + + for (k=0; k<ctx->client.vertexArrayStackDepth; ++k) + { + CRVertexArrays *pArray = &ctx->client.vertexArrayStack[k]; + for (j=0; j<CRSTATECLIENT_MAX_VERTEXARRAYS; ++j) + { + CRClientPointer *cp = crStateGetClientPointerByIndex(j, pArray); + if (obj == cp->buffer) + { + cp->buffer = b->nullBuffer; + ++b->nullBuffer->refCount; } } } -} +#endif + CR_STATE_SHAREDOBJ_USAGE_CLEAR(obj, ctx); +} void STATE_APIENTRY -crStateGenBuffersARB(GLsizei n, GLuint * buffers) +crStateDeleteBuffersARB(GLsizei n, const GLuint *buffers) { CRContext *g = GetCurrentContext(); - CRBufferObjectState *b = &(g->bufferobject); - GLint start; + int i; FLUSH(); if (g->current.inBeginEnd) { crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION, - "glGenBuffersARB called in Begin/End"); + "glDeleteBuffersARB called in Begin/End"); return; } if (n < 0) { crStateError(__LINE__, __FILE__, GL_INVALID_VALUE, - "glGenBuffersARB(n < 0)"); + "glDeleteBuffersARB(n < 0)"); return; } - start = crHashtableAllocKeys(g->shared->buffersTable, n); - if (start) { - GLint i; - for (i = 0; i < n; i++) - buffers[i] = (GLuint) (start + i); - } - else { - crStateError(__LINE__, __FILE__, GL_OUT_OF_MEMORY, "glGenBuffersARB"); - } -} - + for (i = 0; i < n; i++) { + if (buffers[i]) { + CRBufferObject *obj = (CRBufferObject *) + crHashtableSearch(g->shared->buffersTable, buffers[i]); + if (obj) { + int j; -GLboolean STATE_APIENTRY -crStateIsBufferARB(GLuint buffer) -{ - CRContext *g = GetCurrentContext(); - CRBufferObjectState *b = &g->bufferobject; + ctStateBuffersRefsCleanup(g, obj, g->neg_bitid); - FLUSH(); + CR_STATE_SHAREDOBJ_USAGE_FOREACH_USED_IDX(obj, j) + { + /* saved state version <= SHCROGL_SSM_VERSION_BEFORE_CTXUSAGE_BITS does not have usage bits info, + * so on restore, we set mark bits as used. + * This is why g_pAvailableContexts[j] could be NULL + * also g_pAvailableContexts[0] will hold default context, which we should discard */ + CRContext *ctx = g_pAvailableContexts[j]; + if (j && ctx) + { + ctStateBuffersRefsCleanup(ctx, obj, g->neg_bitid); /* <- yes, use g->neg_bitid, i.e. neg_bitid of the current context to ensure others bits get dirtified, + * but not the current context ones*/ + } + else + CR_STATE_SHAREDOBJ_USAGE_CLEAR_IDX(obj, j); + } - if (g->current.inBeginEnd) { - crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION, - "glIsBufferARB called in begin/end"); - return GL_FALSE; + crHashtableDelete(g->shared->buffersTable, buffers[i], crStateFreeBufferObject); + } + } } - - if (buffer && crHashtableSearch(g->shared->buffersTable, buffer)) - return GL_TRUE; - else - return GL_FALSE; } - void STATE_APIENTRY crStateBufferDataARB(GLenum target, GLsizeiptrARB size, const GLvoid * data, GLenum usage) { diff --git a/src/VBox/GuestHost/OpenGL/state_tracker/state_client.c b/src/VBox/GuestHost/OpenGL/state_tracker/state_client.c index f0405c64..e02f3abe 100644 --- a/src/VBox/GuestHost/OpenGL/state_tracker/state_client.c +++ b/src/VBox/GuestHost/OpenGL/state_tracker/state_client.c @@ -83,8 +83,9 @@ static void crStateUnlockClientPointer(CRClientPointer* cp) } } -void crStateClientDestroy(CRClientState *c) +void crStateClientDestroy(CRContext *g) { + CRClientState *c = &(g->client); #ifdef CR_EXT_compiled_vertex_array if (c->array.locked) { @@ -109,9 +110,9 @@ void crStateClientDestroy(CRClientState *c) #endif } -void crStateClientInit(CRClientState *c) +void crStateClientInit(CRContext *ctx) { - CRContext *g = GetCurrentContext(); + CRClientState *c = &(ctx->client); unsigned int i; /* pixel pack/unpack */ @@ -151,7 +152,9 @@ void crStateClientInit(CRClientState *c) c->array.v.stride = 0; c->array.v.enabled = 0; #ifdef CR_ARB_vertex_buffer_object - c->array.v.buffer = g ? g->bufferobject.arrayBuffer : NULL; + c->array.v.buffer = ctx->bufferobject.arrayBuffer; + if (c->array.v.buffer) + ++c->array.v.buffer->refCount; #endif #ifdef CR_EXT_compiled_vertex_array c->array.v.locked = GL_FALSE; @@ -166,7 +169,9 @@ void crStateClientInit(CRClientState *c) c->array.c.stride = 0; c->array.c.enabled = 0; #ifdef CR_ARB_vertex_buffer_object - c->array.c.buffer = g ? g->bufferobject.arrayBuffer : NULL; + c->array.c.buffer = ctx->bufferobject.arrayBuffer; + if (c->array.c.buffer) + ++c->array.c.buffer->refCount; #endif #ifdef CR_EXT_compiled_vertex_array c->array.c.locked = GL_FALSE; @@ -181,7 +186,9 @@ void crStateClientInit(CRClientState *c) c->array.f.stride = 0; c->array.f.enabled = 0; #ifdef CR_ARB_vertex_buffer_object - c->array.f.buffer = g ? g->bufferobject.arrayBuffer : NULL; + c->array.f.buffer = ctx->bufferobject.arrayBuffer; + if (c->array.f.buffer) + ++c->array.f.buffer->refCount; #endif #ifdef CR_EXT_compiled_vertex_array c->array.f.locked = GL_FALSE; @@ -196,7 +203,9 @@ void crStateClientInit(CRClientState *c) c->array.s.stride = 0; c->array.s.enabled = 0; #ifdef CR_ARB_vertex_buffer_object - c->array.s.buffer = g ? g->bufferobject.arrayBuffer : NULL; + c->array.s.buffer = ctx->bufferobject.arrayBuffer; + if (c->array.s.buffer) + ++c->array.s.buffer->refCount; #endif #ifdef CR_EXT_compiled_vertex_array c->array.s.locked = GL_FALSE; @@ -211,7 +220,9 @@ void crStateClientInit(CRClientState *c) c->array.e.stride = 0; c->array.e.enabled = 0; #ifdef CR_ARB_vertex_buffer_object - c->array.e.buffer = g ? g->bufferobject.arrayBuffer : NULL; + c->array.e.buffer = ctx->bufferobject.arrayBuffer; + if (c->array.e.buffer) + ++c->array.e.buffer->refCount; #endif #ifdef CR_EXT_compiled_vertex_array c->array.e.locked = GL_FALSE; @@ -226,7 +237,9 @@ void crStateClientInit(CRClientState *c) c->array.i.stride = 0; c->array.i.enabled = 0; #ifdef CR_ARB_vertex_buffer_object - c->array.i.buffer = g ? g->bufferobject.arrayBuffer : NULL; + c->array.i.buffer = ctx->bufferobject.arrayBuffer; + if (c->array.i.buffer) + ++c->array.i.buffer->refCount; #endif #ifdef CR_EXT_compiled_vertex_array c->array.i.locked = GL_FALSE; @@ -241,7 +254,9 @@ void crStateClientInit(CRClientState *c) c->array.n.stride = 0; c->array.n.enabled = 0; #ifdef CR_ARB_vertex_buffer_object - c->array.n.buffer = g ? g->bufferobject.arrayBuffer : NULL; + c->array.n.buffer = ctx->bufferobject.arrayBuffer; + if (c->array.n.buffer) + ++c->array.n.buffer->refCount; #endif #ifdef CR_EXT_compiled_vertex_array c->array.n.locked = GL_FALSE; @@ -258,7 +273,9 @@ void crStateClientInit(CRClientState *c) c->array.t[i].stride = 0; c->array.t[i].enabled = 0; #ifdef CR_ARB_vertex_buffer_object - c->array.t[i].buffer = g ? g->bufferobject.arrayBuffer : NULL; + c->array.t[i].buffer = ctx->bufferobject.arrayBuffer; + if (c->array.t[i].buffer) + ++c->array.t[i].buffer->refCount; #endif #ifdef CR_EXT_compiled_vertex_array c->array.t[i].locked = GL_FALSE; @@ -275,7 +292,9 @@ void crStateClientInit(CRClientState *c) c->array.a[i].size = 4; c->array.a[i].stride = 0; #ifdef CR_ARB_vertex_buffer_object - c->array.a[i].buffer = g ? g->bufferobject.arrayBuffer : NULL; + c->array.a[i].buffer = ctx->bufferobject.arrayBuffer; + if (c->array.a[i].buffer) + ++c->array.a[i].buffer->refCount; #endif #ifdef CR_EXT_compiled_vertex_array c->array.a[i].locked = GL_FALSE; @@ -622,7 +641,14 @@ crStateClientSetPointer(CRClientPointer *cp, GLint size, cp->stride = cp->bytesPerIndex; #ifdef CR_ARB_vertex_buffer_object + if (cp->buffer) + { + --cp->buffer->refCount; + CRASSERT(cp->buffer->refCount && cp->buffer->refCount < UINT32_MAX/2); + } cp->buffer = g->bufferobject.arrayBuffer; + if (cp->buffer) + ++cp->buffer->refCount; #endif } @@ -1622,6 +1648,7 @@ crStateUseServerArrayElements(void) #endif } +#define CR_BUFFER_HWID(_p) ((_p) ? (_p)->hwid : 0) void crStateClientDiff(CRClientBits *cb, CRbitvalue *bitID, @@ -1631,6 +1658,17 @@ crStateClientDiff(CRClientBits *cb, CRbitvalue *bitID, const CRClientState *to = &(toCtx->client); GLint curClientTextureUnit = from->curClientTextureUnit; int i; + GLint idHwArrayBuffer = CR_BUFFER_HWID(toCtx->bufferobject.arrayBuffer); + const GLint idHwInitialBuffer = idHwArrayBuffer; + +#ifdef DEBUG_misha + { + GLint tstHwBuffer = -1; + diff_api.GetIntegerv(GL_ARRAY_BUFFER_BINDING, &tstHwBuffer); + CRASSERT(idHwInitialBuffer == tstHwBuffer); + } +#endif + if (CHECKDIRTY(cb->clientPointer, bitID)) { /* one or more vertex pointers is dirty */ @@ -1638,7 +1676,14 @@ crStateClientDiff(CRClientBits *cb, CRbitvalue *bitID, if (from->array.v.size != to->array.v.size || from->array.v.type != to->array.v.type || from->array.v.stride != to->array.v.stride || + from->array.v.p != to->array.v.p || from->array.v.buffer != to->array.v.buffer) { + GLint idHwArrayBufferUsed = CR_BUFFER_HWID(to->array.v.buffer); + if (idHwArrayBufferUsed != idHwArrayBuffer) + { + diff_api.BindBufferARB(GL_ARRAY_BUFFER_ARB, idHwArrayBufferUsed); + idHwArrayBuffer = idHwArrayBufferUsed; + } diff_api.VertexPointer(to->array.v.size, to->array.v.type, to->array.v.stride, to->array.v.p); from->array.v.size = to->array.v.size; @@ -1653,7 +1698,14 @@ crStateClientDiff(CRClientBits *cb, CRbitvalue *bitID, if (CHECKDIRTY(cb->n, bitID)) { if (from->array.n.type != to->array.n.type || from->array.n.stride != to->array.n.stride || + from->array.n.p != to->array.n.p || from->array.n.buffer != to->array.n.buffer) { + GLint idHwArrayBufferUsed = CR_BUFFER_HWID(to->array.n.buffer); + if (idHwArrayBufferUsed != idHwArrayBuffer) + { + diff_api.BindBufferARB(GL_ARRAY_BUFFER_ARB, idHwArrayBufferUsed); + idHwArrayBuffer = idHwArrayBufferUsed; + } diff_api.NormalPointer(to->array.n.type, to->array.n.stride, to->array.n.p); from->array.n.type = to->array.n.type; @@ -1668,7 +1720,14 @@ crStateClientDiff(CRClientBits *cb, CRbitvalue *bitID, if (from->array.c.size != to->array.c.size || from->array.c.type != to->array.c.type || from->array.c.stride != to->array.c.stride || + from->array.c.p != to->array.c.p || from->array.c.buffer != to->array.c.buffer) { + GLint idHwArrayBufferUsed = CR_BUFFER_HWID(to->array.c.buffer); + if (idHwArrayBufferUsed != idHwArrayBuffer) + { + diff_api.BindBufferARB(GL_ARRAY_BUFFER_ARB, idHwArrayBufferUsed); + idHwArrayBuffer = idHwArrayBufferUsed; + } diff_api.ColorPointer(to->array.c.size, to->array.c.type, to->array.c.stride, to->array.c.p); from->array.c.size = to->array.c.size; @@ -1683,7 +1742,14 @@ crStateClientDiff(CRClientBits *cb, CRbitvalue *bitID, if (CHECKDIRTY(cb->i, bitID)) { if (from->array.i.type != to->array.i.type || from->array.i.stride != to->array.i.stride || + from->array.i.p != to->array.i.p || from->array.i.buffer != to->array.i.buffer) { + GLint idHwArrayBufferUsed = CR_BUFFER_HWID(to->array.i.buffer); + if (idHwArrayBufferUsed != idHwArrayBuffer) + { + diff_api.BindBufferARB(GL_ARRAY_BUFFER_ARB, idHwArrayBufferUsed); + idHwArrayBuffer = idHwArrayBufferUsed; + } diff_api.IndexPointer(to->array.i.type, to->array.i.stride, to->array.i.p); from->array.i.type = to->array.i.type; @@ -1699,7 +1765,14 @@ crStateClientDiff(CRClientBits *cb, CRbitvalue *bitID, if (from->array.t[i].size != to->array.t[i].size || from->array.t[i].type != to->array.t[i].type || from->array.t[i].stride != to->array.t[i].stride || + from->array.t[i].p != to->array.t[i].p || from->array.t[i].buffer != to->array.t[i].buffer) { + GLint idHwArrayBufferUsed = CR_BUFFER_HWID(to->array.t[i].buffer); + if (idHwArrayBufferUsed != idHwArrayBuffer) + { + diff_api.BindBufferARB(GL_ARRAY_BUFFER_ARB, idHwArrayBufferUsed); + idHwArrayBuffer = idHwArrayBufferUsed; + } diff_api.ClientActiveTextureARB(GL_TEXTURE0_ARB + i); curClientTextureUnit = i; diff_api.TexCoordPointer(to->array.t[i].size, to->array.t[i].type, @@ -1716,7 +1789,14 @@ crStateClientDiff(CRClientBits *cb, CRbitvalue *bitID, /* edge flag */ if (CHECKDIRTY(cb->e, bitID)) { if (from->array.e.stride != to->array.e.stride || + from->array.e.p != to->array.e.p || from->array.e.buffer != to->array.e.buffer) { + GLint idHwArrayBufferUsed = CR_BUFFER_HWID(to->array.e.buffer); + if (idHwArrayBufferUsed != idHwArrayBuffer) + { + diff_api.BindBufferARB(GL_ARRAY_BUFFER_ARB, idHwArrayBufferUsed); + idHwArrayBuffer = idHwArrayBufferUsed; + } diff_api.EdgeFlagPointer(to->array.e.stride, to->array.e.p); from->array.e.stride = to->array.e.stride; from->array.e.p = to->array.e.p; @@ -1729,7 +1809,14 @@ crStateClientDiff(CRClientBits *cb, CRbitvalue *bitID, if (from->array.s.size != to->array.s.size || from->array.s.type != to->array.s.type || from->array.s.stride != to->array.s.stride || + from->array.s.p != to->array.s.p || from->array.s.buffer != to->array.s.buffer) { + GLint idHwArrayBufferUsed = CR_BUFFER_HWID(to->array.s.buffer); + if (idHwArrayBufferUsed != idHwArrayBuffer) + { + diff_api.BindBufferARB(GL_ARRAY_BUFFER_ARB, idHwArrayBufferUsed); + idHwArrayBuffer = idHwArrayBufferUsed; + } diff_api.SecondaryColorPointerEXT(to->array.s.size, to->array.s.type, to->array.s.stride, to->array.s.p); from->array.s.size = to->array.s.size; @@ -1744,7 +1831,14 @@ crStateClientDiff(CRClientBits *cb, CRbitvalue *bitID, if (CHECKDIRTY(cb->f, bitID)) { if (from->array.f.type != to->array.f.type || from->array.f.stride != to->array.f.stride || + from->array.f.p != to->array.f.p || from->array.f.buffer != to->array.f.buffer) { + GLint idHwArrayBufferUsed = CR_BUFFER_HWID(to->array.f.buffer); + if (idHwArrayBufferUsed != idHwArrayBuffer) + { + diff_api.BindBufferARB(GL_ARRAY_BUFFER_ARB, idHwArrayBufferUsed); + idHwArrayBuffer = idHwArrayBufferUsed; + } diff_api.FogCoordPointerEXT(to->array.f.type, to->array.f.stride, to->array.f.p); from->array.f.type = to->array.f.type; @@ -1762,7 +1856,14 @@ crStateClientDiff(CRClientBits *cb, CRbitvalue *bitID, from->array.a[i].type != to->array.a[i].type || from->array.a[i].stride != to->array.a[i].stride || from->array.a[i].normalized != to->array.a[i].normalized || + from->array.a[i].p != to->array.a[i].p || from->array.a[i].buffer != to->array.a[i].buffer) { + GLint idHwArrayBufferUsed = CR_BUFFER_HWID(to->array.a[i].buffer); + if (idHwArrayBufferUsed != idHwArrayBuffer) + { + diff_api.BindBufferARB(GL_ARRAY_BUFFER_ARB, idHwArrayBufferUsed); + idHwArrayBuffer = idHwArrayBufferUsed; + } diff_api.VertexAttribPointerARB(i, to->array.a[i].size, to->array.a[i].type, to->array.a[i].normalized, @@ -1781,11 +1882,16 @@ crStateClientDiff(CRClientBits *cb, CRbitvalue *bitID, #endif } + if (idHwArrayBuffer != idHwInitialBuffer) + { + diff_api.BindBufferARB(GL_ARRAY_BUFFER_ARB, idHwInitialBuffer); + } + if (CHECKDIRTY(cb->enableClientState, bitID)) { /* update vertex array enable/disable flags */ glAble able[2]; - able[0] = diff_api.Disable; - able[1] = diff_api.Enable; + able[0] = diff_api.DisableClientState; + able[1] = diff_api.EnableClientState; if (from->array.v.enabled != to->array.v.enabled) { able[to->array.v.enabled](GL_VERTEX_ARRAY); from->array.v.enabled = to->array.v.enabled; @@ -1849,6 +1955,16 @@ crStateClientSwitch(CRClientBits *cb, CRbitvalue *bitID, const CRClientState *to = &(toCtx->client); GLint curClientTextureUnit = from->curClientTextureUnit; int i; + GLint idHwArrayBuffer = CR_BUFFER_HWID(toCtx->bufferobject.arrayBuffer); + const GLint idHwInitialBuffer = idHwArrayBuffer; + +#ifdef DEBUG_misha + { + GLint tstHwBuffer = -1; + diff_api.GetIntegerv(GL_ARRAY_BUFFER_BINDING, &tstHwBuffer); + CRASSERT(idHwInitialBuffer == tstHwBuffer); + } +#endif if (CHECKDIRTY(cb->clientPointer, bitID)) { /* one or more vertex pointers is dirty */ @@ -1856,7 +1972,14 @@ crStateClientSwitch(CRClientBits *cb, CRbitvalue *bitID, if (from->array.v.size != to->array.v.size || from->array.v.type != to->array.v.type || from->array.v.stride != to->array.v.stride || + from->array.v.p != to->array.v.p || from->array.v.buffer != to->array.v.buffer) { + GLint idHwArrayBufferUsed = CR_BUFFER_HWID(to->array.v.buffer); + if (idHwArrayBufferUsed != idHwArrayBuffer) + { + diff_api.BindBufferARB(GL_ARRAY_BUFFER_ARB, idHwArrayBufferUsed); + idHwArrayBuffer = idHwArrayBufferUsed; + } diff_api.VertexPointer(to->array.v.size, to->array.v.type, to->array.v.stride, to->array.v.p); FILLDIRTY(cb->v); @@ -1869,7 +1992,14 @@ crStateClientSwitch(CRClientBits *cb, CRbitvalue *bitID, if (CHECKDIRTY(cb->n, bitID)) { if (from->array.n.type != to->array.n.type || from->array.n.stride != to->array.n.stride || + from->array.n.p != to->array.n.p || from->array.n.buffer != to->array.n.buffer) { + GLint idHwArrayBufferUsed = CR_BUFFER_HWID(to->array.n.buffer); + if (idHwArrayBufferUsed != idHwArrayBuffer) + { + diff_api.BindBufferARB(GL_ARRAY_BUFFER_ARB, idHwArrayBufferUsed); + idHwArrayBuffer = idHwArrayBufferUsed; + } diff_api.NormalPointer(to->array.n.type, to->array.n.stride, to->array.n.p); FILLDIRTY(cb->n); @@ -1883,7 +2013,14 @@ crStateClientSwitch(CRClientBits *cb, CRbitvalue *bitID, if (from->array.c.size != to->array.c.size || from->array.c.type != to->array.c.type || from->array.c.stride != to->array.c.stride || + from->array.c.p != to->array.c.p || from->array.c.buffer != to->array.c.buffer) { + GLint idHwArrayBufferUsed = CR_BUFFER_HWID(to->array.c.buffer); + if (idHwArrayBufferUsed != idHwArrayBuffer) + { + diff_api.BindBufferARB(GL_ARRAY_BUFFER_ARB, idHwArrayBufferUsed); + idHwArrayBuffer = idHwArrayBufferUsed; + } diff_api.ColorPointer(to->array.c.size, to->array.c.type, to->array.c.stride, to->array.c.p); FILLDIRTY(cb->c); @@ -1896,7 +2033,14 @@ crStateClientSwitch(CRClientBits *cb, CRbitvalue *bitID, if (CHECKDIRTY(cb->i, bitID)) { if (from->array.i.type != to->array.i.type || from->array.i.stride != to->array.i.stride || + from->array.i.p != to->array.i.p || from->array.i.buffer != to->array.i.buffer) { + GLint idHwArrayBufferUsed = CR_BUFFER_HWID(to->array.i.buffer); + if (idHwArrayBufferUsed != idHwArrayBuffer) + { + diff_api.BindBufferARB(GL_ARRAY_BUFFER_ARB, idHwArrayBufferUsed); + idHwArrayBuffer = idHwArrayBufferUsed; + } diff_api.IndexPointer(to->array.i.type, to->array.i.stride, to->array.i.p); FILLDIRTY(cb->i); @@ -1911,7 +2055,14 @@ crStateClientSwitch(CRClientBits *cb, CRbitvalue *bitID, if (from->array.t[i].size != to->array.t[i].size || from->array.t[i].type != to->array.t[i].type || from->array.t[i].stride != to->array.t[i].stride || + from->array.t[i].p != to->array.t[i].p || from->array.t[i].buffer != to->array.t[i].buffer) { + GLint idHwArrayBufferUsed = CR_BUFFER_HWID(to->array.t[i].buffer); + if (idHwArrayBufferUsed != idHwArrayBuffer) + { + diff_api.BindBufferARB(GL_ARRAY_BUFFER_ARB, idHwArrayBufferUsed); + idHwArrayBuffer = idHwArrayBufferUsed; + } diff_api.ClientActiveTextureARB(GL_TEXTURE0_ARB + i); curClientTextureUnit = i; diff_api.TexCoordPointer(to->array.t[i].size, to->array.t[i].type, @@ -1926,7 +2077,14 @@ crStateClientSwitch(CRClientBits *cb, CRbitvalue *bitID, /* edge flag */ if (CHECKDIRTY(cb->e, bitID)) { if (from->array.e.stride != to->array.e.stride || + from->array.e.p != to->array.e.p || from->array.e.buffer != to->array.e.buffer) { + GLint idHwArrayBufferUsed = CR_BUFFER_HWID(to->array.e.buffer); + if (idHwArrayBufferUsed != idHwArrayBuffer) + { + diff_api.BindBufferARB(GL_ARRAY_BUFFER_ARB, idHwArrayBufferUsed); + idHwArrayBuffer = idHwArrayBufferUsed; + } diff_api.EdgeFlagPointer(to->array.e.stride, to->array.e.p); FILLDIRTY(cb->e); FILLDIRTY(cb->clientPointer); @@ -1939,7 +2097,14 @@ crStateClientSwitch(CRClientBits *cb, CRbitvalue *bitID, if (from->array.s.size != to->array.s.size || from->array.s.type != to->array.s.type || from->array.s.stride != to->array.s.stride || + from->array.s.p != to->array.s.p || from->array.s.buffer != to->array.s.buffer) { + GLint idHwArrayBufferUsed = CR_BUFFER_HWID(to->array.s.buffer); + if (idHwArrayBufferUsed != idHwArrayBuffer) + { + diff_api.BindBufferARB(GL_ARRAY_BUFFER_ARB, idHwArrayBufferUsed); + idHwArrayBuffer = idHwArrayBufferUsed; + } diff_api.SecondaryColorPointerEXT(to->array.s.size, to->array.s.type, to->array.s.stride, to->array.s.p); FILLDIRTY(cb->s); @@ -1952,7 +2117,14 @@ crStateClientSwitch(CRClientBits *cb, CRbitvalue *bitID, if (CHECKDIRTY(cb->f, bitID)) { if (from->array.f.type != to->array.f.type || from->array.f.stride != to->array.f.stride || + from->array.f.p != to->array.f.p || from->array.f.buffer != to->array.f.buffer) { + GLint idHwArrayBufferUsed = CR_BUFFER_HWID(to->array.f.buffer); + if (idHwArrayBufferUsed != idHwArrayBuffer) + { + diff_api.BindBufferARB(GL_ARRAY_BUFFER_ARB, idHwArrayBufferUsed); + idHwArrayBuffer = idHwArrayBufferUsed; + } diff_api.FogCoordPointerEXT(to->array.f.type, to->array.f.stride, to->array.f.p); FILLDIRTY(cb->f); @@ -1969,7 +2141,14 @@ crStateClientSwitch(CRClientBits *cb, CRbitvalue *bitID, from->array.a[i].type != to->array.a[i].type || from->array.a[i].stride != to->array.a[i].stride || from->array.a[i].normalized != to->array.a[i].normalized || + from->array.a[i].p != to->array.a[i].p || from->array.a[i].buffer != to->array.a[i].buffer) { + GLint idHwArrayBufferUsed = CR_BUFFER_HWID(to->array.a[i].buffer); + if (idHwArrayBufferUsed != idHwArrayBuffer) + { + diff_api.BindBufferARB(GL_ARRAY_BUFFER_ARB, idHwArrayBufferUsed); + idHwArrayBuffer = idHwArrayBufferUsed; + } diff_api.VertexAttribPointerARB(i, to->array.a[i].size, to->array.a[i].type, to->array.a[i].normalized, @@ -1985,11 +2164,16 @@ crStateClientSwitch(CRClientBits *cb, CRbitvalue *bitID, #endif } + if (idHwArrayBuffer != idHwInitialBuffer) + { + diff_api.BindBufferARB(GL_ARRAY_BUFFER_ARB, idHwInitialBuffer); + } + if (CHECKDIRTY(cb->enableClientState, bitID)) { /* update vertex array enable/disable flags */ glAble able[2]; - able[0] = diff_api.Disable; - able[1] = diff_api.Enable; + able[0] = diff_api.DisableClientState; + able[1] = diff_api.EnableClientState; if (from->array.v.enabled != to->array.v.enabled) { able[to->array.v.enabled](GL_VERTEX_ARRAY); FILLDIRTY(cb->enableClientState); @@ -2038,7 +2222,7 @@ crStateClientSwitch(CRClientBits *cb, CRbitvalue *bitID, if (from->array.a[i].enabled != to->array.a[i].enabled) { if (to->array.a[i].enabled) diff_api.EnableVertexAttribArrayARB(i); - else + else diff_api.DisableVertexAttribArrayARB(i); FILLDIRTY(cb->enableClientState); FILLDIRTY(cb->dirty); diff --git a/src/VBox/GuestHost/OpenGL/state_tracker/state_diff.c b/src/VBox/GuestHost/OpenGL/state_tracker/state_diff.c index d46a9561..c8e616d2 100644 --- a/src/VBox/GuestHost/OpenGL/state_tracker/state_diff.c +++ b/src/VBox/GuestHost/OpenGL/state_tracker/state_diff.c @@ -8,6 +8,8 @@ #include "cr_error.h" #include "cr_mem.h" #include "cr_pixeldata.h" +#include <iprt/err.h> +#include <stdio.h> void crStateDiffContext( CRContext *from, CRContext *to ) { @@ -121,12 +123,165 @@ void crStateDiffContext( CRContext *from, CRContext *to ) } } -void crStateApplyFBImage(CRContext *to) +void crStateFreeFBImageLegacy(CRContext *to) +{ + if (to->buffer.pFrontImg) + { + crFree(to->buffer.pFrontImg); + to->buffer.pFrontImg = NULL; + } + if (to->buffer.pBackImg) + { + crFree(to->buffer.pBackImg); + to->buffer.pBackImg = NULL; + } + + to->buffer.storedWidth = 0; + to->buffer.storedHeight = 0; +} + +int crStateAcquireFBImage(CRContext *to, CRFBData *data) +{ + CRBufferState *pBuf = &to->buffer; + CRPixelPackState packing = to->client.pack; + uint32_t i; + + diff_api.PixelStorei(GL_PACK_SKIP_ROWS, 0); + diff_api.PixelStorei(GL_PACK_SKIP_PIXELS, 0); + diff_api.PixelStorei(GL_PACK_ALIGNMENT, 1); + diff_api.PixelStorei(GL_PACK_ROW_LENGTH, 0); + diff_api.PixelStorei(GL_PACK_IMAGE_HEIGHT, 0); + diff_api.PixelStorei(GL_PACK_SKIP_IMAGES, 0); + diff_api.PixelStorei(GL_PACK_SWAP_BYTES, 0); + diff_api.PixelStorei(GL_PACK_LSB_FIRST, 0); + + if (to->bufferobject.packBuffer->hwid>0) + { + diff_api.BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0); + } + + for (i = 0; i < data->cElements; ++i) + { + CRFBDataElement *el = &data->aElements[i]; + + if (el->enmFormat == GL_DEPTH_COMPONENT || el->enmFormat == GL_DEPTH_STENCIL) + { + if (!to->buffer.depthTest) + { + diff_api.Enable(GL_DEPTH_TEST); + } + if (to->pixel.depthScale != 1.0f) + { + diff_api.PixelTransferf (GL_DEPTH_SCALE, 1.0f); + } + if (to->pixel.depthBias != 0.0f) + { + diff_api.PixelTransferf (GL_DEPTH_BIAS, 0.0f); + } + } + if (el->enmFormat == GL_STENCIL_INDEX || el->enmFormat == GL_DEPTH_STENCIL) + { + if (!to->stencil.stencilTest) + { + diff_api.Enable(GL_STENCIL_TEST); + } + if (to->pixel.mapStencil) + { + diff_api.PixelTransferi (GL_MAP_STENCIL, GL_FALSE); + } + if (to->pixel.indexOffset) + { + diff_api.PixelTransferi (GL_INDEX_OFFSET, 0); + } + if (to->pixel.indexShift) + { + diff_api.PixelTransferi (GL_INDEX_SHIFT, 0); + } + } + + diff_api.BindFramebufferEXT(GL_READ_FRAMEBUFFER, el->idFBO); + + if (el->enmBuffer) + diff_api.ReadBuffer(el->enmBuffer); + + diff_api.ReadPixels(el->posX, el->posY, el->width, el->height, el->enmFormat, el->enmType, el->pvData); + crDebug("Acquired %d;%d;%d;%d;%d;0x%p fb image", el->enmBuffer, el->width, el->height, el->enmFormat, el->enmType, el->pvData); + + if (el->enmFormat == GL_DEPTH_COMPONENT || el->enmFormat == GL_DEPTH_STENCIL) + { + if (to->pixel.depthScale != 1.0f) + { + diff_api.PixelTransferf (GL_DEPTH_SCALE, to->pixel.depthScale); + } + if (to->pixel.depthBias != 0.0f) + { + diff_api.PixelTransferf (GL_DEPTH_BIAS, to->pixel.depthBias); + } + if (!to->buffer.depthTest) + { + diff_api.Disable(GL_DEPTH_TEST); + } + } + if (el->enmFormat == GL_STENCIL_INDEX || el->enmFormat == GL_DEPTH_STENCIL) + { + if (to->pixel.indexOffset) + { + diff_api.PixelTransferi (GL_INDEX_OFFSET, to->pixel.indexOffset); + } + if (to->pixel.indexShift) + { + diff_api.PixelTransferi (GL_INDEX_SHIFT, to->pixel.indexShift); + } + if (to->pixel.mapStencil) + { + diff_api.PixelTransferi (GL_MAP_STENCIL, GL_TRUE); + } + if (!to->stencil.stencilTest) + { + diff_api.Disable(GL_STENCIL_TEST); + } + } + } + + if (to->bufferobject.packBuffer->hwid>0) + { + diff_api.BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, to->bufferobject.packBuffer->hwid); + } + if (to->framebufferobject.readFB) + { + CRASSERT(to->framebufferobject.readFB->hwid); + diff_api.BindFramebufferEXT(GL_READ_FRAMEBUFFER, to->framebufferobject.readFB->hwid); + diff_api.ReadBuffer(to->framebufferobject.readFB->readbuffer); + + } + else if (data->idOverrrideFBO) + { + diff_api.BindFramebufferEXT(GL_READ_FRAMEBUFFER, data->idOverrrideFBO); + diff_api.ReadBuffer(GL_COLOR_ATTACHMENT0); + } + else + { + diff_api.BindFramebufferEXT(GL_READ_FRAMEBUFFER, 0); + diff_api.ReadBuffer(to->buffer.readBuffer); + } + + diff_api.PixelStorei(GL_PACK_SKIP_ROWS, packing.skipRows); + diff_api.PixelStorei(GL_PACK_SKIP_PIXELS, packing.skipPixels); + diff_api.PixelStorei(GL_PACK_ALIGNMENT, packing.alignment); + diff_api.PixelStorei(GL_PACK_ROW_LENGTH, packing.rowLength); + diff_api.PixelStorei(GL_PACK_IMAGE_HEIGHT, packing.imageHeight); + diff_api.PixelStorei(GL_PACK_SKIP_IMAGES, packing.skipImages); + diff_api.PixelStorei(GL_PACK_SWAP_BYTES, packing.swapBytes); + diff_api.PixelStorei(GL_PACK_LSB_FIRST, packing.psLSBFirst); + return VINF_SUCCESS; +} + +void crStateApplyFBImage(CRContext *to, CRFBData *data) { - if (to->buffer.pFrontImg || to->buffer.pBackImg) { CRBufferState *pBuf = &to->buffer; CRPixelPackState unpack = to->client.unpack; + uint32_t i; diff_api.PixelStorei(GL_UNPACK_SKIP_ROWS, 0); diff_api.PixelStorei(GL_UNPACK_SKIP_PIXELS, 0); @@ -137,11 +292,6 @@ void crStateApplyFBImage(CRContext *to) diff_api.PixelStorei(GL_UNPACK_SWAP_BYTES, 0); diff_api.PixelStorei(GL_UNPACK_LSB_FIRST, 0); - if (to->framebufferobject.drawFB) - { - diff_api.BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, 0); - } - if (to->bufferobject.unpackBuffer->hwid>0) { diff_api.BindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0); @@ -151,25 +301,84 @@ void crStateApplyFBImage(CRContext *to) diff_api.Disable(GL_SCISSOR_TEST); diff_api.Disable(GL_BLEND); diff_api.Disable(GL_COLOR_LOGIC_OP); + diff_api.Disable(GL_DEPTH_TEST); + diff_api.Disable(GL_STENCIL_TEST); - if (pBuf->pFrontImg) + for (i = 0; i < data->cElements; ++i) { - diff_api.DrawBuffer(GL_FRONT); - diff_api.WindowPos2iARB(0, 0); - diff_api.DrawPixels(pBuf->storedWidth, pBuf->storedHeight, GL_RGBA, GL_UNSIGNED_BYTE, pBuf->pFrontImg); - crDebug("Applied %ix%i fb image", pBuf->storedWidth, pBuf->storedHeight); - crFree(pBuf->pFrontImg); - pBuf->pFrontImg = NULL; - } + CRFBDataElement *el = &data->aElements[i]; +#if 0 + char fname[200]; + sprintf(fname, "./img_apply_%p_%d_%d.tga", to, i, el->enmFormat); + crDumpNamedTGA(fname, el->width, el->height, el->pvData); +#endif - if (pBuf->pBackImg) - { - diff_api.DrawBuffer(GL_BACK); - diff_api.WindowPos2iARB(0, 0); - diff_api.DrawPixels(pBuf->storedWidth, pBuf->storedHeight, GL_RGBA, GL_UNSIGNED_BYTE, pBuf->pBackImg); - crDebug("Applied %ix%i bb image", pBuf->storedWidth, pBuf->storedHeight); - crFree(pBuf->pBackImg); - pBuf->pBackImg = NULL; + if (el->enmFormat == GL_DEPTH_COMPONENT || el->enmFormat == GL_DEPTH_STENCIL) + { + diff_api.Enable(GL_DEPTH_TEST); + if (to->pixel.depthScale != 1.0f) + { + diff_api.PixelTransferf (GL_DEPTH_SCALE, 1.0f); + } + if (to->pixel.depthBias != 0.0f) + { + diff_api.PixelTransferf (GL_DEPTH_BIAS, 0.0f); + } + } + if (el->enmFormat == GL_STENCIL_INDEX || el->enmFormat == GL_DEPTH_STENCIL) + { + diff_api.Enable(GL_STENCIL_TEST); + if (to->pixel.mapStencil) + { + diff_api.PixelTransferi (GL_MAP_STENCIL, GL_FALSE); + } + if (to->pixel.indexOffset) + { + diff_api.PixelTransferi (GL_INDEX_OFFSET, 0); + } + if (to->pixel.indexShift) + { + diff_api.PixelTransferi (GL_INDEX_SHIFT, 0); + } + } + + diff_api.BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, el->idFBO); + + if (el->enmBuffer) + diff_api.DrawBuffer(el->enmBuffer); + + diff_api.WindowPos2iARB(el->posX, el->posY); + diff_api.DrawPixels(el->width, el->height, el->enmFormat, el->enmType, el->pvData); + crDebug("Applied %d;%d;%d;%d;%d;0x%p fb image", el->enmBuffer, el->width, el->height, el->enmFormat, el->enmType, el->pvData); + + if (el->enmFormat == GL_DEPTH_COMPONENT || el->enmFormat == GL_DEPTH_STENCIL) + { + if (to->pixel.depthScale != 1.0f) + { + diff_api.PixelTransferf (GL_DEPTH_SCALE, to->pixel.depthScale); + } + if (to->pixel.depthBias != 0.0f) + { + diff_api.PixelTransferf (GL_DEPTH_BIAS, to->pixel.depthBias); + } + diff_api.Disable(GL_DEPTH_TEST); + } + if (el->enmFormat == GL_STENCIL_INDEX || el->enmFormat == GL_DEPTH_STENCIL) + { + if (to->pixel.indexOffset) + { + diff_api.PixelTransferi (GL_INDEX_OFFSET, to->pixel.indexOffset); + } + if (to->pixel.indexShift) + { + diff_api.PixelTransferi (GL_INDEX_SHIFT, to->pixel.indexShift); + } + if (to->pixel.mapStencil) + { + diff_api.PixelTransferi (GL_MAP_STENCIL, GL_TRUE); + } + diff_api.Disable(GL_STENCIL_TEST); + } } diff_api.WindowPos3fvARB(to->current.rasterAttrib[VERT_ATTRIB_POS]); @@ -179,10 +388,20 @@ void crStateApplyFBImage(CRContext *to) } if (to->framebufferobject.drawFB) { + CRASSERT(to->framebufferobject.drawFB->hwid); diff_api.BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, to->framebufferobject.drawFB->hwid); + diff_api.DrawBuffer(to->framebufferobject.drawFB->drawbuffer[0]); + } + else if (data->idOverrrideFBO) + { + diff_api.BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, data->idOverrrideFBO); + diff_api.DrawBuffer(GL_COLOR_ATTACHMENT0); + } + else + { + diff_api.BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, 0); + diff_api.DrawBuffer(to->buffer.drawBuffer); } - diff_api.DrawBuffer(to->framebufferobject.drawFB ? - to->framebufferobject.drawFB->drawbuffer[0] : to->buffer.drawBuffer); if (to->buffer.alphaTest) { diff_api.Enable(GL_ALPHA_TEST); @@ -199,6 +418,14 @@ void crStateApplyFBImage(CRContext *to) { diff_api.Enable(GL_COLOR_LOGIC_OP); } + if (to->buffer.depthTest) + { + diff_api.Enable(GL_DEPTH_TEST); + } + if (to->stencil.stencilTest) + { + diff_api.Enable(GL_STENCIL_TEST); + } diff_api.PixelStorei(GL_UNPACK_SKIP_ROWS, unpack.skipRows); diff_api.PixelStorei(GL_UNPACK_SKIP_PIXELS, unpack.skipPixels); @@ -341,34 +568,59 @@ void crStateSwitchContext( CRContext *from, CRContext *to ) } #ifdef WINDOWS - crStateApplyFBImage(to); + if (to->buffer.pFrontImg) + { + CRFBData *pLazyData = (CRFBData *)to->buffer.pFrontImg; + crStateApplyFBImage(to, pLazyData); + crStateFreeFBImageLegacy(to); + } #endif } -CRContext * crStateSwichPrepare(CRContext *toCtx, GLboolean fMultipleContexts, GLuint idFBO) +void crStateSyncHWErrorState(CRContext *ctx) { - CRContext *fromCtx = GetCurrentContext(); - - if (!fMultipleContexts) + GLenum err; + while ((err = diff_api.GetError()) != GL_NO_ERROR) { + if (ctx->error != GL_NO_ERROR) + ctx->error = err; + } +} + +void crStateSwitchPrepare(CRContext *toCtx, CRContext *fromCtx, GLuint idDrawFBO, GLuint idReadFBO) +{ + if (!fromCtx) + return; + + if (g_bVBoxEnableDiffOnMakeCurrent && toCtx && toCtx != fromCtx) + crStateSyncHWErrorState(fromCtx); + #ifdef CR_EXT_framebuffer_object - if (fromCtx) - crStateFramebufferObjectDisableHW(fromCtx, idFBO); + crStateFramebufferObjectDisableHW(fromCtx, idDrawFBO, idReadFBO); #endif - } - return fromCtx; } -void crStateSwichPostprocess(CRContext *fromCtx, GLboolean fMultipleContexts, GLuint idFBO) +void crStateSwitchPostprocess(CRContext *toCtx, CRContext *fromCtx, GLuint idDrawFBO, GLuint idReadFBO) { - CRContext *toCtx = GetCurrentContext();; - if (!fromCtx || !toCtx) + if (!toCtx) return; - if (!fMultipleContexts) + if (g_bVBoxEnableDiffOnMakeCurrent && fromCtx && toCtx != fromCtx) { -#ifdef CR_EXT_framebuffer_object - crStateFramebufferObjectReenableHW(fromCtx, toCtx, idFBO); + GLenum err; + while ((err = diff_api.GetError()) != GL_NO_ERROR) + { + static int cErrPrints = 0; +#ifndef DEBUG_misha + if (cErrPrints < 5) #endif + { + ++cErrPrints; + crWarning("gl error (0x%x) after context switch, ignoring.. (%d out of 5) ..", err, cErrPrints); + } + } } +#ifdef CR_EXT_framebuffer_object + crStateFramebufferObjectReenableHW(fromCtx, toCtx, idDrawFBO, idReadFBO); +#endif } diff --git a/src/VBox/GuestHost/OpenGL/state_tracker/state_enable.c b/src/VBox/GuestHost/OpenGL/state_tracker/state_enable.c index 75a1534d..185de9eb 100644 --- a/src/VBox/GuestHost/OpenGL/state_tracker/state_enable.c +++ b/src/VBox/GuestHost/OpenGL/state_tracker/state_enable.c @@ -496,6 +496,13 @@ static void __enableSet (CRContext *g, CRStateBits *sb, CRbitvalue *neg_bitid, else crStateDisableClientState(cap); break; +#ifdef CR_EXT_stencil_two_side + case GL_STENCIL_TEST_TWO_SIDE_EXT: + g->stencil.stencilTwoSideEXT= val; + DIRTY(sb->stencil.enableTwoSideEXT, neg_bitid); + DIRTY(sb->stencil.dirty, neg_bitid); + break; +#endif default: crStateError(__LINE__, __FILE__, GL_INVALID_ENUM, "glEnable/glDisable called with bogus cap: 0x%x", cap); return; diff --git a/src/VBox/GuestHost/OpenGL/state_tracker/state_error.c b/src/VBox/GuestHost/OpenGL/state_tracker/state_error.c index 60eaa457..07a7b494 100644 --- a/src/VBox/GuestHost/OpenGL/state_tracker/state_error.c +++ b/src/VBox/GuestHost/OpenGL/state_tracker/state_error.c @@ -18,9 +18,14 @@ void crStateError( int line, const char *file, GLenum error, const char *format, char errstr[8096]; va_list args; - g->error = error; + CRASSERT(error != GL_NO_ERROR); + if (g->error == GL_NO_ERROR) + g->error = error; + +#ifndef DEBUG_misha if (crGetenv("CR_DEBUG")) +#endif { char *glerr; va_start( args, format ); diff --git a/src/VBox/GuestHost/OpenGL/state_tracker/state_framebuffer.c b/src/VBox/GuestHost/OpenGL/state_tracker/state_framebuffer.c index cdd3cecd..2f150361 100644 --- a/src/VBox/GuestHost/OpenGL/state_tracker/state_framebuffer.c +++ b/src/VBox/GuestHost/OpenGL/state_tracker/state_framebuffer.c @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2009 Oracle Corporation + * Copyright (C) 2009-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -22,12 +22,6 @@ #include "state_internals.h" #include "cr_mem.h" -#define CRSTATE_FBO_CHECKERR(expr, result, message) \ - if (expr) { \ - crStateError(__LINE__, __FILE__, result, message); \ - return; \ - } - DECLEXPORT(void) STATE_APIENTRY crStateFramebufferObjectInit(CRContext *ctx) { @@ -39,6 +33,82 @@ crStateFramebufferObjectInit(CRContext *ctx) ctx->shared->bFBOResyncNeeded = GL_FALSE; } +void STATE_APIENTRY crStateGenFramebuffersEXT(GLsizei n, GLuint *buffers) +{ + CRContext *g = GetCurrentContext(); + crStateGenNames(g, g->shared->fbTable, n, buffers); +} + +void STATE_APIENTRY crStateGenRenderbuffersEXT(GLsizei n, GLuint *buffers) +{ + CRContext *g = GetCurrentContext(); + crStateGenNames(g, g->shared->rbTable, n, buffers); +} + +void crStateRegFramebuffers(GLsizei n, GLuint *buffers) +{ + CRContext *g = GetCurrentContext(); + crStateRegNames(g, g->shared->fbTable, n, buffers); +} + +void crStateRegRenderbuffers(GLsizei n, GLuint *buffers) +{ + CRContext *g = GetCurrentContext(); + crStateRegNames(g, g->shared->rbTable, n, buffers); +} + +static void crStateInitFrameBuffer(CRFramebufferObject *fbo); + +static CRFramebufferObject * +crStateFramebufferAllocate(CRContext *ctx, GLuint name) +{ + CRFramebufferObject *buffer = (CRFramebufferObject*) crCalloc(sizeof(CRFramebufferObject)); + CRSTATE_CHECKERR_RET(!buffer, GL_OUT_OF_MEMORY, "crStateFramebufferAllocate", NULL); + buffer->id = name; +#ifndef IN_GUEST + diff_api.GenFramebuffersEXT(1, &buffer->hwid); + if (!buffer->hwid) + { + crWarning("GenFramebuffersEXT failed!"); + crFree(buffer); + return NULL; + } +#else + buffer->hwid = name; +#endif + + crStateInitFrameBuffer(buffer); + crHashtableAdd(ctx->shared->fbTable, name, buffer); + CR_STATE_SHAREDOBJ_USAGE_INIT(buffer); + + return buffer; +} + +static CRRenderbufferObject * +crStateRenderbufferAllocate(CRContext *ctx, GLuint name) +{ + CRRenderbufferObject *buffer = (CRRenderbufferObject*) crCalloc(sizeof(CRRenderbufferObject)); + CRSTATE_CHECKERR_RET(!buffer, GL_OUT_OF_MEMORY, "crStateRenderbufferAllocate", NULL); + buffer->id = name; +#ifndef IN_GUEST + diff_api.GenRenderbuffersEXT(1, &buffer->hwid); + if (!buffer->hwid) + { + crWarning("GenRenderbuffersEXT failed!"); + crFree(buffer); + return NULL; + } +#else + buffer->hwid = name; +#endif + + buffer->internalformat = GL_RGBA; + crHashtableAdd(ctx->shared->rbTable, name, buffer); + CR_STATE_SHAREDOBJ_USAGE_INIT(buffer); + + return buffer; +} + void crStateFreeFBO(void *data) { CRFramebufferObject *pObj = (CRFramebufferObject *)data; @@ -83,28 +153,18 @@ crStateBindRenderbufferEXT(GLenum target, GLuint renderbuffer) CRContext *g = GetCurrentContext(); CRFramebufferObjectState *fbo = &g->framebufferobject; - CRSTATE_FBO_CHECKERR(g->current.inBeginEnd, GL_INVALID_OPERATION, "called in begin/end"); - CRSTATE_FBO_CHECKERR(target!=GL_RENDERBUFFER_EXT, GL_INVALID_ENUM, "invalid target"); + CRSTATE_CHECKERR(g->current.inBeginEnd, GL_INVALID_OPERATION, "called in begin/end"); + CRSTATE_CHECKERR(target!=GL_RENDERBUFFER_EXT, GL_INVALID_ENUM, "invalid target"); if (renderbuffer) { fbo->renderbuffer = (CRRenderbufferObject*) crHashtableSearch(g->shared->rbTable, renderbuffer); if (!fbo->renderbuffer) { - fbo->renderbuffer = (CRRenderbufferObject*) crCalloc(sizeof(CRRenderbufferObject)); - CRSTATE_FBO_CHECKERR(!fbo->renderbuffer, GL_OUT_OF_MEMORY, "glBindRenderbufferEXT"); - fbo->renderbuffer->id = renderbuffer; - fbo->renderbuffer->hwid = renderbuffer; - fbo->renderbuffer->internalformat = GL_RGBA; - crHashtableAdd(g->shared->rbTable, renderbuffer, fbo->renderbuffer); -#ifndef IN_GUEST - CR_STATE_SHAREDOBJ_USAGE_INIT(fbo->renderbuffer); -#endif + CRSTATE_CHECKERR(!crHashtableIsKeyUsed(g->shared->rbTable, renderbuffer), GL_INVALID_OPERATION, "name is not a renderbuffer"); + fbo->renderbuffer = crStateRenderbufferAllocate(g, renderbuffer); } -#ifndef IN_GUEST CR_STATE_SHAREDOBJ_USAGE_SET(fbo->renderbuffer, g); -#endif - } else fbo->renderbuffer = NULL; } @@ -147,6 +207,22 @@ static void crStateCheckFBOAttachments(CRFramebufferObject *pFBO, GLuint rbo, GL } } +static void ctStateRenderbufferRefsCleanup(CRContext *g, GLuint fboId, CRRenderbufferObject *rbo) +{ + CRFramebufferObjectState *fbo = &g->framebufferobject; + + if (fbo->renderbuffer==rbo) + { + fbo->renderbuffer = NULL; + } + + /* check the attachments of current framebuffers */ + crStateCheckFBOAttachments(fbo->readFB, fboId, GL_READ_FRAMEBUFFER); + crStateCheckFBOAttachments(fbo->drawFB, fboId, GL_DRAW_FRAMEBUFFER); + + CR_STATE_SHAREDOBJ_USAGE_CLEAR(rbo, g); +} + DECLEXPORT(void) STATE_APIENTRY crStateDeleteRenderbuffersEXT(GLsizei n, const GLuint *renderbuffers) { @@ -154,8 +230,8 @@ crStateDeleteRenderbuffersEXT(GLsizei n, const GLuint *renderbuffers) CRFramebufferObjectState *fbo = &g->framebufferobject; int i; - CRSTATE_FBO_CHECKERR(g->current.inBeginEnd, GL_INVALID_OPERATION, "called in begin/end"); - CRSTATE_FBO_CHECKERR(n<0, GL_INVALID_OPERATION, "n<0"); + CRSTATE_CHECKERR(g->current.inBeginEnd, GL_INVALID_OPERATION, "called in begin/end"); + CRSTATE_CHECKERR(n<0, GL_INVALID_OPERATION, "n<0"); for (i = 0; i < n; i++) { @@ -165,15 +241,29 @@ crStateDeleteRenderbuffersEXT(GLsizei n, const GLuint *renderbuffers) rbo = (CRRenderbufferObject*) crHashtableSearch(g->shared->rbTable, renderbuffers[i]); if (rbo) { - if (fbo->renderbuffer==rbo) + int j; + + ctStateRenderbufferRefsCleanup(g, renderbuffers[i], rbo); + CR_STATE_SHAREDOBJ_USAGE_FOREACH_USED_IDX(rbo, j) { - fbo->renderbuffer = NULL; + /* saved state version <= SHCROGL_SSM_VERSION_BEFORE_CTXUSAGE_BITS does not have usage bits info, + * so on restore, we set mark bits as used. + * This is why g_pAvailableContexts[j] could be NULL + * also g_pAvailableContexts[0] will hold default context, which we should discard */ + CRContext *ctx = g_pAvailableContexts[j]; + if (j && ctx) + { + CRFramebufferObjectState *ctxFbo; + CRASSERT(ctx); + ctxFbo = &ctx->framebufferobject; + if (ctxFbo->renderbuffer==rbo) + crWarning("deleting RBO being used by another context %d", ctx->id); + + ctStateRenderbufferRefsCleanup(ctx, renderbuffers[i], rbo); + } + else + CR_STATE_SHAREDOBJ_USAGE_CLEAR_IDX(rbo, j); } - - /* check the attachments of current framebuffers */ - crStateCheckFBOAttachments(fbo->readFB, renderbuffers[i], GL_READ_FRAMEBUFFER); - crStateCheckFBOAttachments(fbo->drawFB, renderbuffers[i], GL_DRAW_FRAMEBUFFER); - crHashtableDelete(g->shared->rbTable, renderbuffers[i], crStateFreeRBO); } } @@ -187,9 +277,9 @@ crStateRenderbufferStorageEXT(GLenum target, GLenum internalformat, GLsizei widt CRFramebufferObjectState *fbo = &g->framebufferobject; CRRenderbufferObject *rb = fbo->renderbuffer; - CRSTATE_FBO_CHECKERR(g->current.inBeginEnd, GL_INVALID_OPERATION, "called in begin/end"); - CRSTATE_FBO_CHECKERR(target!=GL_RENDERBUFFER_EXT, GL_INVALID_ENUM, "invalid target"); - CRSTATE_FBO_CHECKERR(!rb, GL_INVALID_OPERATION, "no bound renderbuffer"); + CRSTATE_CHECKERR(g->current.inBeginEnd, GL_INVALID_OPERATION, "called in begin/end"); + CRSTATE_CHECKERR(target!=GL_RENDERBUFFER_EXT, GL_INVALID_ENUM, "invalid target"); + CRSTATE_CHECKERR(!rb, GL_INVALID_OPERATION, "no bound renderbuffer"); rb->width = width; rb->height = height; @@ -203,9 +293,9 @@ crStateGetRenderbufferParameterivEXT(GLenum target, GLenum pname, GLint *params) CRFramebufferObjectState *fbo = &g->framebufferobject; CRRenderbufferObject *rb = fbo->renderbuffer; - CRSTATE_FBO_CHECKERR(g->current.inBeginEnd, GL_INVALID_OPERATION, "called in begin/end"); - CRSTATE_FBO_CHECKERR(target!=GL_RENDERBUFFER_EXT, GL_INVALID_ENUM, "invalid target"); - CRSTATE_FBO_CHECKERR(!rb, GL_INVALID_OPERATION, "no bound renderbuffer"); + CRSTATE_CHECKERR(g->current.inBeginEnd, GL_INVALID_OPERATION, "called in begin/end"); + CRSTATE_CHECKERR(target!=GL_RENDERBUFFER_EXT, GL_INVALID_ENUM, "invalid target"); + CRSTATE_CHECKERR(!rb, GL_INVALID_OPERATION, "no bound renderbuffer"); switch (pname) { @@ -224,10 +314,10 @@ crStateGetRenderbufferParameterivEXT(GLenum target, GLenum pname, GLint *params) case GL_RENDERBUFFER_ALPHA_SIZE_EXT: case GL_RENDERBUFFER_DEPTH_SIZE_EXT: case GL_RENDERBUFFER_STENCIL_SIZE_EXT: - CRSTATE_FBO_CHECKERR(GL_TRUE, GL_INVALID_OPERATION, "unimplemented"); + CRSTATE_CHECKERR(GL_TRUE, GL_INVALID_OPERATION, "unimplemented"); break; default: - CRSTATE_FBO_CHECKERR(GL_TRUE, GL_INVALID_ENUM, "invalid pname"); + CRSTATE_CHECKERR(GL_TRUE, GL_INVALID_ENUM, "invalid pname"); } } @@ -286,8 +376,8 @@ crStateBindFramebufferEXT(GLenum target, GLuint framebuffer) CRFramebufferObjectState *fbo = &g->framebufferobject; CRFramebufferObject *pFBO=NULL; - CRSTATE_FBO_CHECKERR(g->current.inBeginEnd, GL_INVALID_OPERATION, "called in begin/end"); - CRSTATE_FBO_CHECKERR(((target!=GL_FRAMEBUFFER_EXT) && (target!=GL_READ_FRAMEBUFFER) && (target!=GL_DRAW_FRAMEBUFFER)), + CRSTATE_CHECKERR(g->current.inBeginEnd, GL_INVALID_OPERATION, "called in begin/end"); + CRSTATE_CHECKERR(((target!=GL_FRAMEBUFFER_EXT) && (target!=GL_READ_FRAMEBUFFER) && (target!=GL_DRAW_FRAMEBUFFER)), GL_INVALID_ENUM, "invalid target"); if (framebuffer) @@ -295,20 +385,12 @@ crStateBindFramebufferEXT(GLenum target, GLuint framebuffer) pFBO = (CRFramebufferObject*) crHashtableSearch(g->shared->fbTable, framebuffer); if (!pFBO) { - pFBO = (CRFramebufferObject*) crCalloc(sizeof(CRFramebufferObject)); - CRSTATE_FBO_CHECKERR(!pFBO, GL_OUT_OF_MEMORY, "glBindFramebufferEXT"); - pFBO->id = framebuffer; - pFBO->hwid = framebuffer; - crStateInitFrameBuffer(pFBO); - crHashtableAdd(g->shared->fbTable, framebuffer, pFBO); -#ifndef IN_GUEST - CR_STATE_SHAREDOBJ_USAGE_INIT(pFBO); -#endif + CRSTATE_CHECKERR(!crHashtableIsKeyUsed(g->shared->fbTable, framebuffer), GL_INVALID_OPERATION, "name is not a framebuffer"); + pFBO = crStateFramebufferAllocate(g, framebuffer); } -#ifndef IN_GUEST + CR_STATE_SHAREDOBJ_USAGE_SET(pFBO, g); -#endif } /* @todo: http://www.opengl.org/registry/specs/ARB/framebuffer_object.txt @@ -331,15 +413,29 @@ crStateBindFramebufferEXT(GLenum target, GLuint framebuffer) } } +static void ctStateFramebufferRefsCleanup(CRContext *g, CRFramebufferObject *fb) +{ + CRFramebufferObjectState *fbo = &g->framebufferobject; + if (fbo->readFB==fb) + { + fbo->readFB = NULL; + } + if (fbo->drawFB==fb) + { + fbo->drawFB = NULL; + } + + CR_STATE_SHAREDOBJ_USAGE_CLEAR(fb, g); +} + DECLEXPORT(void) STATE_APIENTRY crStateDeleteFramebuffersEXT(GLsizei n, const GLuint *framebuffers) { CRContext *g = GetCurrentContext(); - CRFramebufferObjectState *fbo = &g->framebufferobject; int i; - CRSTATE_FBO_CHECKERR(g->current.inBeginEnd, GL_INVALID_OPERATION, "called in begin/end"); - CRSTATE_FBO_CHECKERR(n<0, GL_INVALID_OPERATION, "n<0"); + CRSTATE_CHECKERR(g->current.inBeginEnd, GL_INVALID_OPERATION, "called in begin/end"); + CRSTATE_CHECKERR(n<0, GL_INVALID_OPERATION, "n<0"); for (i = 0; i < n; i++) { @@ -349,13 +445,32 @@ crStateDeleteFramebuffersEXT(GLsizei n, const GLuint *framebuffers) fb = (CRFramebufferObject*) crHashtableSearch(g->shared->fbTable, framebuffers[i]); if (fb) { - if (fbo->readFB==fb) - { - fbo->readFB = NULL; - } - if (fbo->drawFB==fb) + int j; + + ctStateFramebufferRefsCleanup(g, fb); + + CR_STATE_SHAREDOBJ_USAGE_FOREACH_USED_IDX(fb, j) { - fbo->drawFB = NULL; + /* saved state version <= SHCROGL_SSM_VERSION_BEFORE_CTXUSAGE_BITS does not have usage bits info, + * so on restore, we set mark bits as used. + * This is why g_pAvailableContexts[j] could be NULL + * also g_pAvailableContexts[0] will hold default context, which we should discard */ + CRContext *ctx = g_pAvailableContexts[j]; + if (j && ctx) + { + CRFramebufferObjectState *ctxFbo; + CRASSERT(ctx); + ctxFbo = &ctx->framebufferobject; + if (ctxFbo->readFB==fb) + crWarning("deleting FBO being used as read buffer by another context %d", ctx->id); + + if (ctxFbo->drawFB==fb) + crWarning("deleting FBO being used as draw buffer by another context %d", ctx->id); + + ctStateFramebufferRefsCleanup(ctx, fb); + } + else + CR_STATE_SHAREDOBJ_USAGE_CLEAR_IDX(fb, j); } crHashtableDelete(g->shared->fbTable, framebuffers[i], crStateFreeFBO); } @@ -380,27 +495,72 @@ unsigned int crLog2Floor(unsigned int x) return (x & 0x0000003f) - 1; } -static void crStateFramebufferTextureCheck(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, - GLboolean *failed, CRFBOAttachmentPoint **ap, CRTextureObj **tobj) +static GLuint crStateFramebufferGet(CRFramebufferObjectState *fbo, GLenum target, CRFramebufferObject **apFBOs) +{ + GLuint cPBOs = 0; + switch (target) + { + case GL_READ_FRAMEBUFFER: + cPBOs = 1; + apFBOs[0] = fbo->readFB; + break; + case GL_DRAW_FRAMEBUFFER: + cPBOs = 1; + apFBOs[0] = fbo->drawFB; + break; + case GL_FRAMEBUFFER: + if (fbo->readFB == fbo->drawFB) + { + cPBOs = 1; + apFBOs[0] = fbo->readFB; + } + else + { + cPBOs = 2; + apFBOs[0] = fbo->readFB; + apFBOs[1] = fbo->drawFB; + } + break; + default: + crWarning("unexpected target value: 0x%x", target); + cPBOs = 0; + break; + } + + return cPBOs; +} + +static GLuint crStateFramebufferTextureCheck(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, + CRFBOAttachmentPoint **aap, CRTextureObj **tobj) { CRContext *g = GetCurrentContext(); CRFramebufferObjectState *fbo = &g->framebufferobject; - CRFramebufferObject *pFBO; + CRFramebufferObject *apFBOs[2]; + GLuint cFBOs = 0, i; GLuint maxtexsizelog2; - *failed = GL_TRUE; + CRSTATE_CHECKERR_RET(g->current.inBeginEnd, GL_INVALID_OPERATION, "called in begin/end", 0); + CRSTATE_CHECKERR_RET(((target!=GL_FRAMEBUFFER_EXT) && (target!=GL_READ_FRAMEBUFFER) && (target!=GL_DRAW_FRAMEBUFFER)), + GL_INVALID_ENUM, "invalid target", 0); - CRSTATE_FBO_CHECKERR(g->current.inBeginEnd, GL_INVALID_OPERATION, "called in begin/end"); - CRSTATE_FBO_CHECKERR(((target!=GL_FRAMEBUFFER_EXT) && (target!=GL_READ_FRAMEBUFFER) && (target!=GL_DRAW_FRAMEBUFFER)), - GL_INVALID_ENUM, "invalid target"); - pFBO = GL_READ_FRAMEBUFFER==target ? fbo->readFB : fbo->drawFB; - CRSTATE_FBO_CHECKERR(!pFBO, GL_INVALID_OPERATION, "no fbo bound"); - CRSTATE_FBO_CHECKERR(!crStateGetFBOAttachmentPoint(pFBO, attachment, ap), GL_INVALID_ENUM, "invalid attachment"); + cFBOs = crStateFramebufferGet(fbo, target, apFBOs); + CRSTATE_CHECKERR_RET(!cFBOs, GL_INVALID_ENUM, "unexpected target", 0); + for (i = 0; i < cFBOs; ++i) + { + CRSTATE_CHECKERR_RET(!apFBOs[i], GL_INVALID_OPERATION, "zero fbo bound", 0); + } + + Assert(cFBOs); + Assert(cFBOs <= 2); + + for (i = 0; i < cFBOs; ++i) + { + CRSTATE_CHECKERR_RET(!crStateGetFBOAttachmentPoint(apFBOs[i], attachment, &aap[i]), GL_INVALID_ENUM, "invalid attachment", 0); + } if (!texture) { - *failed = GL_FALSE; - return; + return cFBOs; } switch (textarget) @@ -428,27 +588,33 @@ static void crStateFramebufferTextureCheck(GLenum target, GLenum attachment, GLe *tobj = crStateTextureGet(textarget, texture); break; default: - CRSTATE_FBO_CHECKERR(GL_TRUE, GL_INVALID_OPERATION, "invalid textarget"); + CRSTATE_CHECKERR_RET(GL_TRUE, GL_INVALID_OPERATION, "invalid textarget", 0); } - CRSTATE_FBO_CHECKERR(!*tobj, GL_INVALID_OPERATION, "invalid textarget/texture combo"); + CRSTATE_CHECKERR_RET(!*tobj, GL_INVALID_OPERATION, "invalid textarget/texture combo", 0); if (GL_TEXTURE_RECTANGLE_ARB==textarget) { - CRSTATE_FBO_CHECKERR(level!=0, GL_INVALID_VALUE, "non zero mipmap level"); + CRSTATE_CHECKERR_RET(level!=0, GL_INVALID_VALUE, "non zero mipmap level", 0); } - CRSTATE_FBO_CHECKERR(level<0, GL_INVALID_VALUE, "level<0"); - CRSTATE_FBO_CHECKERR(level>maxtexsizelog2, GL_INVALID_VALUE, "level too big"); - - *failed = GL_FALSE; + CRSTATE_CHECKERR_RET(level<0, GL_INVALID_VALUE, "level<0", 0); + CRSTATE_CHECKERR_RET(level>maxtexsizelog2, GL_INVALID_VALUE, "level too big", 0); #ifdef IN_GUEST - if ((*ap)->type!=GL_TEXTURE || (*ap)->name!=texture || (*ap)->level!=level) + for (i = 0; i < cFBOs; ++i) { - pFBO->status = GL_FRAMEBUFFER_UNDEFINED; + if ((aap[i])->type!=GL_TEXTURE || (aap[i])->name!=texture || (aap[i])->level!=level) + { + apFBOs[i]->status = GL_FRAMEBUFFER_UNDEFINED; + } } #endif + + Assert(cFBOs); + Assert(cFBOs <= 2); + + return cFBOs; } DECLEXPORT(void) STATE_APIENTRY @@ -456,29 +622,33 @@ crStateFramebufferTexture1DEXT(GLenum target, GLenum attachment, GLenum textarge { CRContext *g = GetCurrentContext(); CRFramebufferObjectState *fbo = &g->framebufferobject; - CRFBOAttachmentPoint *ap; + CRFBOAttachmentPoint *aap[2]; + GLuint cap, i; CRTextureObj *tobj; - GLboolean failed; - crStateFramebufferTextureCheck(target, attachment, textarget, texture, level, &failed, &ap, &tobj); - if (failed) return; + cap = crStateFramebufferTextureCheck(target, attachment, textarget, texture, level, aap, &tobj); + if (!cap) return; if (!texture) { - crStateInitFBOAttachmentPoint(ap); + for (i = 0; i < cap; ++i) + { + crStateInitFBOAttachmentPoint(aap[i]); + } return; } - CRSTATE_FBO_CHECKERR(textarget!=GL_TEXTURE_1D, GL_INVALID_OPERATION, "textarget"); + CRSTATE_CHECKERR(textarget!=GL_TEXTURE_1D, GL_INVALID_OPERATION, "textarget"); -#ifndef IN_GUEST CR_STATE_SHAREDOBJ_USAGE_SET(tobj, g); -#endif - crStateInitFBOAttachmentPoint(ap); - ap->type = GL_TEXTURE; - ap->name = texture; - ap->level = level; + for (i = 0; i < cap; ++i) + { + crStateInitFBOAttachmentPoint(aap[i]); + aap[i]->type = GL_TEXTURE; + aap[i]->name = texture; + aap[i]->level = level; + } } DECLEXPORT(void) STATE_APIENTRY @@ -486,32 +656,36 @@ crStateFramebufferTexture2DEXT(GLenum target, GLenum attachment, GLenum textarge { CRContext *g = GetCurrentContext(); CRFramebufferObjectState *fbo = &g->framebufferobject; - CRFBOAttachmentPoint *ap; + CRFBOAttachmentPoint *aap[2]; + GLuint cap, i; CRTextureObj *tobj; - GLboolean failed; - crStateFramebufferTextureCheck(target, attachment, textarget, texture, level, &failed, &ap, &tobj); - if (failed) return; + cap = crStateFramebufferTextureCheck(target, attachment, textarget, texture, level, aap, &tobj); + if (!cap) return; if (!texture) { - crStateInitFBOAttachmentPoint(ap); + for (i = 0; i < cap; ++i) + { + crStateInitFBOAttachmentPoint(aap[i]); + } return; } - CRSTATE_FBO_CHECKERR(GL_TEXTURE_1D==textarget || GL_TEXTURE_3D==textarget, GL_INVALID_OPERATION, "textarget"); + CRSTATE_CHECKERR(GL_TEXTURE_1D==textarget || GL_TEXTURE_3D==textarget, GL_INVALID_OPERATION, "textarget"); -#ifndef IN_GUEST CR_STATE_SHAREDOBJ_USAGE_SET(tobj, g); -#endif - crStateInitFBOAttachmentPoint(ap); - ap->type = GL_TEXTURE; - ap->name = texture; - ap->level = level; - if (textarget!=GL_TEXTURE_2D && textarget!=GL_TEXTURE_RECTANGLE_ARB) + for (i = 0; i < cap; ++i) { - ap->face = textarget; + crStateInitFBOAttachmentPoint(aap[i]); + aap[i]->type = GL_TEXTURE; + aap[i]->name = texture; + aap[i]->level = level; + if (textarget!=GL_TEXTURE_2D && textarget!=GL_TEXTURE_RECTANGLE_ARB) + { + aap[i]->face = textarget; + } } } @@ -520,31 +694,35 @@ crStateFramebufferTexture3DEXT(GLenum target, GLenum attachment, GLenum textarge { CRContext *g = GetCurrentContext(); CRFramebufferObjectState *fbo = &g->framebufferobject; - CRFBOAttachmentPoint *ap; + CRFBOAttachmentPoint *aap[2]; + GLuint cap, i; CRTextureObj *tobj; - GLboolean failed; - crStateFramebufferTextureCheck(target, attachment, textarget, texture, level, &failed, &ap, &tobj); - if (failed) return; + cap = crStateFramebufferTextureCheck(target, attachment, textarget, texture, level, aap, &tobj); + if (!cap) return; if (!texture) { - crStateInitFBOAttachmentPoint(ap); + for (i = 0; i < cap; ++i) + { + crStateInitFBOAttachmentPoint(aap[i]); + } return; } - CRSTATE_FBO_CHECKERR(zoffset>(g->limits.max3DTextureSize-1), GL_INVALID_VALUE, "zoffset too big"); - CRSTATE_FBO_CHECKERR(textarget!=GL_TEXTURE_3D, GL_INVALID_OPERATION, "textarget"); + CRSTATE_CHECKERR(zoffset>(g->limits.max3DTextureSize-1), GL_INVALID_VALUE, "zoffset too big"); + CRSTATE_CHECKERR(textarget!=GL_TEXTURE_3D, GL_INVALID_OPERATION, "textarget"); -#ifndef IN_GUEST CR_STATE_SHAREDOBJ_USAGE_SET(tobj, g); -#endif - crStateInitFBOAttachmentPoint(ap); - ap->type = GL_TEXTURE; - ap->name = texture; - ap->level = level; - ap->zoffset = zoffset; + for (i = 0; i < cap; ++i) + { + crStateInitFBOAttachmentPoint(aap[i]); + aap[i]->type = GL_TEXTURE; + aap[i]->name = texture; + aap[i]->level = level; + aap[i]->zoffset = zoffset; + } } DECLEXPORT(void) STATE_APIENTRY @@ -552,41 +730,62 @@ crStateFramebufferRenderbufferEXT(GLenum target, GLenum attachment, GLenum rende { CRContext *g = GetCurrentContext(); CRFramebufferObjectState *fbo = &g->framebufferobject; - CRFramebufferObject *pFBO; - CRFBOAttachmentPoint *ap; + CRFramebufferObject *apFBOs[2]; + GLuint cFBOs, i; + CRFBOAttachmentPoint *aap[2]; CRRenderbufferObject *rb; - CRSTATE_FBO_CHECKERR(g->current.inBeginEnd, GL_INVALID_OPERATION, "called in begin/end"); - CRSTATE_FBO_CHECKERR(((target!=GL_FRAMEBUFFER_EXT) && (target!=GL_READ_FRAMEBUFFER) && (target!=GL_DRAW_FRAMEBUFFER)), + CRSTATE_CHECKERR(g->current.inBeginEnd, GL_INVALID_OPERATION, "called in begin/end"); + CRSTATE_CHECKERR(((target!=GL_FRAMEBUFFER_EXT) && (target!=GL_READ_FRAMEBUFFER) && (target!=GL_DRAW_FRAMEBUFFER)), GL_INVALID_ENUM, "invalid target"); - pFBO = GL_READ_FRAMEBUFFER==target ? fbo->readFB : fbo->drawFB; - CRSTATE_FBO_CHECKERR(!pFBO, GL_INVALID_OPERATION, "no fbo bound"); - CRSTATE_FBO_CHECKERR(!crStateGetFBOAttachmentPoint(pFBO, attachment, &ap), GL_INVALID_ENUM, "invalid attachment"); + cFBOs = crStateFramebufferGet(fbo, target, apFBOs); + CRSTATE_CHECKERR(!cFBOs, GL_INVALID_OPERATION, "no fbo bound"); + for (i = 0; i < cFBOs; ++i) + { + CRSTATE_CHECKERR(!apFBOs[i], GL_INVALID_OPERATION, "zero fbo bound"); + } + + for (i = 0; i < cFBOs; ++i) + { + CRSTATE_CHECKERR(!crStateGetFBOAttachmentPoint(apFBOs[i], attachment, &aap[i]), GL_INVALID_ENUM, "invalid attachment"); + } if (!renderbuffer) { -#ifdef IN_GUEST - if (ap->type!=GL_NONE) + for (i = 0; i < cFBOs; ++i) { - pFBO->status = GL_FRAMEBUFFER_UNDEFINED; - } +#ifdef IN_GUEST + if (&aap[i]->type!=GL_NONE) + { + apFBOs[i]->status = GL_FRAMEBUFFER_UNDEFINED; + } #endif - crStateInitFBOAttachmentPoint(ap); + crStateInitFBOAttachmentPoint(aap[i]); + } return; } rb = (CRRenderbufferObject*) crHashtableSearch(g->shared->rbTable, renderbuffer); - CRSTATE_FBO_CHECKERR(!rb, GL_INVALID_OPERATION, "rb doesn't exist"); + if (!rb) + { + CRSTATE_CHECKERR(!crHashtableIsKeyUsed(g->shared->rbTable, renderbuffer), GL_INVALID_OPERATION, "rb doesn't exist"); + rb = crStateRenderbufferAllocate(g, renderbuffer); + } + CR_STATE_SHAREDOBJ_USAGE_SET(rb, g); + + for (i = 0; i < cFBOs; ++i) + { #ifdef IN_GUEST - if (ap->type!=GL_RENDERBUFFER_EXT || ap->name!=renderbuffer) + if (aap[i]->type!=GL_RENDERBUFFER_EXT || aap[i]->name!=renderbuffer) { - pFBO->status = GL_FRAMEBUFFER_UNDEFINED; + apFBOs[i]->status = GL_FRAMEBUFFER_UNDEFINED; } #endif - crStateInitFBOAttachmentPoint(ap); - ap->type = GL_RENDERBUFFER_EXT; - ap->name = renderbuffer; + crStateInitFBOAttachmentPoint(aap[i]); + aap[i]->type = GL_RENDERBUFFER_EXT; + aap[i]->name = renderbuffer; + } } DECLEXPORT(void) STATE_APIENTRY @@ -594,40 +793,87 @@ crStateGetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment, { CRContext *g = GetCurrentContext(); CRFramebufferObjectState *fbo = &g->framebufferobject; - CRFramebufferObject *pFBO; + CRFramebufferObject *apFBOs[2]; + GLint cFBOs = 0, i; CRFBOAttachmentPoint *ap; - CRSTATE_FBO_CHECKERR(g->current.inBeginEnd, GL_INVALID_OPERATION, "called in begin/end"); - CRSTATE_FBO_CHECKERR(((target!=GL_FRAMEBUFFER_EXT) && (target!=GL_READ_FRAMEBUFFER) && (target!=GL_DRAW_FRAMEBUFFER)), + CRSTATE_CHECKERR(g->current.inBeginEnd, GL_INVALID_OPERATION, "called in begin/end"); + CRSTATE_CHECKERR(((target!=GL_FRAMEBUFFER_EXT) && (target!=GL_READ_FRAMEBUFFER) && (target!=GL_DRAW_FRAMEBUFFER)), GL_INVALID_ENUM, "invalid target"); - pFBO = GL_READ_FRAMEBUFFER==target ? fbo->readFB : fbo->drawFB; - CRSTATE_FBO_CHECKERR(!pFBO, GL_INVALID_OPERATION, "no fbo bound"); - CRSTATE_FBO_CHECKERR(!crStateGetFBOAttachmentPoint(pFBO, attachment, &ap), GL_INVALID_ENUM, "invalid attachment"); - switch (pname) + cFBOs = crStateFramebufferGet(fbo, target, apFBOs); + + CRSTATE_CHECKERR(!cFBOs, GL_INVALID_OPERATION, "no fbo bound"); + for (i = 0; i < cFBOs; ++i) { - case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT: - *params = ap->type; - break; - case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT: - CRSTATE_FBO_CHECKERR(ap->type!=GL_RENDERBUFFER_EXT && ap->type!=GL_TEXTURE, GL_INVALID_ENUM, "can't query object name when it's not bound") - *params = ap->name; - break; - case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT: - CRSTATE_FBO_CHECKERR(ap->type!=GL_TEXTURE, GL_INVALID_ENUM, "not a texture"); - *params = ap->level; - break; - case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT: - CRSTATE_FBO_CHECKERR(ap->type!=GL_TEXTURE, GL_INVALID_ENUM, "not a texture"); - *params = ap->face; - break; - case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT: - CRSTATE_FBO_CHECKERR(ap->type!=GL_TEXTURE, GL_INVALID_ENUM, "not a texture"); - *params = ap->zoffset; - break; - default: - CRSTATE_FBO_CHECKERR(GL_TRUE, GL_INVALID_ENUM, "invalid pname"); + CRSTATE_CHECKERR(!apFBOs[i], GL_INVALID_OPERATION, "zero fbo bound"); + } + + if(cFBOs != 1) + { + crWarning("different FBPs attached to draw and read buffers, returning info for the read buffer"); + } + + for (i = 0; i < 1; ++i) + { + CRSTATE_CHECKERR(!crStateGetFBOAttachmentPoint(apFBOs[i], attachment, &ap), GL_INVALID_ENUM, "invalid attachment"); + + switch (pname) + { + case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT: + *params = ap->type; + break; + case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT: + CRSTATE_CHECKERR(ap->type!=GL_RENDERBUFFER_EXT && ap->type!=GL_TEXTURE, GL_INVALID_ENUM, "can't query object name when it's not bound") + *params = ap->name; + break; + case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT: + CRSTATE_CHECKERR(ap->type!=GL_TEXTURE, GL_INVALID_ENUM, "not a texture"); + *params = ap->level; + break; + case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT: + CRSTATE_CHECKERR(ap->type!=GL_TEXTURE, GL_INVALID_ENUM, "not a texture"); + *params = ap->face; + break; + case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT: + CRSTATE_CHECKERR(ap->type!=GL_TEXTURE, GL_INVALID_ENUM, "not a texture"); + *params = ap->zoffset; + break; + default: + CRSTATE_CHECKERR(GL_TRUE, GL_INVALID_ENUM, "invalid pname"); + } + } +} + +DECLEXPORT(GLboolean) STATE_APIENTRY crStateIsFramebufferEXT( GLuint framebuffer ) +{ + CRContext *g = GetCurrentContext(); + + FLUSH(); + + if (g->current.inBeginEnd) { + crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION, + "glIsFramebufferEXT called in begin/end"); + return GL_FALSE; } + + return framebuffer ? crHashtableIsKeyUsed(g->shared->fbTable, framebuffer) : GL_FALSE; +} + +DECLEXPORT(GLboolean) STATE_APIENTRY crStateIsRenderbufferEXT( GLuint renderbuffer ) +{ + CRContext *g = GetCurrentContext(); + + + FLUSH(); + + if (g->current.inBeginEnd) { + crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION, + "glIsRenderbufferEXT called in begin/end"); + return GL_FALSE; + } + + return renderbuffer ? crHashtableIsKeyUsed(g->shared->rbTable, renderbuffer) : GL_FALSE; } DECLEXPORT(void) STATE_APIENTRY @@ -642,8 +888,11 @@ static void crStateSyncRenderbuffersCB(unsigned long key, void *data1, void *dat diff_api.GenRenderbuffersEXT(1, &pRBO->hwid); - diff_api.BindRenderbufferEXT(GL_RENDERBUFFER_EXT, pRBO->hwid); - diff_api.RenderbufferStorageEXT(GL_RENDERBUFFER_EXT, pRBO->internalformat, pRBO->width, pRBO->height); + if (pRBO->width && pRBO->height) + { + diff_api.BindRenderbufferEXT(GL_RENDERBUFFER_EXT, pRBO->hwid); + diff_api.RenderbufferStorageEXT(GL_RENDERBUFFER_EXT, pRBO->internalformat, pRBO->width, pRBO->height); + } } static void crStateSyncAP(CRFBOAttachmentPoint *pAP, GLenum ap, CRContext *ctx) @@ -774,36 +1023,37 @@ crStateFramebufferObjectSwitch(CRContext *from, CRContext *to) } DECLEXPORT(void) STATE_APIENTRY -crStateFramebufferObjectDisableHW(CRContext *ctx, GLuint idFBO) +crStateFramebufferObjectDisableHW(CRContext *ctx, GLuint idDrawFBO, GLuint idReadFBO) { - GLboolean fAdjustDrawReadBuffers = GL_FALSE; + GLenum idDrawBuffer = 0, idReadBuffer = 0; - if (ctx->framebufferobject.drawFB || idFBO) + if (ctx->framebufferobject.drawFB || idDrawFBO) { diff_api.BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, 0); - fAdjustDrawReadBuffers = GL_TRUE; + idDrawBuffer = ctx->buffer.drawBuffer; } - if (ctx->framebufferobject.readFB ||idFBO) + if (ctx->framebufferobject.readFB || idReadFBO) { diff_api.BindFramebufferEXT(GL_READ_FRAMEBUFFER, 0); - fAdjustDrawReadBuffers = GL_TRUE; + idReadBuffer = ctx->buffer.readBuffer; } - if (fAdjustDrawReadBuffers) - { - diff_api.DrawBuffer(GL_BACK); - diff_api.ReadBuffer(GL_BACK); - } + if (idDrawBuffer) + diff_api.DrawBuffer(idDrawBuffer); + if (idReadBuffer) + diff_api.ReadBuffer(idReadBuffer); if (ctx->framebufferobject.renderbuffer) diff_api.BindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); } DECLEXPORT(void) STATE_APIENTRY -crStateFramebufferObjectReenableHW(CRContext *fromCtx, CRContext *toCtx, GLuint idFBO) +crStateFramebufferObjectReenableHW(CRContext *fromCtx, CRContext *toCtx, GLuint idDrawFBO, GLuint idReadFBO) { GLuint idReadBuffer = 0, idDrawBuffer = 0; + if (!fromCtx) + fromCtx = toCtx; /* <- in case fromCtx is zero, set it to toCtx to ensure framebuffer state gets re-enabled correctly */ if ((fromCtx->framebufferobject.drawFB) /* <- the FBO state was reset in crStateFramebufferObjectDisableHW */ && fromCtx->framebufferobject.drawFB == toCtx->framebufferobject.drawFB) /* .. and it was NOT restored properly in crStateFramebufferObjectSwitch */ @@ -811,9 +1061,9 @@ crStateFramebufferObjectReenableHW(CRContext *fromCtx, CRContext *toCtx, GLuint diff_api.BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, toCtx->framebufferobject.drawFB->hwid); idDrawBuffer = toCtx->framebufferobject.drawFB->drawbuffer[0]; } - else if (idFBO && !toCtx->framebufferobject.drawFB) + else if (idDrawFBO && !toCtx->framebufferobject.drawFB) { - diff_api.BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, idFBO); + diff_api.BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, idDrawFBO); idDrawBuffer = GL_COLOR_ATTACHMENT0; } @@ -823,9 +1073,9 @@ crStateFramebufferObjectReenableHW(CRContext *fromCtx, CRContext *toCtx, GLuint diff_api.BindFramebufferEXT(GL_READ_FRAMEBUFFER, toCtx->framebufferobject.readFB->hwid); idReadBuffer = toCtx->framebufferobject.readFB->readbuffer; } - else if (idFBO && !toCtx->framebufferobject.readFB) + else if (idReadFBO && !toCtx->framebufferobject.readFB) { - diff_api.BindFramebufferEXT(GL_READ_FRAMEBUFFER, idFBO); + diff_api.BindFramebufferEXT(GL_READ_FRAMEBUFFER, idReadFBO); idReadBuffer = GL_COLOR_ATTACHMENT0; } diff --git a/src/VBox/GuestHost/OpenGL/state_tracker/state_get.py b/src/VBox/GuestHost/OpenGL/state_tracker/state_get.py index 674eb6b6..759c30d9 100644 --- a/src/VBox/GuestHost/OpenGL/state_tracker/state_get.py +++ b/src/VBox/GuestHost/OpenGL/state_tracker/state_get.py @@ -233,3 +233,5 @@ for rettype in types: print '\t\t\treturn;' print '\t}' print '}' + +from get_components import *
\ No newline at end of file diff --git a/src/VBox/GuestHost/OpenGL/state_tracker/state_get.txt b/src/VBox/GuestHost/OpenGL/state_tracker/state_get.txt index 01974573..150d350b 100644 --- a/src/VBox/GuestHost/OpenGL/state_tracker/state_get.txt +++ b/src/VBox/GuestHost/OpenGL/state_tracker/state_get.txt @@ -80,6 +80,7 @@ GLfloat GL_POINT_SIZE g->point.pointSize GLfloat GL_POINT_SIZE_MIN_ARB g->point.minSize GLfloat GL_POINT_SIZE_MAX_ARB g->point.maxSize GLfloat GL_POINT_FADE_THRESHOLD_SIZE_ARB g->point.fadeThresholdSize +GLfloat GL_POINT_SPRITE_COORD_ORIGIN g->point.spriteCoordOrigin GLfloat GL_POINT_DISTANCE_ATTENUATION_ARB g->point.distanceAttenuation[0] g->point.distanceAttenuation[1] g->point.distanceAttenuation[2] GLboolean GL_NORMALIZE g->transform.normalize @@ -233,13 +234,19 @@ GLint GL_LIST_INDEX g->lists.currentIndex GLenum GL_LIST_MODE g->lists.mode GLint GL_STENCIL_CLEAR_VALUE g->stencil.clearValue -GLint GL_STENCIL_FAIL g->stencil.fail -GLint GL_STENCIL_FUNC g->stencil.func -GLint GL_STENCIL_PASS_DEPTH_FAIL g->stencil.passDepthFail -GLint GL_STENCIL_PASS_DEPTH_PASS g->stencil.passDepthPass -GLint GL_STENCIL_REF g->stencil.ref +GLint GL_STENCIL_FAIL g->stencil.buffers[g->stencil.activeStencilFace==GL_FRONT?CRSTATE_STENCIL_BUFFER_ID_FRONT:CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].fail +GLint GL_STENCIL_BACK_FAIL g->stencil.buffers[g->stencil.activeStencilFace==GL_FRONT?CRSTATE_STENCIL_BUFFER_ID_BACK:CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].fail +GLint GL_STENCIL_FUNC g->stencil.buffers[g->stencil.activeStencilFace==GL_FRONT?CRSTATE_STENCIL_BUFFER_ID_FRONT:CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].func +GLint GL_STENCIL_BACK_FUNC g->stencil.buffers[g->stencil.activeStencilFace==GL_FRONT?CRSTATE_STENCIL_BUFFER_ID_BACK:CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].func +GLint GL_STENCIL_PASS_DEPTH_FAIL g->stencil.buffers[g->stencil.activeStencilFace==GL_FRONT?CRSTATE_STENCIL_BUFFER_ID_FRONT:CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].passDepthFail +GLint GL_STENCIL_BACK_PASS_DEPTH_FAIL g->stencil.buffers[g->stencil.activeStencilFace==GL_FRONT?CRSTATE_STENCIL_BUFFER_ID_BACK:CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].passDepthFail +GLint GL_STENCIL_PASS_DEPTH_PASS g->stencil.buffers[g->stencil.activeStencilFace==GL_FRONT?CRSTATE_STENCIL_BUFFER_ID_FRONT:CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].passDepthPass +GLint GL_STENCIL_BACK_PASS_DEPTH_PASS g->stencil.buffers[g->stencil.activeStencilFace==GL_FRONT?CRSTATE_STENCIL_BUFFER_ID_BACK:CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].passDepthPass +GLint GL_STENCIL_REF g->stencil.buffers[g->stencil.activeStencilFace==GL_FRONT?CRSTATE_STENCIL_BUFFER_ID_FRONT:CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].ref +GLint GL_STENCIL_BACK_REF g->stencil.buffers[g->stencil.activeStencilFace==GL_FRONT?CRSTATE_STENCIL_BUFFER_ID_BACK:CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].ref GLboolean GL_STENCIL_TEST g->stencil.stencilTest -GLint GL_STENCIL_VALUE_MASK g->stencil.mask +GLint GL_STENCIL_VALUE_MASK g->stencil.buffers[g->stencil.activeStencilFace==GL_FRONT?CRSTATE_STENCIL_BUFFER_ID_FRONT:CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].mask +GLint GL_STENCIL_BACK_VALUE_MASK g->stencil.buffers[g->stencil.activeStencilFace==GL_FRONT?CRSTATE_STENCIL_BUFFER_ID_BACK:CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].mask GLint GL_STENCIL_WRITEMASK g->stencil.writeMask GLfloat GL_CURRENT_INDEX g->current.colorIndex @@ -308,3 +315,5 @@ GLint GL_RENDERBUFFER_BINDING_EXT (g->framebufferobject.renderbuffer?g->framebuf #CVA GLint GL_ARRAY_ELEMENT_LOCK_FIRST_EXT g->client.array.lockFirst GLint GL_ARRAY_ELEMENT_LOCK_COUNT_EXT g->client.array.lockCount + +GLint GL_ACTIVE_STENCIL_FACE_EXT g->stencil.activeStencilFace
\ No newline at end of file diff --git a/src/VBox/GuestHost/OpenGL/state_tracker/state_glsl.c b/src/VBox/GuestHost/OpenGL/state_tracker/state_glsl.c index 7741007b..48d5a7e8 100644 --- a/src/VBox/GuestHost/OpenGL/state_tracker/state_glsl.c +++ b/src/VBox/GuestHost/OpenGL/state_tracker/state_glsl.c @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2009 Oracle Corporation + * Copyright (C) 2009-2012 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -258,6 +258,21 @@ DECLEXPORT(GLuint) STATE_APIENTRY crStateGLSLProgramHWIDtoID(GLuint hwid) return parms.id; } +DECLEXPORT(GLuint) STATE_APIENTRY crStateDeleteObjectARB( VBoxGLhandleARB obj ) +{ + GLuint hwId = crStateGetProgramHWID(obj); + if (hwId) + { + crStateDeleteProgram(obj); + } + else + { + hwId = crStateGetShaderHWID(obj); + crStateDeleteShader(obj); + } + return hwId; +} + DECLEXPORT(GLuint) STATE_APIENTRY crStateCreateShader(GLuint hwid, GLenum type) { CRGLSLShader *pShader; @@ -267,13 +282,17 @@ DECLEXPORT(GLuint) STATE_APIENTRY crStateCreateShader(GLuint hwid, GLenum type) #ifdef IN_GUEST CRASSERT(!crStateGetShaderObj(stateId)); #else - /* the id may not necesserily be hwid after save state restoration */ - while ((pShader = crStateGetShaderObj(stateId)) != NULL) + /* the proogram and shader names must not intersect because DeleteObjectARB must distinguish between them + * see crStateDeleteObjectARB + * this is why use programs table for shader keys allocation */ + stateId = crHashtableAllocKeys(g->glsl.programs, 1); + if (!stateId) { - GLuint newStateId = stateId + 7; - crDebug("Shader object %d already exists, generating a new one, %d", stateId, newStateId); - stateId = newStateId; + crWarning("failed to allocate program key"); + return 0; } + + Assert((pShader = crStateGetShaderObj(stateId)) == NULL); #endif pShader = (CRGLSLShader *) crAlloc(sizeof(*pShader)); @@ -311,19 +330,18 @@ DECLEXPORT(GLuint) STATE_APIENTRY crStateCreateProgram(GLuint hwid) CRASSERT(!crStateGetProgramObj(stateId)); } #else - /* the id may not necesserily be hwid after save state restoration */ - while ((pProgram = crStateGetProgramObj(stateId)) != NULL) + stateId = crHashtableAllocKeys(g->glsl.programs, 1); + if (!stateId) { - GLuint newStateId = stateId + 7; - crDebug("Program object %d already exists, generating a new one, %d", stateId, newStateId); - stateId = newStateId; + crWarning("failed to allocate program key"); + return 0; } #endif pProgram = (CRGLSLProgram *) crAlloc(sizeof(*pProgram)); if (!pProgram) { - crWarning("crStateCreateShader: Out of memory!"); + crWarning("crStateCreateProgram: Out of memory!"); return 0; } @@ -363,6 +381,11 @@ DECLEXPORT(void) STATE_APIENTRY crStateCompileShader(GLuint shader) pShader->compiled = GL_TRUE; } +static void crStateDbgCheckNoProgramOfId(void *data) +{ + crError("Unexpected Program id"); +} + DECLEXPORT(void) STATE_APIENTRY crStateDeleteShader(GLuint shader) { CRGLSLShader *pShader = crStateGetShaderObj(shader); @@ -378,6 +401,10 @@ DECLEXPORT(void) STATE_APIENTRY crStateDeleteShader(GLuint shader) { CRContext *g = GetCurrentContext(); crHashtableDelete(g->glsl.shaders, shader, crStateFreeGLSLShader); + /* since we use programs table for key allocation key allocation, we need to + * free the key in the programs table. + * See comment in crStateCreateShader */ + crHashtableDelete(g->glsl.programs, shader, crStateDbgCheckNoProgramOfId); } } @@ -598,8 +625,7 @@ DECLEXPORT(void) STATE_APIENTRY crStateBindAttribLocation(GLuint program, GLuint { if (!crStrcmp(pProgram->currentState.pAttribs[i].name, name)) { - crFree(pProgram->currentState.pAttribs[i].name); - pProgram->currentState.pAttribs[i].name = crStrdup(name); + pProgram->currentState.pAttribs[i].index = index; return; } } @@ -1186,6 +1212,7 @@ static void crStateGLSLCreateProgramCB(unsigned long key, void *data1, void *dat DECLEXPORT(void) STATE_APIENTRY crStateGLSLSwitch(CRContext *from, CRContext *to) { + GLboolean fForceUseProgramSet = GL_FALSE; if (to->glsl.bResyncNeeded) { to->glsl.bResyncNeeded = GL_FALSE; @@ -1194,10 +1221,13 @@ DECLEXPORT(void) STATE_APIENTRY crStateGLSLSwitch(CRContext *from, CRContext *to crHashtableWalk(to->glsl.programs, crStateGLSLCreateProgramCB, to); + /* crStateGLSLCreateProgramCB changes the current program, ensure we have the proper program re-sored */ + fForceUseProgramSet = GL_TRUE; + crHashtableWalk(to->glsl.shaders, crStateGLSLSyncShadersCB, NULL); } - if (to->glsl.activeProgram != from->glsl.activeProgram) + if (to->glsl.activeProgram != from->glsl.activeProgram || fForceUseProgramSet) { diff_api.UseProgram(to->glsl.activeProgram ? to->glsl.activeProgram->hwid : 0); } diff --git a/src/VBox/GuestHost/OpenGL/state_tracker/state_init.c b/src/VBox/GuestHost/OpenGL/state_tracker/state_init.c index f8ac1f5a..49bcd38b 100644 --- a/src/VBox/GuestHost/OpenGL/state_tracker/state_init.c +++ b/src/VBox/GuestHost/OpenGL/state_tracker/state_init.c @@ -17,13 +17,14 @@ CRContext *__currentContext = NULL; #endif CRStateBits *__currentBits = NULL; -GLboolean g_availableContexts[CR_MAX_CONTEXTS]; +CRContext *g_pAvailableContexts[CR_MAX_CONTEXTS]; +uint32_t g_cContexts = 0; static CRSharedState *gSharedState=NULL; static CRContext *defaultContext = NULL; -static GLboolean g_bVBoxEnableDiffOnMakeCurrent = GL_TRUE; +GLboolean g_bVBoxEnableDiffOnMakeCurrent = GL_TRUE; /** @@ -60,7 +61,6 @@ crStateDeleteTextureCallback(void *texObj) crStateDeleteTextureObject((CRTextureObj *) texObj); } -#ifndef IN_GUEST typedef struct CR_STATE_RELEASEOBJ { CRContext *pCtx; @@ -102,7 +102,7 @@ static void ReleaseRBOCallback(unsigned long key, void *data1, void *data2) if (!CR_STATE_SHAREDOBJ_USAGE_IS_USED(pObj)) crHashtableDelete(pData->s->rbTable, key, crStateFreeRBO); } -#endif + /** * Decrement shared state's refcount and delete when it hits zero. */ @@ -110,6 +110,7 @@ DECLEXPORT(void) crStateFreeShared(CRContext *pContext, CRSharedState *s) { s->refCount--; + Assert(s->refCount >= 0); if (s->refCount <= 0) { if (s==gSharedState) { @@ -122,8 +123,7 @@ crStateFreeShared(CRContext *pContext, CRSharedState *s) crFreeHashtable(s->rbTable, crStateFreeRBO); crFree(s); } -#ifndef IN_GUEST - else + else if (pContext) { /* evaluate usage bits*/ CR_STATE_RELEASEOBJ CbData; @@ -134,7 +134,22 @@ crStateFreeShared(CRContext *pContext, CRSharedState *s) crHashtableWalk(s->fbTable, ReleaseFBOCallback, &CbData); crHashtableWalk(s->rbTable, ReleaseRBOCallback, &CbData); } -#endif +} + +DECLEXPORT(CRSharedState *) crStateGlobalSharedAcquire() +{ + if (!gSharedState) + { + crWarning("No Global Shared State!"); + return NULL; + } + gSharedState->refCount++; + return gSharedState; +} + +DECLEXPORT(void) crStateGlobalSharedRelease() +{ + crStateFreeShared(NULL, gSharedState); } DECLEXPORT(void) STATE_APIENTRY @@ -218,11 +233,26 @@ static CRContext * crStateCreateContextId(int i, const CRLimitsState *limits, GLint visBits, CRContext *shareCtx) { - CRContext *ctx = (CRContext *) crCalloc( sizeof( *ctx ) ); + CRContext *ctx; int j; int node32 = i >> 5; int node = i & 0x1f; + if (g_pAvailableContexts[i] != NULL) + { + crWarning("trying to create context with used id"); + return NULL; + } + + ctx = (CRContext *) crCalloc( sizeof( *ctx ) ); + if (!ctx) + { + crWarning("failed to allocate context"); + return NULL; + } + g_pAvailableContexts[i] = ctx; + ++g_cContexts; + CRASSERT(g_cContexts < RT_ELEMENTS(g_pAvailableContexts)); ctx->id = i; #ifdef CHROMIUM_THREADSAFE VBoxTlsRefInit(ctx, crStateContextDtor); @@ -252,7 +282,7 @@ crStateCreateContextId(int i, const CRLimitsState *limits, crStateExtensionsInit( &(ctx->limits), &(ctx->extensions) ); crStateBufferObjectInit( ctx ); /* must precede client state init! */ - crStateClientInit( &(ctx->client) ); + crStateClientInit( ctx ); crStateBufferInit( ctx ); crStateCurrentInit( ctx ); @@ -330,7 +360,23 @@ crStateCreateContextId(int i, const CRLimitsState *limits, static void crStateFreeContext(CRContext *ctx) { - crStateClientDestroy( &(ctx->client) ); +#ifndef DEBUG_misha + CRASSERT(g_pAvailableContexts[ctx->id] == ctx); +#endif + if (g_pAvailableContexts[ctx->id] == ctx) + { + g_pAvailableContexts[ctx->id] = NULL; + --g_cContexts; + CRASSERT(g_cContexts < RT_ELEMENTS(g_pAvailableContexts)); + } + else + { +#ifndef DEBUG_misha + crWarning("freeing context %p, id(%d) not being in the context list", ctx, ctx->id); +#endif + } + + crStateClientDestroy( ctx ); crStateLimitsDestroy( &(ctx->limits) ); crStateBufferObjectDestroy( ctx ); crStateEvaluatorDestroy( ctx ); @@ -377,10 +423,15 @@ void crStateInit(void) crStateClientInitBits( &(__currentBits->client) ); crStateLightingInitBits( &(__currentBits->lighting) ); } else + { +#ifndef DEBUG_misha crWarning("State tracker is being re-initialized..\n"); +#endif + } for (i=0;i<CR_MAX_CONTEXTS;i++) - g_availableContexts[i] = 0; + g_pAvailableContexts[i] = NULL; + g_cContexts = 0; #ifdef CHROMIUM_THREADSAFE if (!__isContextTLSInited) @@ -411,11 +462,14 @@ void crStateInit(void) /* Reset diff_api */ crMemZero(&diff_api, sizeof(SPUDispatchTable)); + Assert(!gSharedState); + gSharedState = NULL; + /* Allocate the default/NULL context */ + CRASSERT(g_pAvailableContexts[0] == NULL); defaultContext = crStateCreateContextId(0, NULL, CR_RGB_BIT, NULL); - CRASSERT(g_availableContexts[0] == 0); - g_availableContexts[0] = 1; /* in use forever */ - + CRASSERT(g_pAvailableContexts[0] == defaultContext); + CRASSERT(g_cContexts == 1); #ifdef CHROMIUM_THREADSAFE SetCurrentContext(defaultContext); #else @@ -425,6 +479,7 @@ void crStateInit(void) void crStateDestroy(void) { + int i; if (__currentBits) { crStateClientDestroyBits(&(__currentBits->client)); @@ -433,6 +488,25 @@ void crStateDestroy(void) __currentBits = NULL; } + SetCurrentContext(NULL); + + for (i = CR_MAX_CONTEXTS-1; i >= 0; i--) + { + if (g_pAvailableContexts[i]) + { +#ifdef CHROMIUM_THREADSAFE + if (VBoxTlsRefIsFunctional(g_pAvailableContexts[i])) + VBoxTlsRefRelease(g_pAvailableContexts[i]); +#else + crStateFreeContext(g_pAvailableContexts[i]); +#endif + } + } + + /* default context was stored in g_pAvailableContexts[0], so it was destroyed already */ + defaultContext = NULL; + + #ifdef CHROMIUM_THREADSAFE crFreeTSD(&__contextTSD); __isContextTLSInited = 0; @@ -452,7 +526,7 @@ void crStateDestroy(void) * (i.e. the old context to the new context). The transformation * is accomplished by calling GL functions through the 'diff_api' * so that the downstream GL machine (represented by the __currentContext - * structure) is updated to reflect the new context state. Finally, + * structure) is updated to reflect the new context state. Finally, * we point __currentContext to the new context. * * A subtle problem we have to deal with is context destruction. @@ -485,35 +559,46 @@ void crStateDestroy(void) CRContext * crStateCreateContext(const CRLimitsState *limits, GLint visBits, CRContext *share) { - int i; + return crStateCreateContextEx(limits, visBits, share, -1); +} +CRContext * +crStateCreateContextEx(const CRLimitsState *limits, GLint visBits, CRContext *share, GLint presetID) +{ /* Must have created the default context via crStateInit() first */ CRASSERT(defaultContext); - for (i = 1 ; i < CR_MAX_CONTEXTS ; i++) + if (presetID>0) { - if (!g_availableContexts[i]) + if(g_pAvailableContexts[presetID]) { - g_availableContexts[i] = 1; /* it's no longer available */ - return crStateCreateContextId( i, limits, visBits, share ); + crWarning("requesting to create context with already allocated id"); + return NULL; } } - crError( "Out of available contexts in crStateCreateContexts (max %d)", - CR_MAX_CONTEXTS ); - /* never get here */ - return NULL; -} - -CRContext * -crStateCreateContextEx(const CRLimitsState *limits, GLint visBits, CRContext *share, GLint presetID) -{ - if (presetID>0) + else { - CRASSERT(!g_availableContexts[presetID]); - g_availableContexts[presetID] = 1; - return crStateCreateContextId(presetID, limits, visBits, share); + int i; + + for (i = 1 ; i < CR_MAX_CONTEXTS ; i++) + { + if (!g_pAvailableContexts[i]) + { + presetID = i; + break; + } + } + + if (presetID<=0) + { + crError( "Out of available contexts in crStateCreateContexts (max %d)", + CR_MAX_CONTEXTS ); + /* never get here */ + return NULL; + } } - else return crStateCreateContext(limits, visBits, share); + + return crStateCreateContextId(presetID, limits, visBits, share); } void crStateDestroyContext( CRContext *ctx ) @@ -535,9 +620,17 @@ void crStateDestroyContext( CRContext *ctx ) /* ensure matrix state is also current */ crStateMatrixMode(defaultContext->transform.matrixMode); } - g_availableContexts[ctx->id] = 0; #ifdef CHROMIUM_THREADSAFE + VBoxTlsRefMarkDestroy(ctx); +# ifdef IN_GUEST + if (VBoxTlsRefCountGet(ctx) > 1 && ctx->shared == gSharedState) + { + /* we always need to free the global shared state to prevent the situation when guest thinks the shared objects are still valid, while host destroys them */ + crStateFreeShared(ctx, ctx->shared); + ctx->shared = crStateAllocShared(); + } +# endif VBoxTlsRefRelease(ctx); #else crStateFreeContext(ctx); diff --git a/src/VBox/GuestHost/OpenGL/state_tracker/state_lists.c b/src/VBox/GuestHost/OpenGL/state_tracker/state_lists.c index 09831311..005f9462 100644 --- a/src/VBox/GuestHost/OpenGL/state_tracker/state_lists.c +++ b/src/VBox/GuestHost/OpenGL/state_tracker/state_lists.c @@ -30,7 +30,7 @@ void crStateListsInit(CRContext *ctx) RESET(lb->dirty, ctx->bitid); } -/*#define CRSTATE_DEBUG_QUERY_HW_STATE*/ +//#define CRSTATE_DEBUG_QUERY_HW_STATE #ifndef CRSTATE_DEBUG_QUERY_HW_STATE # define CRSTATE_SET_CAP(state, value, format) g->state=value @@ -168,7 +168,7 @@ void crStateListsInit(CRContext *ctx) } \ } -void STATE_APIENTRY crStateQueryHWState() +void STATE_APIENTRY crStateQueryHWState(GLuint fbFbo, GLuint bbFbo) { CRContext *g = GetCurrentContext(); CRStateBits *sb = GetCurrentBits(); @@ -217,12 +217,68 @@ void STATE_APIENTRY crStateQueryHWState() if (CHECKDIRTY(sb->buffer.drawBuffer, negbitID)) { - CRSTATE_SET_ENUM(buffer.drawBuffer, GL_DRAW_BUFFER); + GLuint buf = 0; + diff_api.GetIntegerv(GL_DRAW_BUFFER, &buf); + + if (buf == GL_COLOR_ATTACHMENT0_EXT && (bbFbo || fbFbo)) + { + GLuint binding = 0; + diff_api.GetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &binding); + if (!binding) + { + crWarning("HW state synch: GL_DRAW_FRAMEBUFFER_BINDING is NULL"); + } + + if (bbFbo && binding == bbFbo) + { + g->buffer.drawBuffer = GL_BACK; + } + else if (fbFbo && binding == fbFbo) + { + g->buffer.drawBuffer = GL_FRONT; + } + else + { + g->buffer.drawBuffer = buf; + } + } + else + { + g->buffer.drawBuffer = buf; + } } if (CHECKDIRTY(sb->buffer.readBuffer, negbitID)) { - CRSTATE_SET_ENUM(buffer.readBuffer, GL_READ_BUFFER); + GLuint buf = 0; + diff_api.GetIntegerv(GL_READ_BUFFER, &buf); + + if (buf == GL_COLOR_ATTACHMENT0_EXT && (bbFbo || fbFbo)) + { + GLuint binding = 0; + diff_api.GetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &binding); + if (!binding) + { + crWarning("HW state synch: GL_READ_FRAMEBUFFER_BINDING is NULL"); + } + + if (bbFbo && binding == bbFbo) + { + g->buffer.readBuffer = GL_BACK; + } + else if (fbFbo && binding == fbFbo) + { + g->buffer.readBuffer = GL_FRONT; + } + else + { + g->buffer.readBuffer = buf; + } + } + else + { + g->buffer.readBuffer = buf; + } } if (CHECKDIRTY(sb->buffer.indexMask, negbitID)) @@ -295,23 +351,122 @@ void STATE_APIENTRY crStateQueryHWState() if (CHECKDIRTY(sb->stencil.dirty, negbitID)) { + GLenum activeFace; + GLboolean backIsSet = GL_FALSE, frontIsSet = GL_FALSE; + if (CHECKDIRTY(sb->stencil.enable, negbitID)) { CRSTATE_SET_ENABLED(stencil.stencilTest, GL_STENCIL_TEST); } - if (CHECKDIRTY(sb->stencil.func, negbitID)) + if (CHECKDIRTY(sb->stencil.enableTwoSideEXT, negbitID)) { - CRSTATE_SET_ENUM(stencil.func, GL_STENCIL_FUNC); - CRSTATE_SET_INT(stencil.ref, GL_STENCIL_REF); - CRSTATE_SET_INT(stencil.mask, GL_STENCIL_VALUE_MASK); + CRSTATE_SET_ENABLED(stencil.stencilTwoSideEXT, GL_STENCIL_TEST_TWO_SIDE_EXT); } - if (CHECKDIRTY(sb->stencil.op, negbitID)) + if (CHECKDIRTY(sb->stencil.activeStencilFace, negbitID)) { - CRSTATE_SET_ENUM(stencil.fail, GL_STENCIL_FAIL); - CRSTATE_SET_ENUM(stencil.passDepthFail, GL_STENCIL_PASS_DEPTH_FAIL); - CRSTATE_SET_ENUM(stencil.passDepthPass, GL_STENCIL_PASS_DEPTH_PASS); + CRSTATE_SET_ENUM(stencil.activeStencilFace, GL_ACTIVE_STENCIL_FACE_EXT); + } + + activeFace = g->stencil.activeStencilFace; + + +#define CRSTATE_SET_STENCIL_FUNC(_idx, _suff) do { \ + CRSTATE_SET_ENUM(stencil.buffers[(_idx)].func, GL_STENCIL##_suff##FUNC); \ + CRSTATE_SET_INT(stencil.buffers[(_idx)].ref, GL_STENCIL##_suff##REF); \ + CRSTATE_SET_INT(stencil.buffers[(_idx)].mask, GL_STENCIL##_suff##VALUE_MASK); \ + } while (0) + +#define CRSTATE_SET_STENCIL_OP(_idx, _suff) do { \ + CRSTATE_SET_ENUM(stencil.buffers[(_idx)].fail, GL_STENCIL##_suff##FAIL); \ + CRSTATE_SET_ENUM(stencil.buffers[(_idx)].passDepthFail, GL_STENCIL##_suff##PASS_DEPTH_FAIL); \ + CRSTATE_SET_ENUM(stencil.buffers[(_idx)].passDepthPass, GL_STENCIL##_suff##PASS_DEPTH_PASS); \ + } while (0) + + /* func */ + + if (CHECKDIRTY(sb->stencil.bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_BACK].func, negbitID)) + { + /* this if branch is not needed here actually, just in case ogl drivers misbehave */ + if (activeFace == GL_BACK) + { + diff_api.ActiveStencilFaceEXT(GL_FRONT); + activeFace = GL_FRONT; + } + + CRSTATE_SET_STENCIL_FUNC(CRSTATE_STENCIL_BUFFER_ID_BACK, _BACK_); + backIsSet = GL_TRUE; + } + + if (CHECKDIRTY(sb->stencil.bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT].func, negbitID)) + { + if (activeFace == GL_BACK) + { + diff_api.ActiveStencilFaceEXT(GL_FRONT); + activeFace = GL_FRONT; + } + CRSTATE_SET_STENCIL_FUNC(CRSTATE_STENCIL_BUFFER_ID_FRONT, _); + frontIsSet = GL_TRUE; + } + + if ((!frontIsSet || !backIsSet) && CHECKDIRTY(sb->stencil.bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT_AND_BACK].func, negbitID)) + { + if (activeFace == GL_BACK) + { + diff_api.ActiveStencilFaceEXT(GL_FRONT); + activeFace = GL_FRONT; + } + CRSTATE_SET_STENCIL_FUNC(CRSTATE_STENCIL_BUFFER_ID_FRONT, _); + if (!backIsSet) + { + g->stencil.buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].func = g->stencil.buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].func; + g->stencil.buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].ref = g->stencil.buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].ref; + g->stencil.buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].mask = g->stencil.buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].mask; + } + } + + /* op */ + backIsSet = GL_FALSE, frontIsSet = GL_FALSE; + + if (CHECKDIRTY(sb->stencil.bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_BACK].op, negbitID)) + { + /* this if branch is not needed here actually, just in case ogl drivers misbehave */ + if (activeFace == GL_BACK) + { + diff_api.ActiveStencilFaceEXT(GL_FRONT); + activeFace = GL_FRONT; + } + + CRSTATE_SET_STENCIL_OP(CRSTATE_STENCIL_BUFFER_ID_BACK, _BACK_); + backIsSet = GL_TRUE; + } + + if (CHECKDIRTY(sb->stencil.bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT].op, negbitID)) + { + if (activeFace == GL_BACK) + { + diff_api.ActiveStencilFaceEXT(GL_FRONT); + activeFace = GL_FRONT; + } + CRSTATE_SET_STENCIL_OP(CRSTATE_STENCIL_BUFFER_ID_FRONT, _); + frontIsSet = GL_TRUE; + } + + if ((!frontIsSet || !backIsSet) && CHECKDIRTY(sb->stencil.bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT_AND_BACK].op, negbitID)) + { + if (activeFace == GL_BACK) + { + diff_api.ActiveStencilFaceEXT(GL_FRONT); + activeFace = GL_FRONT; + } + CRSTATE_SET_STENCIL_OP(CRSTATE_STENCIL_BUFFER_ID_FRONT, _); + if (!backIsSet) + { + g->stencil.buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].fail = g->stencil.buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].fail; + g->stencil.buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].passDepthFail = g->stencil.buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthFail; + g->stencil.buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].passDepthPass = g->stencil.buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthPass; + } } if (CHECKDIRTY(sb->stencil.clearValue, negbitID)) @@ -499,12 +654,12 @@ void STATE_APIENTRY crStateQueryHWState() { CRSTATE_SET_MATERIAL_COLOR(lighting.ambient[0], GL_FRONT, GL_AMBIENT); CRSTATE_SET_MATERIAL_COLOR(lighting.ambient[1], GL_BACK, GL_AMBIENT); - CRSTATE_SET_MATERIAL_COLOR(lighting.diffuse[0], GL_FRONT, GL_AMBIENT); - CRSTATE_SET_MATERIAL_COLOR(lighting.diffuse[1], GL_BACK, GL_AMBIENT); - CRSTATE_SET_MATERIAL_COLOR(lighting.specular[0], GL_FRONT, GL_AMBIENT); - CRSTATE_SET_MATERIAL_COLOR(lighting.specular[1], GL_BACK, GL_AMBIENT); - CRSTATE_SET_MATERIAL_COLOR(lighting.emission[0], GL_FRONT, GL_AMBIENT); - CRSTATE_SET_MATERIAL_COLOR(lighting.emission[1], GL_BACK, GL_AMBIENT); + CRSTATE_SET_MATERIAL_COLOR(lighting.diffuse[0], GL_FRONT, GL_DIFFUSE); + CRSTATE_SET_MATERIAL_COLOR(lighting.diffuse[1], GL_BACK, GL_DIFFUSE); + CRSTATE_SET_MATERIAL_COLOR(lighting.specular[0], GL_FRONT, GL_SPECULAR); + CRSTATE_SET_MATERIAL_COLOR(lighting.specular[1], GL_BACK, GL_SPECULAR); + CRSTATE_SET_MATERIAL_COLOR(lighting.emission[0], GL_FRONT, GL_EMISSION); + CRSTATE_SET_MATERIAL_COLOR(lighting.emission[1], GL_BACK, GL_EMISSION); CRSTATE_SET_MATERIAL_F(lighting.shininess[0], GL_FRONT, GL_SHININESS); CRSTATE_SET_MATERIAL_F(lighting.shininess[1], GL_BACK, GL_SHININESS); } @@ -1093,7 +1248,7 @@ void STATE_APIENTRY crStateNewList (GLuint list, GLenum mode) l->mode = mode; } -void STATE_APIENTRY crStateEndList (void) +void STATE_APIENTRY crStateEndList (void) { CRContext *g = GetCurrentContext(); CRListsState *l = &(g->lists); @@ -1110,13 +1265,6 @@ void STATE_APIENTRY crStateEndList (void) return; } -#ifndef IN_GUEST - if (l->mode==GL_COMPILE) - { - crStateQueryHWState(); - } -#endif - l->currentIndex = 0; l->mode = 0; } diff --git a/src/VBox/GuestHost/OpenGL/state_tracker/state_point.c b/src/VBox/GuestHost/OpenGL/state_tracker/state_point.c index fbaac24d..de40c089 100644 --- a/src/VBox/GuestHost/OpenGL/state_tracker/state_point.c +++ b/src/VBox/GuestHost/OpenGL/state_tracker/state_point.c @@ -40,6 +40,9 @@ void crStatePointInit (CRContext *ctx) } #endif + p->spriteCoordOrigin = (GLfloat)GL_UPPER_LEFT; + RESET(pb->spriteCoordOrigin, ctx->bitid); + RESET(pb->dirty, ctx->bitid); /* @@ -167,6 +170,17 @@ void STATE_APIENTRY crStatePointParameterfvARB(GLenum pname, const GLfloat *para return; } break; + case GL_POINT_SPRITE_COORD_ORIGIN: + { + GLenum enmVal = (GLenum)params[0]; + if (enmVal != GL_LOWER_LEFT && enmVal != GL_UPPER_LEFT) { + crStateError(__LINE__, __FILE__, GL_INVALID_VALUE, "glPointParameterfvARB invalid GL_POINT_SPRITE_COORD_ORIGIN value: %f", params[0]); + return; + } + p->spriteCoordOrigin = params[0]; + DIRTY(pb->spriteCoordOrigin, g->neg_bitid); + break; + } default: crStateError(__LINE__, __FILE__, GL_INVALID_ENUM, "glPointParameterfvARB invalid enum: %f", pname); return; @@ -186,3 +200,248 @@ void STATE_APIENTRY crStatePointParameteriv(GLenum pname, const GLint *params) GLfloat f_param = (GLfloat) (*params); crStatePointParameterfvARB( pname, &f_param ); } + +void crStatePointDiff(CRPointBits *b, CRbitvalue *bitID, + CRContext *fromCtx, CRContext *toCtx) +{ + CRPointState *from = &(fromCtx->point); + CRPointState *to = &(toCtx->point); + unsigned int j, i; + CRbitvalue nbitID[CR_MAX_BITARRAY]; + Assert(0); + for (j=0;j<CR_MAX_BITARRAY;j++) + nbitID[j] = ~bitID[j]; + i = 0; /* silence compiler */ + if (CHECKDIRTY(b->enableSmooth, bitID)) + { + glAble able[2]; + able[0] = diff_api.Disable; + able[1] = diff_api.Enable; + if (from->pointSmooth != to->pointSmooth) + { + able[to->pointSmooth](GL_POINT_SMOOTH); + from->pointSmooth = to->pointSmooth; + } + CLEARDIRTY(b->enableSmooth, nbitID); + } + if (CHECKDIRTY(b->size, bitID)) + { + if (from->pointSize != to->pointSize) + { + diff_api.PointSize (to->pointSize); + from->pointSize = to->pointSize; + } + CLEARDIRTY(b->size, nbitID); + } + if (CHECKDIRTY(b->minSize, bitID)) + { + if (from->minSize != to->minSize) + { + diff_api.PointParameterfARB (GL_POINT_SIZE_MIN_ARB, to->minSize); + from->minSize = to->minSize; + } + CLEARDIRTY(b->minSize, nbitID); + } + if (CHECKDIRTY(b->maxSize, bitID)) + { + if (from->maxSize != to->maxSize) + { + diff_api.PointParameterfARB (GL_POINT_SIZE_MAX_ARB, to->maxSize); + from->maxSize = to->maxSize; + } + CLEARDIRTY(b->maxSize, nbitID); + } + if (CHECKDIRTY(b->fadeThresholdSize, bitID)) + { + if (from->fadeThresholdSize != to->fadeThresholdSize) + { + diff_api.PointParameterfARB (GL_POINT_FADE_THRESHOLD_SIZE_ARB, to->fadeThresholdSize); + from->fadeThresholdSize = to->fadeThresholdSize; + } + CLEARDIRTY(b->fadeThresholdSize, nbitID); + } + if (CHECKDIRTY(b->spriteCoordOrigin, bitID)) + { + if (from->spriteCoordOrigin != to->spriteCoordOrigin) + { + diff_api.PointParameterfARB (GL_POINT_SPRITE_COORD_ORIGIN, to->spriteCoordOrigin); + from->spriteCoordOrigin = to->spriteCoordOrigin; + } + CLEARDIRTY(b->spriteCoordOrigin, nbitID); + } + if (CHECKDIRTY(b->distanceAttenuation, bitID)) + { + if (from->distanceAttenuation[0] != to->distanceAttenuation[0] || from->distanceAttenuation[1] != to->distanceAttenuation[1] || from->distanceAttenuation[2] != to->distanceAttenuation[2]) { + diff_api.PointParameterfvARB (GL_POINT_DISTANCE_ATTENUATION_ARB, to->distanceAttenuation); + from->distanceAttenuation[0] = to->distanceAttenuation[0]; + from->distanceAttenuation[1] = to->distanceAttenuation[1]; + from->distanceAttenuation[2] = to->distanceAttenuation[2]; + } + CLEARDIRTY(b->distanceAttenuation, nbitID); + } + if (CHECKDIRTY(b->enableSprite, bitID)) + { + glAble able[2]; + able[0] = diff_api.Disable; + able[1] = diff_api.Enable; + if (from->pointSprite != to->pointSprite) + { + able[to->pointSprite](GL_POINT_SPRITE_ARB); + from->pointSprite = to->pointSprite; + } + CLEARDIRTY(b->enableSprite, nbitID); + } + { + unsigned int activeUnit = (unsigned int) -1; + for (i = 0; i < CR_MAX_TEXTURE_UNITS; i++) { + if (CHECKDIRTY(b->coordReplacement[i], bitID)) + { + GLint replacement = to->coordReplacement[i]; + if (activeUnit != i) { + diff_api.ActiveTextureARB(i + GL_TEXTURE0_ARB ); + activeUnit = i; + } + diff_api.TexEnviv(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, &replacement); + from->coordReplacement[i] = to->coordReplacement[i]; + CLEARDIRTY(b->coordReplacement[i], nbitID); + } + } + if (activeUnit != toCtx->texture.curTextureUnit) + diff_api.ActiveTextureARB(GL_TEXTURE0 + toCtx->texture.curTextureUnit); + } + CLEARDIRTY(b->dirty, nbitID); +} + +void crStatePointSwitch(CRPointBits *b, CRbitvalue *bitID, + CRContext *fromCtx, CRContext *toCtx) +{ + CRPointState *from = &(fromCtx->point); + CRPointState *to = &(toCtx->point); + unsigned int j, i; + GLboolean fEnabled; + CRbitvalue nbitID[CR_MAX_BITARRAY]; + for (j=0;j<CR_MAX_BITARRAY;j++) + nbitID[j] = ~bitID[j]; + i = 0; /* silence compiler */ + if (CHECKDIRTY(b->enableSmooth, bitID)) + { + glAble able[2]; + able[0] = diff_api.Disable; + able[1] = diff_api.Enable; + if (from->pointSmooth != to->pointSmooth) + { + able[to->pointSmooth](GL_POINT_SMOOTH); + FILLDIRTY(b->enableSmooth); + FILLDIRTY(b->dirty); + } + CLEARDIRTY(b->enableSmooth, nbitID); + } + if (CHECKDIRTY(b->size, bitID)) + { + if (from->pointSize != to->pointSize) + { + diff_api.PointSize (to->pointSize); + FILLDIRTY(b->size); + FILLDIRTY(b->dirty); + } + CLEARDIRTY(b->size, nbitID); + } + if (CHECKDIRTY(b->minSize, bitID)) + { + if (from->minSize != to->minSize) + { + diff_api.PointParameterfARB (GL_POINT_SIZE_MIN_ARB, to->minSize); + FILLDIRTY(b->minSize); + FILLDIRTY(b->dirty); + } + CLEARDIRTY(b->minSize, nbitID); + } + if (CHECKDIRTY(b->maxSize, bitID)) + { + if (from->maxSize != to->maxSize) + { + diff_api.PointParameterfARB (GL_POINT_SIZE_MAX_ARB, to->maxSize); + FILLDIRTY(b->maxSize); + FILLDIRTY(b->dirty); + } + CLEARDIRTY(b->maxSize, nbitID); + } + if (CHECKDIRTY(b->fadeThresholdSize, bitID)) + { + if (from->fadeThresholdSize != to->fadeThresholdSize) + { + diff_api.PointParameterfARB (GL_POINT_FADE_THRESHOLD_SIZE_ARB, to->fadeThresholdSize); + FILLDIRTY(b->fadeThresholdSize); + FILLDIRTY(b->dirty); + } + CLEARDIRTY(b->fadeThresholdSize, nbitID); + } + if (CHECKDIRTY(b->spriteCoordOrigin, bitID)) + { + if (from->spriteCoordOrigin != to->spriteCoordOrigin) + { + diff_api.PointParameterfARB (GL_POINT_SPRITE_COORD_ORIGIN, to->spriteCoordOrigin); + FILLDIRTY(b->spriteCoordOrigin); + FILLDIRTY(b->dirty); + } + CLEARDIRTY(b->spriteCoordOrigin, nbitID); + } + if (CHECKDIRTY(b->distanceAttenuation, bitID)) + { + if (from->distanceAttenuation[0] != to->distanceAttenuation[0] || from->distanceAttenuation[1] != to->distanceAttenuation[1] || from->distanceAttenuation[2] != to->distanceAttenuation[2]) { + diff_api.PointParameterfvARB (GL_POINT_DISTANCE_ATTENUATION_ARB, to->distanceAttenuation); + FILLDIRTY(b->distanceAttenuation); + FILLDIRTY(b->dirty); + } + CLEARDIRTY(b->distanceAttenuation, nbitID); + } + fEnabled = from->pointSprite; + { + unsigned int activeUnit = (unsigned int) -1; + for (i = 0; i < CR_MAX_TEXTURE_UNITS; i++) { + if (CHECKDIRTY(b->coordReplacement[i], bitID)) + { + if (!fEnabled) + { + diff_api.Enable(GL_POINT_SPRITE_ARB); + fEnabled = GL_TRUE; + } +#if 0 + /*don't set coord replacement, it will be set just before drawing points when necessary, + * to work around gpu driver bugs + * See crServerDispatch[Begin|End|Draw*] */ + GLint replacement = to->coordReplacement[i]; + if (activeUnit != i) { + diff_api.ActiveTextureARB(i + GL_TEXTURE0_ARB ); + activeUnit = i; + } + diff_api.TexEnviv(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, &replacement); +#endif + CLEARDIRTY(b->coordReplacement[i], nbitID); + } + } + if (activeUnit != toCtx->texture.curTextureUnit) + diff_api.ActiveTextureARB(GL_TEXTURE0 + toCtx->texture.curTextureUnit); + } + if (CHECKDIRTY(b->enableSprite, bitID)) + { + glAble able[2]; + able[0] = diff_api.Disable; + able[1] = diff_api.Enable; + if (fEnabled != to->pointSprite) + { + able[to->pointSprite](GL_POINT_SPRITE_ARB); + FILLDIRTY(b->enableSprite); + FILLDIRTY(b->dirty); + } + CLEARDIRTY(b->enableSprite, nbitID); + } + else if (fEnabled != to->pointSprite) + { + glAble able[2]; + able[0] = diff_api.Disable; + able[1] = diff_api.Enable; + able[to->pointSprite](GL_POINT_SPRITE_ARB); + } + CLEARDIRTY(b->dirty, nbitID); +} diff --git a/src/VBox/GuestHost/OpenGL/state_tracker/state_point.txt b/src/VBox/GuestHost/OpenGL/state_tracker/state_point.txt index 69ab8a70..ba92c153 100644 --- a/src/VBox/GuestHost/OpenGL/state_tracker/state_point.txt +++ b/src/VBox/GuestHost/OpenGL/state_tracker/state_point.txt @@ -7,6 +7,7 @@ :minSize:minSize:PointParameterfARB,GL_POINT_SIZE_MIN_ARB :maxSize:maxSize:PointParameterfARB,GL_POINT_SIZE_MAX_ARB :fadeThresholdSize:fadeThresholdSize:PointParameterfARB,GL_POINT_FADE_THRESHOLD_SIZE_ARB +:spriteCoordOrigin:spriteCoordOrigin:PointParameterfARB,GL_POINT_SPRITE_COORD_ORIGIN #:distanceAttenuation:distanceAttenuation:PointParameterfvARB,GL_POINT_DISTANCE_ATTENUATION_ARB -:distanceAttenuation:*if (from->distanceAttenuation[0] != to->distanceAttenuation[0] || from->distanceAttenuation[1] != to->distanceAttenuation[1] || from->distanceAttenuation[2] != to->distanceAttenuation[2]) { -:distanceAttenuation:* diff_api.PointParameterfvARB (GL_POINT_DISTANCE_ATTENUATION_ARB, to->distanceAttenuation); diff --git a/src/VBox/GuestHost/OpenGL/state_tracker/state_polygon.c b/src/VBox/GuestHost/OpenGL/state_tracker/state_polygon.c index 31410bed..611e2f18 100644 --- a/src/VBox/GuestHost/OpenGL/state_tracker/state_polygon.c +++ b/src/VBox/GuestHost/OpenGL/state_tracker/state_polygon.c @@ -180,8 +180,7 @@ void STATE_APIENTRY crStatePolygonStipple (const GLubyte *p) if (!p && !crStateIsBufferBound(GL_PIXEL_UNPACK_BUFFER_ARB)) { - crStateError(__LINE__, __FILE__, GL_NO_ERROR, - "Void pointer passed to PolygonStipple"); + crDebug("Void pointer passed to PolygonStipple"); return; } diff --git a/src/VBox/GuestHost/OpenGL/state_tracker/state_program.c b/src/VBox/GuestHost/OpenGL/state_tracker/state_program.c index 2b0940bb..e8dd5971 100644 --- a/src/VBox/GuestHost/OpenGL/state_tracker/state_program.c +++ b/src/VBox/GuestHost/OpenGL/state_tracker/state_program.c @@ -267,25 +267,10 @@ void STATE_APIENTRY crStateGenProgramsNV(GLsizei n, GLuint *ids) { CRContext *g = GetCurrentContext(); CRProgramState *p = &(g->program); - GLint start, i; - if (g->current.inBeginEnd) { - crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION, - "glGenProgramsNV called in Begin/End"); - return; - } - - if (n < 0) { - crStateError(__LINE__, __FILE__, GL_INVALID_VALUE, "glGenProgramsNV(n)"); - return; - } - - start = crHashtableAllocKeys(p->programHash , n); - for (i = 0; i < n; i++) - ids[i] = (GLuint) (start + i); + crStateGenNames(g, p->programHash, n, ids); } - void STATE_APIENTRY crStateGenProgramsARB(GLsizei n, GLuint *ids) { crStateGenProgramsNV(n, ids); diff --git a/src/VBox/GuestHost/OpenGL/state_tracker/state_snapshot.c b/src/VBox/GuestHost/OpenGL/state_tracker/state_snapshot.c index eadc228a..6b2a5baa 100644 --- a/src/VBox/GuestHost/OpenGL/state_tracker/state_snapshot.c +++ b/src/VBox/GuestHost/OpenGL/state_tracker/state_snapshot.c @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2008 Oracle Corporation + * Copyright (C) 2008-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -85,6 +85,18 @@ static int32_t crStateAllocAndSSMR3GetMem(PSSMHANDLE pSSM, void **pBuffer, size_ } \ } while (0) +#define SHCROGL_ROUNDBOUND(_v, _b) (((_v) + ((_b) - 1)) & ~((_b) - 1)) +#define SHCROGL_ALIGNTAILSIZE(_v, _b) (SHCROGL_ROUNDBOUND((_v),(_b)) - (_v)) +#define SHCROGL_CUT_FOR_OLD_TYPE_TO_ENSURE_ALIGNMENT_SIZE(_type, _field, _oldFieldType, _nextFieldAllignment) (SHCROGL_ALIGNTAILSIZE(((RT_OFFSETOF(_type, _field) + sizeof (_oldFieldType))), (_nextFieldAllignment))) +#define SHCROGL_CUT_FOR_OLD_TYPE_TO_ENSURE_ALIGNMENT(_type, _field, _oldFieldType, _nextFieldAllignment) do { \ + const int32_t cbAlignment = SHCROGL_CUT_FOR_OLD_TYPE_TO_ENSURE_ALIGNMENT_SIZE(_type, _field, _oldFieldType, _nextFieldAllignment); \ + /*AssertCompile(SHCROGL_CUT_TAIL_ALIGNMENT_SIZE(_type, _lastField) >= 0 && SHCROGL_CUT_TAIL_ALIGNMENT_SIZE(_type, _lastField) < sizeof (void*));*/ \ + if (cbAlignment) { \ + rc = SSMR3Skip(pSSM, cbAlignment); \ + } \ + } while (0) + + #define SHCROGL_CUT_TAIL_ALIGNMENT_SIZE(_type, _lastField) (sizeof (_type) - RT_OFFSETOF(_type, _lastField) - RT_SIZEOFMEMB(_type, _lastField)) #define SHCROGL_CUT_TAIL_ALIGNMENT(_type, _lastField) do { \ const int32_t cbAlignment = SHCROGL_CUT_TAIL_ALIGNMENT_SIZE(_type, _lastField); \ @@ -139,6 +151,35 @@ static int32_t crStateLoadTextureUnit_v_BEFORE_CTXUSAGE_BITS(CRTextureUnit *t, P return rc; } +static int crStateLoadStencilPoint_v_37(CRPointState *pPoint, PSSMHANDLE pSSM) +{ + int rc = VINF_SUCCESS; + SHCROGL_GET_STRUCT_HEAD(pPoint, CRPointState, spriteCoordOrigin); + pPoint->spriteCoordOrigin = (GLfloat)GL_UPPER_LEFT; + return rc; +} + +static int32_t crStateLoadStencilState_v_33(CRStencilState *s, PSSMHANDLE pSSM) +{ + CRStencilState_v_33 stencilV33; + int32_t rc = SSMR3GetMem(pSSM, &stencilV33, sizeof (stencilV33)); + AssertRCReturn(rc, rc); + s->stencilTest = stencilV33.stencilTest; + s->stencilTwoSideEXT = GL_FALSE; + s->activeStencilFace = GL_FRONT; + s->clearValue = stencilV33.clearValue; + s->writeMask = stencilV33.writeMask; + s->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].func = stencilV33.func; + s->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].mask = stencilV33.mask; + s->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].ref = stencilV33.ref; + s->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].fail = stencilV33.fail; + s->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthFail = stencilV33.passDepthFail; + s->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthPass = stencilV33.passDepthPass; + s->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK] = s->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT]; + crStateStencilBufferInit(&s->buffers[CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK]); + return VINF_SUCCESS; +} + static int32_t crStateLoadTextureState_v_BEFORE_CTXUSAGE_BITS(CRTextureState *t, PSSMHANDLE pSSM) { GLint i; @@ -202,6 +243,47 @@ static int32_t crStateLoadTextureState_v_BEFORE_CTXUSAGE_BITS(CRTextureState *t, SHCROGL_CUT_TAIL_ALIGNMENT(CRTextureState, unit); + return VINF_SUCCESS; +} + +static int32_t crStateStencilBufferStack_v_33(CRStencilBufferStack *s, PSSMHANDLE pSSM) +{ + CRStencilBufferStack_v_33 stackV33; + int32_t rc = SSMR3GetMem(pSSM, &stackV33, sizeof (stackV33)); + + s->stencilTest = stackV33.stencilTest; + s->stencilTwoSideEXT = GL_FALSE; + s->activeStencilFace = GL_FRONT; + s->clearValue = stackV33.clearValue; + s->writeMask = stackV33.writeMask; + s->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].func = stackV33.func; + s->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].mask = stackV33.mask; + s->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].ref = stackV33.ref; + s->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].fail = stackV33.fail; + s->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthFail = stackV33.passDepthFail; + s->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthPass = stackV33.passDepthPass; + s->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK] = s->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT]; + + s->buffers[CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].func = GL_ALWAYS; + s->buffers[CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].mask = 0xFFFFFFFF; + s->buffers[CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].ref = 0; + s->buffers[CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].fail = GL_KEEP; + s->buffers[CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].passDepthFail = GL_KEEP; + s->buffers[CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].passDepthPass = GL_KEEP; + + return VINF_SUCCESS; +} + +static int32_t crStateLoadAttribState_v_33(CRAttribState *t, PSSMHANDLE pSSM) +{ + int32_t i, rc; + SHCROGL_GET_STRUCT_HEAD(t, CRAttribState, stencilBufferStack); + for (i = 0; i < CR_MAX_ATTRIB_STACK_DEPTH; ++i) + { + rc = crStateStencilBufferStack_v_33(&t->stencilBufferStack[i], pSSM); + AssertRCReturn(rc, rc); + } + SHCROGL_GET_STRUCT_TAIL(t, CRAttribState, textureStackDepth); return rc; } @@ -221,7 +303,14 @@ static int32_t crStateLoadTextureStack_v_BEFORE_CTXUSAGE_BITS(CRTextureStack *t, static int32_t crStateLoadAttribState_v_BEFORE_CTXUSAGE_BITS(CRAttribState *t, PSSMHANDLE pSSM) { int32_t i, rc; - SHCROGL_GET_STRUCT_HEAD(t, CRAttribState, textureStack); + + SHCROGL_GET_STRUCT_HEAD(t, CRAttribState, stencilBufferStack); + for (i = 0; i < CR_MAX_ATTRIB_STACK_DEPTH; ++i) + { + rc = crStateStencilBufferStack_v_33(&t->stencilBufferStack[i], pSSM); + AssertRCReturn(rc, rc); + } + SHCROGL_GET_STRUCT_PART(t, CRAttribState, textureStackDepth, textureStack); for (i = 0; i < CR_MAX_ATTRIB_STACK_DEPTH; ++i) { rc = crStateLoadTextureStack_v_BEFORE_CTXUSAGE_BITS(&t->textureStack[i], pSSM); @@ -1069,6 +1158,15 @@ static void crStateSaveGLSLProgramCB(unsigned long key, void *data1, void *data2 diff_api.GetProgramiv(pProgram->hwid, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxUniformLen); diff_api.GetProgramiv(pProgram->hwid, GL_ACTIVE_UNIFORMS, &activeUniforms); + if (!maxUniformLen) + { + if (activeUniforms) + { + crWarning("activeUniforms (%d), while maxUniformLen is zero", activeUniforms); + activeUniforms = 0; + } + } + if (activeUniforms>0) { name = (GLchar *) crAlloc((maxUniformLen+8)*sizeof(GLchar)); @@ -1148,7 +1246,11 @@ static int32_t crStateSaveClientPointer(CRVertexArrays *pArrays, int32_t index, cp = crStateGetClientPointerByIndex(index, pArrays); - rc = SSMR3PutU32(pSSM, cp->buffer->id); + if (cp->buffer) + rc = SSMR3PutU32(pSSM, cp->buffer->id); + else + rc = SSMR3PutU32(pSSM, 0); + AssertRCReturn(rc, rc); #ifdef CR_EXT_compiled_vertex_array @@ -1304,6 +1406,59 @@ static int32_t crStateLoadCurrentBits(CRStateBits *pBits, PSSMHANDLE pSSM) return VINF_SUCCESS; } +static void crStateSaveKeysCB(unsigned long firstKey, unsigned long count, void *data) +{ + PSSMHANDLE pSSM = (PSSMHANDLE)data; + int rc; + CRASSERT(firstKey); + CRASSERT(count); + rc = SSMR3PutU32(pSSM, firstKey); + CRASSERT(RT_SUCCESS(rc)); + rc = SSMR3PutU32(pSSM, count); + CRASSERT(RT_SUCCESS(rc)); +} + +static int32_t crStateSaveKeys(CRHashTable *pHash, PSSMHANDLE pSSM) +{ + crHashtableWalkKeys(pHash, crStateSaveKeysCB , pSSM); + /* use null terminator */ + SSMR3PutU32(pSSM, 0); + return VINF_SUCCESS; +} + +static int32_t crStateLoadKeys(CRHashTable *pHash, PSSMHANDLE pSSM, uint32_t u32Version) +{ + uint32_t u32Key, u32Count, i; + int rc; + for(;;) + { + rc = SSMR3GetU32(pSSM, &u32Key); + AssertRCReturn(rc, rc); + + if (!u32Key) + return rc; + + rc = SSMR3GetU32(pSSM, &u32Count); + AssertRCReturn(rc, rc); + + CRASSERT(u32Count); + + if (u32Version > SHCROGL_SSM_VERSION_WITH_BUGGY_KEYS) + { + for (i = u32Key; i < u32Count + u32Key; ++i) + { + GLboolean fIsNew = crHashtableAllocRegisterKey(pHash, i); +#if 0 //def DEBUG_misha + CRASSERT(fIsNew); +#endif + } + } + } + + return rc; +} + + int32_t crStateSaveContext(CRContext *pContext, PSSMHANDLE pSSM) { int32_t rc, i; @@ -1312,30 +1467,18 @@ int32_t crStateSaveContext(CRContext *pContext, PSSMHANDLE pSSM) CRASSERT(pContext && pSSM); - pContext->buffer.storedWidth = pContext->buffer.width; - pContext->buffer.storedHeight = pContext->buffer.height; + CRASSERT(pContext->client.attribStackDepth == 0); - CRASSERT(VBoxTlsRefIsFunctional(pContext)); + /* this stuff is not used anymore, zero it up for sanity */ + pContext->buffer.storedWidth = 0; + pContext->buffer.storedHeight = 0; - /* do not increment the saved state version due to VBOXTLSREFDATA addition to CRContext */ - rc = SSMR3PutMem(pSSM, pContext, VBOXTLSREFDATA_OFFSET(CRContext)); - AssertRCReturn(rc, rc); - - /* now store bitid & neg_bitid */ - rc = SSMR3PutMem(pSSM, pContext->bitid, sizeof (pContext->bitid) + sizeof (pContext->neg_bitid)); - AssertRCReturn(rc, rc); + CRASSERT(VBoxTlsRefIsFunctional(pContext)); - /* the pre-VBOXTLSREFDATA CRContext structure might have additional allignment bits before the CRContext::shared */ - ui32 = VBOXTLSREFDATA_OFFSET(CRContext) + sizeof (pContext->bitid) + sizeof (pContext->neg_bitid); - ui32 &= (sizeof (void*) - 1); - if (ui32) - { - void* pTmp = NULL; - rc = SSMR3PutMem(pSSM, &pTmp, ui32); - AssertRCReturn(rc, rc); - } + /* make sure the gl error state is captured by our state mechanism to store the correct gl error value */ + crStateSyncHWErrorState(pContext); - rc = SSMR3PutMem(pSSM, &pContext->shared, sizeof (CRContext) - RT_OFFSETOF(CRContext, shared)); + rc = SSMR3PutMem(pSSM, pContext, sizeof (*pContext)); AssertRCReturn(rc, rc); if (crHashtableNumElements(pContext->shared->dlistTable)>0) @@ -1412,6 +1555,8 @@ int32_t crStateSaveContext(CRContext *pContext, PSSMHANDLE pSSM) if (bSaveShared) { CRASSERT(pContext->shared && pContext->shared->textureTable); + rc = crStateSaveKeys(pContext->shared->textureTable, pSSM); + AssertRCReturn(rc, rc); ui32 = crHashtableNumElements(pContext->shared->textureTable); rc = SSMR3PutU32(pSSM, ui32); AssertRCReturn(rc, rc); @@ -1509,6 +1654,11 @@ int32_t crStateSaveContext(CRContext *pContext, PSSMHANDLE pSSM) #ifdef CR_ARB_vertex_buffer_object /* Save buffer objects */ + if (bSaveShared) + { + rc = crStateSaveKeys(pContext->shared->buffersTable, pSSM); + AssertRCReturn(rc, rc); + } ui32 = bSaveShared? crHashtableNumElements(pContext->shared->buffersTable):0; rc = SSMR3PutU32(pSSM, ui32); AssertRCReturn(rc, rc); @@ -1576,10 +1726,15 @@ int32_t crStateSaveContext(CRContext *pContext, PSSMHANDLE pSSM) /* Save FBOs */ if (bSaveShared) { + rc = crStateSaveKeys(pContext->shared->fbTable, pSSM); + AssertRCReturn(rc, rc); ui32 = crHashtableNumElements(pContext->shared->fbTable); rc = SSMR3PutU32(pSSM, ui32); AssertRCReturn(rc, rc); crHashtableWalk(pContext->shared->fbTable, crStateSaveFramebuffersCB, pSSM); + + rc = crStateSaveKeys(pContext->shared->rbTable, pSSM); + AssertRCReturn(rc, rc); ui32 = crHashtableNumElements(pContext->shared->rbTable); rc = SSMR3PutU32(pSSM, ui32); AssertRCReturn(rc, rc); @@ -1607,72 +1762,6 @@ int32_t crStateSaveContext(CRContext *pContext, PSSMHANDLE pSSM) AssertRCReturn(rc, rc); #endif - if (pContext->buffer.storedWidth && pContext->buffer.storedHeight) - { - CRBufferState *pBuf = &pContext->buffer; - CRPixelPackState packing = pContext->client.pack; - GLint cbData; - void *pData; - - cbData = crPixelSize(GL_RGBA, GL_UNSIGNED_BYTE) * pBuf->storedWidth * pBuf->storedHeight; - pData = crAlloc(cbData); - - if (!pData) - { - return VERR_NO_MEMORY; - } - - diff_api.PixelStorei(GL_PACK_SKIP_ROWS, 0); - diff_api.PixelStorei(GL_PACK_SKIP_PIXELS, 0); - diff_api.PixelStorei(GL_PACK_ALIGNMENT, 1); - diff_api.PixelStorei(GL_PACK_ROW_LENGTH, 0); - diff_api.PixelStorei(GL_PACK_IMAGE_HEIGHT, 0); - diff_api.PixelStorei(GL_PACK_SKIP_IMAGES, 0); - diff_api.PixelStorei(GL_PACK_SWAP_BYTES, 0); - diff_api.PixelStorei(GL_PACK_LSB_FIRST, 0); - - if (pContext->framebufferobject.readFB) - { - diff_api.BindFramebufferEXT(GL_READ_FRAMEBUFFER, 0); - } - if (pContext->bufferobject.packBuffer->hwid>0) - { - diff_api.BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0); - } - - diff_api.ReadBuffer(GL_FRONT); - diff_api.ReadPixels(0, 0, pBuf->storedWidth, pBuf->storedHeight, GL_RGBA, GL_UNSIGNED_BYTE, pData); - rc = SSMR3PutMem(pSSM, pData, cbData); - AssertRCReturn(rc, rc); - - diff_api.ReadBuffer(GL_BACK); - diff_api.ReadPixels(0, 0, pBuf->storedWidth, pBuf->storedHeight, GL_RGBA, GL_UNSIGNED_BYTE, pData); - rc = SSMR3PutMem(pSSM, pData, cbData); - AssertRCReturn(rc, rc); - - if (pContext->bufferobject.packBuffer->hwid>0) - { - diff_api.BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pContext->bufferobject.packBuffer->hwid); - } - if (pContext->framebufferobject.readFB) - { - diff_api.BindFramebufferEXT(GL_READ_FRAMEBUFFER, pContext->framebufferobject.readFB->hwid); - } - diff_api.ReadBuffer(pContext->framebufferobject.readFB ? - pContext->framebufferobject.readFB->readbuffer : pContext->buffer.readBuffer); - - diff_api.PixelStorei(GL_PACK_SKIP_ROWS, packing.skipRows); - diff_api.PixelStorei(GL_PACK_SKIP_PIXELS, packing.skipPixels); - diff_api.PixelStorei(GL_PACK_ALIGNMENT, packing.alignment); - diff_api.PixelStorei(GL_PACK_ROW_LENGTH, packing.rowLength); - diff_api.PixelStorei(GL_PACK_IMAGE_HEIGHT, packing.imageHeight); - diff_api.PixelStorei(GL_PACK_SKIP_IMAGES, packing.skipImages); - diff_api.PixelStorei(GL_PACK_SWAP_BYTES, packing.swapBytes); - diff_api.PixelStorei(GL_PACK_LSB_FIRST, packing.psLSBFirst); - - crFree(pData); - } - return VINF_SUCCESS; } @@ -1693,6 +1782,77 @@ static void crStateFindSharedCB(unsigned long key, void *data1, void *data2) } } +int32_t crStateSaveGlobals(PSSMHANDLE pSSM) +{ + /* don't need that for now */ +#if 0 + CRStateBits *pBits; + int rc; + + CRASSERT(g_cContexts >= 1); + if (g_cContexts <= 1) + return VINF_SUCCESS; + + pBits = GetCurrentBits(); +#define CRSTATE_BITS_OP(_var, _size) \ + rc = SSMR3PutMem(pSSM, (pBits->_var), _size); \ + AssertRCReturn(rc, rc); +#include "state_bits_globalop.h" +#undef CRSTATE_BITS_OP +#endif + return VINF_SUCCESS; +} + +int32_t crStateLoadGlobals(PSSMHANDLE pSSM, uint32_t u32Version) +{ + CRStateBits *pBits; + int rc; + CRASSERT(g_cContexts >= 1); + if (g_cContexts <= 1) + return VINF_SUCCESS; + + pBits = GetCurrentBits(); + + if (u32Version >= SHCROGL_SSM_VERSION_WITH_STATE_BITS) + { +#define CRSTATE_BITS_OP(_var, _size) \ + rc = SSMR3GetMem(pSSM, (pBits->_var), _size); \ + AssertRCReturn(rc, rc); + + if (u32Version < SHCROGL_SSM_VERSION_WITH_FIXED_STENCIL) + { +#define CRSTATE_BITS_OP_VERSION (SHCROGL_SSM_VERSION_WITH_FIXED_STENCIL - 1) +#define CRSTATE_BITS_OP_STENCIL_FUNC_V_33(_i, _var) do {} while (0) +#define CRSTATE_BITS_OP_STENCIL_OP_V_33(_i, _var) do {} while (0) +#include "state_bits_globalop.h" +#undef CRSTATE_BITS_OP_VERSION +#undef CRSTATE_BITS_OP_STENCIL_FUNC_V_33 +#undef CRSTATE_BITS_OP_STENCIL_OP_V_33 + } + else if (u32Version < SHCROGL_SSM_VERSION_WITH_SPRITE_COORD_ORIGIN) + { +#define CRSTATE_BITS_OP_VERSION (SHCROGL_SSM_VERSION_WITH_SPRITE_COORD_ORIGIN - 1) +#include "state_bits_globalop.h" +#undef CRSTATE_BITS_OP_VERSION + } + else + { + /* we do not put dirty bits to state anymore, + * nop */ +//#include "state_bits_globalop.h" + } +#undef CRSTATE_BITS_OP + /* always dirty all bits */ + /* return VINF_SUCCESS; */ + } + +#define CRSTATE_BITS_OP(_var, _size) FILLDIRTY(pBits->_var); +#include "state_bits_globalop.h" +#undef CRSTATE_BITS_OP + return VINF_SUCCESS; +} + + #define SLC_COPYPTR(ptr) pTmpContext->ptr = pContext->ptr #define SLC_ASSSERT_NULL_PTR(ptr) CRASSERT(!pContext->ptr) @@ -1707,12 +1867,7 @@ int32_t crStateLoadContext(CRContext *pContext, CRHashTable * pCtxTable, PFNCRST uint32_t uiNumElems, ui, k; unsigned long key; GLboolean bLoadShared = GL_TRUE; - union { - CRbitvalue bitid[CR_MAX_BITARRAY]; - struct { - VBOXTLSREFDATA - } tlsRef; - } bitid; + GLenum err; CRASSERT(pContext && pSSM); @@ -1723,70 +1878,130 @@ int32_t crStateLoadContext(CRContext *pContext, CRHashTable * pCtxTable, PFNCRST CRASSERT(VBoxTlsRefIsFunctional(pContext)); - /* do not increment the saved state version due to VBOXTLSREFDATA addition to CRContext */ - rc = SSMR3GetMem(pSSM, pTmpContext, VBOXTLSREFDATA_OFFSET(CRContext)); - AssertRCReturn(rc, rc); - - /* VBox 4.1.8 had a bug that VBOXTLSREFDATA was also stored in the snapshot, - * thus the saved state data format was changed w/o changing the saved state version. - * here we determine whether the saved state contains VBOXTLSREFDATA, and if so, treat it accordingly */ - rc = SSMR3GetMem(pSSM, &bitid, sizeof (bitid)); - AssertRCReturn(rc, rc); - - /* the bitid array has one bit set only. this is why if bitid.tlsRef has both cTlsRefs - * and enmTlsRefState non-zero - this is definitely NOT a bit id and is a VBOXTLSREFDATA */ - if (bitid.tlsRef.enmTlsRefState == VBOXTLSREFDATA_STATE_INITIALIZED - && bitid.tlsRef.cTlsRefs) + if (u32Version <= SHCROGL_SSM_VERSION_WITH_INVALID_ERROR_STATE) { - /* VBOXTLSREFDATA is stored, skip it */ - crMemcpy(&pTmpContext->bitid, ((uint8_t*)&bitid) + VBOXTLSREFDATA_SIZE(), sizeof (bitid) - VBOXTLSREFDATA_SIZE()); - rc = SSMR3GetMem(pSSM, ((uint8_t*)&pTmpContext->bitid) + sizeof (pTmpContext->bitid) - VBOXTLSREFDATA_SIZE(), sizeof (pTmpContext->neg_bitid) + VBOXTLSREFDATA_SIZE()); + union { + CRbitvalue bitid[CR_MAX_BITARRAY]; + struct { + VBOXTLSREFDATA + } tlsRef; + } bitid; + + /* do not increment the saved state version due to VBOXTLSREFDATA addition to CRContext */ + rc = SSMR3GetMem(pSSM, pTmpContext, VBOXTLSREFDATA_OFFSET(CRContext)); AssertRCReturn(rc, rc); - ui = VBOXTLSREFDATA_OFFSET(CRContext) + VBOXTLSREFDATA_SIZE() + sizeof (pTmpContext->bitid) + sizeof (pTmpContext->neg_bitid); - ui = RT_OFFSETOF(CRContext, shared) - ui; - } - else - { - /* VBOXTLSREFDATA is NOT stored */ - crMemcpy(&pTmpContext->bitid, &bitid, sizeof (bitid)); - rc = SSMR3GetMem(pSSM, &pTmpContext->neg_bitid, sizeof (pTmpContext->neg_bitid)); + /* VBox 4.1.8 had a bug that VBOXTLSREFDATA was also stored in the snapshot, + * thus the saved state data format was changed w/o changing the saved state version. + * here we determine whether the saved state contains VBOXTLSREFDATA, and if so, treat it accordingly */ + rc = SSMR3GetMem(pSSM, &bitid, sizeof (bitid)); AssertRCReturn(rc, rc); - /* the pre-VBOXTLSREFDATA CRContext structure might have additional allignment bits before the CRContext::shared */ - ui = VBOXTLSREFDATA_OFFSET(CRContext) + sizeof (pTmpContext->bitid) + sizeof (pTmpContext->neg_bitid); + /* the bitid array has one bit set only. this is why if bitid.tlsRef has both cTlsRefs + * and enmTlsRefState non-zero - this is definitely NOT a bit id and is a VBOXTLSREFDATA */ + if (bitid.tlsRef.enmTlsRefState == VBOXTLSREFDATA_STATE_INITIALIZED + && bitid.tlsRef.cTlsRefs) + { + /* VBOXTLSREFDATA is stored, skip it */ + crMemcpy(&pTmpContext->bitid, ((uint8_t*)&bitid) + VBOXTLSREFDATA_SIZE(), sizeof (bitid) - VBOXTLSREFDATA_SIZE()); + rc = SSMR3GetMem(pSSM, ((uint8_t*)&pTmpContext->bitid) + sizeof (pTmpContext->bitid) - VBOXTLSREFDATA_SIZE(), sizeof (pTmpContext->neg_bitid) + VBOXTLSREFDATA_SIZE()); + AssertRCReturn(rc, rc); - ui &= (sizeof (void*) - 1); - } + ui = VBOXTLSREFDATA_OFFSET(CRContext) + VBOXTLSREFDATA_SIZE() + sizeof (pTmpContext->bitid) + sizeof (pTmpContext->neg_bitid); + ui = RT_OFFSETOF(CRContext, shared) - ui; + } + else + { + /* VBOXTLSREFDATA is NOT stored */ + crMemcpy(&pTmpContext->bitid, &bitid, sizeof (bitid)); + rc = SSMR3GetMem(pSSM, &pTmpContext->neg_bitid, sizeof (pTmpContext->neg_bitid)); + AssertRCReturn(rc, rc); - if (ui) - { - void* pTmp = NULL; - rc = SSMR3GetMem(pSSM, &pTmp, ui); - AssertRCReturn(rc, rc); - } + /* the pre-VBOXTLSREFDATA CRContext structure might have additional allignment bits before the CRContext::shared */ + ui = VBOXTLSREFDATA_OFFSET(CRContext) + sizeof (pTmpContext->bitid) + sizeof (pTmpContext->neg_bitid); - /* we will later do crMemcpy from entire pTmpContext to pContext, - * for simplicity store the VBOXTLSREFDATA from the pContext to pTmpContext */ - VBOXTLSREFDATA_COPY(pTmpContext, pContext); + ui &= (sizeof (void*) - 1); + } - if (u32Version == SHCROGL_SSM_VERSION_BEFORE_CTXUSAGE_BITS) + if (ui) + { + void* pTmp = NULL; + rc = SSMR3GetMem(pSSM, &pTmp, ui); + AssertRCReturn(rc, rc); + } + + if (u32Version == SHCROGL_SSM_VERSION_BEFORE_CTXUSAGE_BITS) + { + SHCROGL_GET_STRUCT_PART(pTmpContext, CRContext, shared, attrib); + rc = crStateLoadAttribState_v_BEFORE_CTXUSAGE_BITS(&pTmpContext->attrib, pSSM); + AssertRCReturn(rc, rc); + SHCROGL_CUT_FIELD_ALIGNMENT(CRContext, attrib, buffer); + SHCROGL_GET_STRUCT_PART(pTmpContext, CRContext, buffer, point); + rc = crStateLoadStencilPoint_v_37(&pTmpContext->point, pSSM); + AssertRCReturn(rc, rc); + SHCROGL_GET_STRUCT_PART(pTmpContext, CRContext, polygon, stencil); + rc = crStateLoadStencilState_v_33(&pTmpContext->stencil, pSSM); + AssertRCReturn(rc, rc); + SHCROGL_CUT_FOR_OLD_TYPE_TO_ENSURE_ALIGNMENT(CRContext, stencil, CRStencilState_v_33, sizeof (void*)); + rc = crStateLoadTextureState_v_BEFORE_CTXUSAGE_BITS(&pTmpContext->texture, pSSM); + AssertRCReturn(rc, rc); + SHCROGL_CUT_FIELD_ALIGNMENT(CRContext, texture, transform); + SHCROGL_GET_STRUCT_TAIL(pTmpContext, CRContext, transform); + } + else + { + SHCROGL_GET_STRUCT_PART(pTmpContext, CRContext, shared, attrib); + rc = crStateLoadAttribState_v_33(&pTmpContext->attrib, pSSM); + AssertRCReturn(rc, rc); + SHCROGL_CUT_FIELD_ALIGNMENT(CRContext, attrib, buffer); + SHCROGL_GET_STRUCT_PART(pTmpContext, CRContext, buffer, point); + rc = crStateLoadStencilPoint_v_37(&pTmpContext->point, pSSM); + AssertRCReturn(rc, rc); + SHCROGL_GET_STRUCT_PART(pTmpContext, CRContext, polygon, stencil); + rc = crStateLoadStencilState_v_33(&pTmpContext->stencil, pSSM); + AssertRCReturn(rc, rc); + SHCROGL_CUT_FOR_OLD_TYPE_TO_ENSURE_ALIGNMENT(CRContext, stencil, CRStencilState_v_33, sizeof (void*)); + SHCROGL_GET_STRUCT_TAIL(pTmpContext, CRContext, texture); + } + + pTmpContext->error = GL_NO_ERROR; /* <- the error state contained some random error data here + * treat as no error */ + } + else if (u32Version < SHCROGL_SSM_VERSION_WITH_FIXED_STENCIL) { - SHCROGL_GET_STRUCT_PART(pTmpContext, CRContext, shared, attrib); - rc = crStateLoadAttribState_v_BEFORE_CTXUSAGE_BITS(&pTmpContext->attrib, pSSM); + SHCROGL_GET_STRUCT_HEAD(pTmpContext, CRContext, attrib); + rc = crStateLoadAttribState_v_33(&pTmpContext->attrib, pSSM); AssertRCReturn(rc, rc); SHCROGL_CUT_FIELD_ALIGNMENT(CRContext, attrib, buffer); - SHCROGL_GET_STRUCT_PART(pTmpContext, CRContext, buffer, texture); - rc = crStateLoadTextureState_v_BEFORE_CTXUSAGE_BITS(&pTmpContext->texture, pSSM); + SHCROGL_GET_STRUCT_PART(pTmpContext, CRContext, buffer, point); + rc = crStateLoadStencilPoint_v_37(&pTmpContext->point, pSSM); AssertRCReturn(rc, rc); - SHCROGL_CUT_FIELD_ALIGNMENT(CRContext, texture, transform); - SHCROGL_GET_STRUCT_TAIL(pTmpContext, CRContext, transform); + SHCROGL_GET_STRUCT_PART(pTmpContext, CRContext, polygon, stencil); + rc = crStateLoadStencilState_v_33(&pTmpContext->stencil, pSSM); + AssertRCReturn(rc, rc); + SHCROGL_CUT_FOR_OLD_TYPE_TO_ENSURE_ALIGNMENT(CRContext, stencil, CRStencilState_v_33, sizeof (void*)); + SHCROGL_GET_STRUCT_TAIL(pTmpContext, CRContext, texture); + } + else if (u32Version < SHCROGL_SSM_VERSION_WITH_SPRITE_COORD_ORIGIN) + { + SHCROGL_GET_STRUCT_HEAD(pTmpContext, CRContext, point); + crStateLoadStencilPoint_v_37(&pTmpContext->point, pSSM); + SHCROGL_GET_STRUCT_TAIL(pTmpContext, CRContext, polygon); } else { - SHCROGL_GET_STRUCT_TAIL(pTmpContext, CRContext, shared); + rc = SSMR3GetMem(pSSM, pTmpContext, sizeof (*pTmpContext)); + AssertRCReturn(rc, rc); } + /* preserve the error to restore it at the end of context creation, + * it should not normally change, but just in case it it changed */ + err = pTmpContext->error; + + /* we will later do crMemcpy from entire pTmpContext to pContext, + * for simplicity store the VBOXTLSREFDATA from the pContext to pTmpContext */ + VBOXTLSREFDATA_COPY(pTmpContext, pContext); + /* Deal with shared state */ { crFindSharedCtxParms_t parms; @@ -2018,6 +2233,13 @@ int32_t crStateLoadContext(CRContext *pContext, CRHashTable * pCtxTable, PFNCRST { /* Load shared textures */ CRASSERT(pContext->shared && pContext->shared->textureTable); + + if (u32Version >= SHCROGL_SSM_VERSION_WITH_ALLOCATED_KEYS) + { + rc = crStateLoadKeys(pContext->shared->buffersTable, pSSM, u32Version); + AssertRCReturn(rc, rc); + } + rc = SSMR3GetU32(pSSM, &uiNumElems); AssertRCReturn(rc, rc); for (ui=0; ui<uiNumElems; ++ui) @@ -2120,6 +2342,15 @@ int32_t crStateLoadContext(CRContext *pContext, CRHashTable * pCtxTable, PFNCRST /* Load buffer objects */ #ifdef CR_ARB_vertex_buffer_object + if (bLoadShared) + { + if (u32Version >= SHCROGL_SSM_VERSION_WITH_ALLOCATED_KEYS) + { + rc = crStateLoadKeys(pContext->shared->textureTable, pSSM, u32Version); + AssertRCReturn(rc, rc); + } + } + rc = SSMR3GetU32(pSSM, &uiNumElems); AssertRCReturn(rc, rc); for (ui=0; ui<=uiNumElems; ++ui) /*ui<=uiNumElems to load nullBuffer in same loop*/ @@ -2242,6 +2473,12 @@ int32_t crStateLoadContext(CRContext *pContext, CRHashTable * pCtxTable, PFNCRST /* Load FBOs */ if (bLoadShared) { + if (u32Version >= SHCROGL_SSM_VERSION_WITH_ALLOCATED_KEYS) + { + rc = crStateLoadKeys(pContext->shared->fbTable, pSSM, u32Version); + AssertRCReturn(rc, rc); + } + rc = SSMR3GetU32(pSSM, &uiNumElems); AssertRCReturn(rc, rc); for (ui=0; ui<uiNumElems; ++ui) @@ -2256,9 +2493,17 @@ int32_t crStateLoadContext(CRContext *pContext, CRHashTable * pCtxTable, PFNCRST rc = crStateLoadFramebufferObject(pFBO, pSSM, u32Version); AssertRCReturn(rc, rc); + Assert(key == pFBO->id); + crHashtableAdd(pContext->shared->fbTable, key, pFBO); } + if (u32Version >= SHCROGL_SSM_VERSION_WITH_ALLOCATED_KEYS) + { + rc = crStateLoadKeys(pContext->shared->rbTable, pSSM, u32Version); + AssertRCReturn(rc, rc); + } + rc = SSMR3GetU32(pSSM, &uiNumElems); AssertRCReturn(rc, rc); for (ui=0; ui<uiNumElems; ++ui) @@ -2304,7 +2549,10 @@ int32_t crStateLoadContext(CRContext *pContext, CRHashTable * pCtxTable, PFNCRST for (ui=0; ui<uiNumElems; ++ui) { CRGLSLShader *pShader = crStateLoadGLSLShader(pSSM); + GLboolean fNewKeyCheck; if (!pShader) return VERR_SSM_UNEXPECTED_DATA; + fNewKeyCheck = crHashtableAllocRegisterKey(pContext->glsl.programs, pShader->id); + CRASSERT(fNewKeyCheck); crHashtableAdd(pContext->glsl.shaders, pShader->id, pShader); } @@ -2416,310 +2664,11 @@ int32_t crStateLoadContext(CRContext *pContext, CRHashTable * pCtxTable, PFNCRST pContext->glsl.bResyncNeeded = GL_TRUE; #endif - - /*Restore front/back buffer images*/ - if (pContext->buffer.storedWidth && pContext->buffer.storedHeight) - { - CRBufferState *pBuf = &pContext->buffer; - GLint cbData; - void *pData; - - cbData = crPixelSize(GL_RGBA, GL_UNSIGNED_BYTE) * pBuf->storedWidth * pBuf->storedHeight; - - pData = crAlloc(cbData); - if (!pData) - { - pBuf->pFrontImg = NULL; - pBuf->pBackImg = NULL; - return VERR_NO_MEMORY; - } - - rc = SSMR3GetMem(pSSM, pData, cbData); - AssertRCReturn(rc, rc); - - pBuf->pFrontImg = pData; - - pData = crAlloc(cbData); - if (!pData) - { - pBuf->pBackImg = NULL; - return VERR_NO_MEMORY; - } - - rc = SSMR3GetMem(pSSM, pData, cbData); - AssertRCReturn(rc, rc); - - pBuf->pBackImg = pData; - } - - - /*Mark all as dirty to make sure we'd restore correct context state*/ + if (pContext->error != err) { - CRStateBits *pBits = GetCurrentBits(); - - FILLDIRTY(pBits->attrib.dirty); - - FILLDIRTY(pBits->buffer.dirty); - FILLDIRTY(pBits->buffer.enable); - FILLDIRTY(pBits->buffer.alphaFunc); - FILLDIRTY(pBits->buffer.depthFunc); - FILLDIRTY(pBits->buffer.blendFunc); - FILLDIRTY(pBits->buffer.logicOp); - FILLDIRTY(pBits->buffer.indexLogicOp); - FILLDIRTY(pBits->buffer.drawBuffer); - FILLDIRTY(pBits->buffer.readBuffer); - FILLDIRTY(pBits->buffer.indexMask); - FILLDIRTY(pBits->buffer.colorWriteMask); - FILLDIRTY(pBits->buffer.clearColor); - FILLDIRTY(pBits->buffer.clearIndex); - FILLDIRTY(pBits->buffer.clearDepth); - FILLDIRTY(pBits->buffer.clearAccum); - FILLDIRTY(pBits->buffer.depthMask); -#ifdef CR_EXT_blend_color - FILLDIRTY(pBits->buffer.blendColor); -#endif -#if defined(CR_EXT_blend_minmax) || defined(CR_EXT_blend_subtract) || defined(CR_EXT_blend_logic_op) - FILLDIRTY(pBits->buffer.blendEquation); -#endif -#if defined(CR_EXT_blend_func_separate) - FILLDIRTY(pBits->buffer.blendFuncSeparate); -#endif - -#ifdef CR_ARB_vertex_buffer_object - FILLDIRTY(pBits->bufferobject.dirty); - FILLDIRTY(pBits->bufferobject.arrayBinding); - FILLDIRTY(pBits->bufferobject.elementsBinding); -# ifdef CR_ARB_pixel_buffer_object - FILLDIRTY(pBits->bufferobject.packBinding); - FILLDIRTY(pBits->bufferobject.unpackBinding); -# endif -#endif - - FILLDIRTY(pBits->client.dirty); - FILLDIRTY(pBits->client.pack); - FILLDIRTY(pBits->client.unpack); - FILLDIRTY(pBits->client.enableClientState); - FILLDIRTY(pBits->client.clientPointer); - FILLDIRTY(pBits->client.v); - FILLDIRTY(pBits->client.n); - FILLDIRTY(pBits->client.c); - FILLDIRTY(pBits->client.i); - FILLDIRTY(pBits->client.e); - FILLDIRTY(pBits->client.s); - FILLDIRTY(pBits->client.f); - for (i=0; i<CR_MAX_TEXTURE_UNITS; i++) - { - FILLDIRTY(pBits->client.t[i]); - } -#ifdef CR_NV_vertex_program - for (i=0; i<CR_MAX_VERTEX_ATTRIBS; i++) - { - FILLDIRTY(pBits->client.a[i]); - } -#endif - - FILLDIRTY(pBits->current.dirty); - for (i=0; i<CR_MAX_VERTEX_ATTRIBS; i++) - { - FILLDIRTY(pBits->current.vertexAttrib[i]); - } - FILLDIRTY(pBits->current.edgeFlag); - FILLDIRTY(pBits->current.colorIndex); - FILLDIRTY(pBits->current.rasterPos); - - - FILLDIRTY(pBits->eval.dirty); - for (i=0; i<GLEVAL_TOT; i++) - { - FILLDIRTY(pBits->eval.eval1D[i]); - FILLDIRTY(pBits->eval.eval2D[i]); - FILLDIRTY(pBits->eval.enable1D[i]); - FILLDIRTY(pBits->eval.enable2D[i]); - } - FILLDIRTY(pBits->eval.enable); - FILLDIRTY(pBits->eval.grid1D); - FILLDIRTY(pBits->eval.grid2D); -#ifdef CR_NV_vertex_program - /*@todo Those seems to be unused? - FILLDIRTY(pBits->eval.enableAttrib1D); - FILLDIRTY(pBits->eval.enableAttrib2D); - */ -#endif - - FILLDIRTY(pBits->feedback.dirty); - FILLDIRTY(pBits->selection.dirty); - - FILLDIRTY(pBits->fog.dirty); - FILLDIRTY(pBits->fog.color); - FILLDIRTY(pBits->fog.index); - FILLDIRTY(pBits->fog.density); - FILLDIRTY(pBits->fog.start); - FILLDIRTY(pBits->fog.end); - FILLDIRTY(pBits->fog.mode); - FILLDIRTY(pBits->fog.enable); -#ifdef CR_NV_fog_distance - FILLDIRTY(pBits->fog.fogDistanceMode); -#endif -#ifdef CR_EXT_fog_coord - FILLDIRTY(pBits->fog.fogCoordinateSource); -#endif - - FILLDIRTY(pBits->hint.dirty); - FILLDIRTY(pBits->hint.perspectiveCorrection); - FILLDIRTY(pBits->hint.pointSmooth); - FILLDIRTY(pBits->hint.lineSmooth); - FILLDIRTY(pBits->hint.polygonSmooth); - FILLDIRTY(pBits->hint.fog); -#ifdef CR_EXT_clip_volume_hint - FILLDIRTY(pBits->hint.clipVolumeClipping); - -#endif -#ifdef CR_ARB_texture_compression - FILLDIRTY(pBits->hint.textureCompression); -#endif -#ifdef CR_SGIS_generate_mipmap - FILLDIRTY(pBits->hint.generateMipmap); -#endif - - FILLDIRTY(pBits->lighting.dirty); - FILLDIRTY(pBits->lighting.shadeModel); - FILLDIRTY(pBits->lighting.colorMaterial); - FILLDIRTY(pBits->lighting.lightModel); - FILLDIRTY(pBits->lighting.material); - FILLDIRTY(pBits->lighting.enable); - for (i=0; i<CR_MAX_LIGHTS; ++i) - { - FILLDIRTY(pBits->lighting.light[i].dirty); - FILLDIRTY(pBits->lighting.light[i].enable); - FILLDIRTY(pBits->lighting.light[i].ambient); - FILLDIRTY(pBits->lighting.light[i].diffuse); - FILLDIRTY(pBits->lighting.light[i].specular); - FILLDIRTY(pBits->lighting.light[i].position); - FILLDIRTY(pBits->lighting.light[i].attenuation); - FILLDIRTY(pBits->lighting.light[i].spot); - } - - FILLDIRTY(pBits->line.dirty); - FILLDIRTY(pBits->line.enable); - FILLDIRTY(pBits->line.width); - FILLDIRTY(pBits->line.stipple); - - FILLDIRTY(pBits->lists.dirty); - FILLDIRTY(pBits->lists.base); - - FILLDIRTY(pBits->multisample.dirty); - FILLDIRTY(pBits->multisample.enable); - FILLDIRTY(pBits->multisample.sampleAlphaToCoverage); - FILLDIRTY(pBits->multisample.sampleAlphaToOne); - FILLDIRTY(pBits->multisample.sampleCoverage); - FILLDIRTY(pBits->multisample.sampleCoverageValue); - -#if CR_ARB_occlusion_query - FILLDIRTY(pBits->occlusion.dirty); -#endif - - FILLDIRTY(pBits->pixel.dirty); - FILLDIRTY(pBits->pixel.transfer); - FILLDIRTY(pBits->pixel.zoom); - FILLDIRTY(pBits->pixel.maps); - - FILLDIRTY(pBits->point.dirty); - FILLDIRTY(pBits->point.enableSmooth); - FILLDIRTY(pBits->point.size); -#ifdef CR_ARB_point_parameters - FILLDIRTY(pBits->point.minSize); - FILLDIRTY(pBits->point.maxSize); - FILLDIRTY(pBits->point.fadeThresholdSize); - FILLDIRTY(pBits->point.distanceAttenuation); -#endif -#ifdef CR_ARB_point_sprite - FILLDIRTY(pBits->point.enableSprite); - for (i=0; i<CR_MAX_TEXTURE_UNITS; ++i) - { - FILLDIRTY(pBits->point.coordReplacement[i]); - } -#endif - - FILLDIRTY(pBits->polygon.dirty); - FILLDIRTY(pBits->polygon.enable); - FILLDIRTY(pBits->polygon.offset); - FILLDIRTY(pBits->polygon.mode); - FILLDIRTY(pBits->polygon.stipple); - - FILLDIRTY(pBits->program.dirty); - FILLDIRTY(pBits->program.vpEnable); - FILLDIRTY(pBits->program.fpEnable); - FILLDIRTY(pBits->program.vpBinding); - FILLDIRTY(pBits->program.fpBinding); - for (i=0; i<CR_MAX_VERTEX_ATTRIBS; ++i) - { - FILLDIRTY(pBits->program.vertexAttribArrayEnable[i]); - FILLDIRTY(pBits->program.map1AttribArrayEnable[i]); - FILLDIRTY(pBits->program.map2AttribArrayEnable[i]); - } - for (i=0; i<CR_MAX_VERTEX_PROGRAM_ENV_PARAMS; ++i) - { - FILLDIRTY(pBits->program.vertexEnvParameter[i]); - } - for (i=0; i<CR_MAX_FRAGMENT_PROGRAM_ENV_PARAMS; ++i) - { - FILLDIRTY(pBits->program.fragmentEnvParameter[i]); - } - FILLDIRTY(pBits->program.vertexEnvParameters); - FILLDIRTY(pBits->program.fragmentEnvParameters); - for (i=0; i<CR_MAX_VERTEX_PROGRAM_ENV_PARAMS/4; ++i) - { - FILLDIRTY(pBits->program.trackMatrix[i]); - } - - FILLDIRTY(pBits->regcombiner.dirty); - FILLDIRTY(pBits->regcombiner.enable); - FILLDIRTY(pBits->regcombiner.regCombinerVars); - FILLDIRTY(pBits->regcombiner.regCombinerColor0); - FILLDIRTY(pBits->regcombiner.regCombinerColor1); - for (i=0; i<CR_MAX_GENERAL_COMBINERS; ++i) - { - FILLDIRTY(pBits->regcombiner.regCombinerStageColor0[i]); - FILLDIRTY(pBits->regcombiner.regCombinerStageColor1[i]); - FILLDIRTY(pBits->regcombiner.regCombinerInput[i]); - FILLDIRTY(pBits->regcombiner.regCombinerOutput[i]); - } - FILLDIRTY(pBits->regcombiner.regCombinerFinalInput); - - FILLDIRTY(pBits->stencil.dirty); - FILLDIRTY(pBits->stencil.enable); - FILLDIRTY(pBits->stencil.func); - FILLDIRTY(pBits->stencil.op); - FILLDIRTY(pBits->stencil.clearValue); - FILLDIRTY(pBits->stencil.writeMask); - - FILLDIRTY(pBits->texture.dirty); - for (i=0; i<CR_MAX_TEXTURE_UNITS; ++i) - { - FILLDIRTY(pBits->texture.enable[i]); - FILLDIRTY(pBits->texture.current[i]); - FILLDIRTY(pBits->texture.objGen[i]); - FILLDIRTY(pBits->texture.eyeGen[i]); - FILLDIRTY(pBits->texture.genMode[i]); - FILLDIRTY(pBits->texture.envBit[i]); - } - - FILLDIRTY(pBits->transform.dirty); - FILLDIRTY(pBits->transform.matrixMode); - FILLDIRTY(pBits->transform.modelviewMatrix); - FILLDIRTY(pBits->transform.projectionMatrix); - FILLDIRTY(pBits->transform.colorMatrix); - FILLDIRTY(pBits->transform.textureMatrix); - FILLDIRTY(pBits->transform.programMatrix); - FILLDIRTY(pBits->transform.clipPlane); - FILLDIRTY(pBits->transform.enable); - FILLDIRTY(pBits->transform.base); - - FILLDIRTY(pBits->viewport.dirty); - FILLDIRTY(pBits->viewport.v_dims); - FILLDIRTY(pBits->viewport.s_dims); - FILLDIRTY(pBits->viewport.enable); - FILLDIRTY(pBits->viewport.depth); + crWarning("context error state changed on context restore, was 0x%x, but became 0x%x, resetting to its original value", + err, pContext->error); + pContext->error = err; } return VINF_SUCCESS; diff --git a/src/VBox/GuestHost/OpenGL/state_tracker/state_special b/src/VBox/GuestHost/OpenGL/state_tracker/state_special index e0bcc305..dfdca2f1 100644 --- a/src/VBox/GuestHost/OpenGL/state_tracker/state_special +++ b/src/VBox/GuestHost/OpenGL/state_tracker/state_special @@ -157,6 +157,9 @@ GetIntegerv GetError StencilFunc StencilOp +StencilFuncSeparate +StencilOpSeparate +ActiveStencilFaceEXT ClearStencil StencilMask Viewport @@ -375,3 +378,7 @@ ValidateProgram BindAttribLocation GetUniformLocation CopyTexImage2D +GenFramebuffersEXT +GenRenderbuffersEXT +IsRenderbufferEXT +IsFramebufferEXT diff --git a/src/VBox/GuestHost/OpenGL/state_tracker/state_stencil.c b/src/VBox/GuestHost/OpenGL/state_tracker/state_stencil.c index e284b31a..d543e301 100644 --- a/src/VBox/GuestHost/OpenGL/state_tracker/state_stencil.c +++ b/src/VBox/GuestHost/OpenGL/state_tracker/state_stencil.c @@ -9,24 +9,74 @@ #include "state/cr_statetypes.h" #include "state_internals.h" + +static GLint crStateStencilBufferGetIdxAndCount(CRStencilState *s, GLenum face, GLint *pIdx, GLint *pBitsIdx) +{ + switch (face) + { + case GL_FRONT_AND_BACK: + *pIdx = 0; + *pBitsIdx = CRSTATE_STENCIL_BUFFER_REF_ID_FRONT_AND_BACK; + return 2; + case GL_FRONT: + *pIdx = CRSTATE_STENCIL_BUFFER_ID_FRONT; + *pBitsIdx = CRSTATE_STENCIL_BUFFER_REF_ID_FRONT; + return 1; + case GL_BACK: + *pIdx = CRSTATE_STENCIL_BUFFER_ID_BACK; + *pBitsIdx = CRSTATE_STENCIL_BUFFER_REF_ID_BACK; + return 1; + case 0: + if (!s->stencilTwoSideEXT || s->activeStencilFace == GL_FRONT) + { + /* both front and back */ + *pIdx = 0; + *pBitsIdx = CRSTATE_STENCIL_BUFFER_REF_ID_FRONT_AND_BACK; + return 2; + } + *pIdx = CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK; + *pBitsIdx = CRSTATE_STENCIL_BUFFER_REF_ID_TWO_SIDE_BACK; + return 1; + default: + crStateError(__LINE__,__FILE__,GL_INVALID_ENUM, "crStateStencilBufferGetIdxAndCount"); + return 0; + } + crError("should never be here!"); + return 0; +} + +void crStateStencilBufferInit(CRStencilBufferState *s) +{ + s->func = GL_ALWAYS; + s->mask = 0xFFFFFFFF; + s->ref = 0; + + s->fail = GL_KEEP; + s->passDepthFail = GL_KEEP; + s->passDepthPass = GL_KEEP; +} + +static void crStateStencilBufferRefBitsInit(CRContext *ctx, CRStencilBufferRefBits *sb) +{ + RESET(sb->func, ctx->bitid); + RESET(sb->op, ctx->bitid); +} + void crStateStencilInit(CRContext *ctx) { CRStencilState *s = &ctx->stencil; CRStateBits *stateb = GetCurrentBits(); CRStencilBits *sb = &(stateb->stencil); + int i; s->stencilTest = GL_FALSE; RESET(sb->enable, ctx->bitid); - s->func = GL_ALWAYS; - s->mask = 0xFFFFFFFF; - s->ref = 0; - RESET(sb->func, ctx->bitid); + s->stencilTwoSideEXT = GL_FALSE; + RESET(sb->enableTwoSideEXT, ctx->bitid); - s->fail = GL_KEEP; - s->passDepthFail = GL_KEEP; - s->passDepthPass = GL_KEEP; - RESET(sb->op, ctx->bitid); + s->activeStencilFace = GL_FRONT; + RESET(sb->activeStencilFace, ctx->bitid); s->clearValue = 0; RESET(sb->clearValue, ctx->bitid); @@ -35,53 +85,101 @@ void crStateStencilInit(CRContext *ctx) RESET(sb->writeMask, ctx->bitid); RESET(sb->dirty, ctx->bitid); + + for (i = 0; i < CRSTATE_STENCIL_BUFFER_COUNT; ++i) + { + crStateStencilBufferInit(&s->buffers[i]); + } + + for (i = 0; i < CRSTATE_STENCIL_BUFFER_REF_COUNT; ++i) + { + crStateStencilBufferRefBitsInit(ctx, &sb->bufferRefs[i]); + } } -void STATE_APIENTRY crStateStencilFunc(GLenum func, GLint ref, GLuint mask) +static void crStateStencilBufferFunc(CRContext *g, CRStencilBufferState *s, GLenum func, GLint ref, GLuint mask) { - CRContext *g = GetCurrentContext(); - CRStencilState *s = &(g->stencil); - CRStateBits *stateb = GetCurrentBits(); - CRStencilBits *sb = &(stateb->stencil); + s->func = func; + s->ref = ref; + s->mask = mask; +} +static void crStateStencilFuncPerform(GLenum face, GLenum func, GLint ref, GLuint mask) +{ + CRContext *g = GetCurrentContext(); + CRStencilState *s = &(g->stencil); + CRStateBits *stateb = GetCurrentBits(); + CRStencilBits *sb = &(stateb->stencil); + GLint idx, bitsIdx, count, i; - if (g->current.inBeginEnd) - { - crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION, - "glStencilFunc called in begin/end"); - return; - } - FLUSH(); + if (g->current.inBeginEnd) + { + crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION, + "glStencilFunc called in begin/end"); + return; + } - if (func != GL_NEVER && - func != GL_LESS && - func != GL_LEQUAL && - func != GL_GREATER && - func != GL_GEQUAL && - func != GL_EQUAL && - func != GL_NOTEQUAL && - func != GL_ALWAYS) - { - crStateError(__LINE__, __FILE__, GL_INVALID_ENUM, - "glStencilFunc called with bogu func: %d", func); - return; - } + FLUSH(); - s->func = func; - s->ref = ref; - s->mask = mask; + if (func != GL_NEVER && + func != GL_LESS && + func != GL_LEQUAL && + func != GL_GREATER && + func != GL_GEQUAL && + func != GL_EQUAL && + func != GL_NOTEQUAL && + func != GL_ALWAYS) + { + crStateError(__LINE__, __FILE__, GL_INVALID_ENUM, + "glStencilFunc called with bogu func: %d", func); + return; + } - DIRTY(sb->func, g->neg_bitid); - DIRTY(sb->dirty, g->neg_bitid); + count = crStateStencilBufferGetIdxAndCount(s, face, &idx, &bitsIdx); + if (count) + { + for (i = idx; i < idx + count; ++i) + { + crStateStencilBufferFunc(g, &s->buffers[i], func, ref, mask); + } + DIRTY(sb->bufferRefs[bitsIdx].func, g->neg_bitid); + + DIRTY(sb->dirty, g->neg_bitid); + } +} + +void STATE_APIENTRY crStateStencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask) +{ + if (!face) + { + /* crStateStencilFuncPerform accepts 0 value, while glStencilFuncSeparate does not, + * filter it out here */ + crStateError(__LINE__,__FILE__,GL_INVALID_ENUM, "crStateStencilFuncSeparate"); + return; + } + crStateStencilFuncPerform(face, func, ref, mask); } -void STATE_APIENTRY crStateStencilOp (GLenum fail, GLenum zfail, GLenum zpass) +void STATE_APIENTRY crStateStencilFunc(GLenum func, GLint ref, GLuint mask) +{ + crStateStencilFuncPerform(0, func, ref, mask); +} + +static void STATE_APIENTRY crStateStencilBufferOp (CRContext *g, CRStencilBufferState *s, GLenum fail, GLenum zfail, GLenum zpass) +{ + s->fail = fail; + s->passDepthFail = zfail; + s->passDepthPass = zpass; +} + +static void crStateStencilOpPerform (GLenum face, GLenum fail, GLenum zfail, GLenum zpass) { CRContext *g = GetCurrentContext(); CRStencilState *s = &(g->stencil); CRStateBits *stateb = GetCurrentBits(); CRStencilBits *sb = &(stateb->stencil); + GLint idx, bitsIdx, count, i; if (g->current.inBeginEnd) { @@ -146,14 +244,36 @@ void STATE_APIENTRY crStateStencilOp (GLenum fail, GLenum zfail, GLenum zpass) return; } - s->fail = fail; - s->passDepthFail = zfail; - s->passDepthPass = zpass; + count = crStateStencilBufferGetIdxAndCount(s, face, &idx, &bitsIdx); + if (count) + { + for (i = idx; i < idx + count; ++i) + { + crStateStencilBufferOp(g, &s->buffers[i], fail, zfail, zpass); + } - DIRTY(sb->op, g->neg_bitid); - DIRTY(sb->dirty, g->neg_bitid); + DIRTY(sb->bufferRefs[bitsIdx].op, g->neg_bitid); + + DIRTY(sb->dirty, g->neg_bitid); + } } +void STATE_APIENTRY crStateStencilOpSeparate (GLenum face, GLenum fail, GLenum zfail, GLenum zpass) +{ + if (!face) + { + /* crStateStencilOpPerform accepts 0 value, while glStencilOpSeparate does not, + * filter it out here */ + crStateError(__LINE__,__FILE__,GL_INVALID_ENUM, "crStateStencilOpSeparate"); + return; + } + crStateStencilOpPerform (0, fail, zfail, zpass); +} + +void STATE_APIENTRY crStateStencilOp (GLenum fail, GLenum zfail, GLenum zpass) +{ + crStateStencilOpPerform (0, fail, zfail, zpass); +} void STATE_APIENTRY crStateClearStencil (GLint c) { @@ -171,7 +291,6 @@ void STATE_APIENTRY crStateClearStencil (GLint c) FLUSH(); - s->clearValue = c; DIRTY(sb->clearValue, g->neg_bitid); @@ -199,3 +318,1129 @@ void STATE_APIENTRY crStateStencilMask (GLuint mask) DIRTY(sb->writeMask, g->neg_bitid); DIRTY(sb->dirty, g->neg_bitid); } + +void STATE_APIENTRY crStateActiveStencilFaceEXT (GLenum face) +{ + CRContext *g = GetCurrentContext(); + CRStencilState *s = &(g->stencil); + CRStateBits *stateb = GetCurrentBits(); + CRStencilBits *sb = &(stateb->stencil); + + switch (face) + { + case GL_FRONT: + case GL_BACK: + s->activeStencilFace = face; + break; + default: + crStateError(__LINE__,__FILE__,GL_INVALID_ENUM, "crStateActiveStencilFaceEXT"); + return; + } + + DIRTY(sb->activeStencilFace, g->neg_bitid); + DIRTY(sb->dirty, g->neg_bitid); +} + +#ifdef CRSTATE_DEBUG_STENCIL_ERR +#define CRSTATE_CLEARERR() do { \ + while (diff_api.GetError() != GL_NO_ERROR) {} \ + } while (0) + +#define CRSTATE_CHECKGLERR(_op) do {\ + GLenum _glErr; \ + CRSTATE_CLEARERR(); \ + _op; \ + while ((_glErr = diff_api.GetError()) != GL_NO_ERROR) { Assert(0);} \ + }while (0) +#else +#define CRSTATE_CHECKGLERR(_op) do { _op; } while (0) +#endif + +#define CR_STATE_STENCIL_FUNC_MATCH(_s1, _i1, _s2, _i2) (\ + (_s1)->buffers[(_i1)].func == (_s2)->buffers[(_i2)].func && \ + (_s1)->buffers[(_i1)].ref == (_s2)->buffers[(_i2)].ref && \ + (_s1)->buffers[(_i1)].mask == (_s2)->buffers[(_i2)].mask) + +#define CR_STATE_STENCIL_FUNC_COPY(_s1, _i1, _s2, _i2) do { \ + (_s1)->buffers[(_i1)].func = (_s2)->buffers[(_i2)].func; \ + (_s1)->buffers[(_i1)].ref = (_s2)->buffers[(_i2)].ref; \ + (_s1)->buffers[(_i1)].mask = (_s2)->buffers[(_i2)].mask; \ + } while (0) + + +#define CR_STATE_STENCIL_OP_MATCH(_s1, _i1, _s2, _i2) (\ + (_s1)->buffers[(_i1)].fail == (_s2)->buffers[(_i2)].fail && \ + (_s1)->buffers[(_i1)].passDepthFail == (_s2)->buffers[(_i2)].passDepthFail && \ + (_s1)->buffers[(_i1)].passDepthPass == (_s2)->buffers[(_i2)].passDepthPass) + +#define CR_STATE_STENCIL_OP_COPY(_s1, _i1, _s2, _i2) do { \ + (_s1)->buffers[(_i1)].fail = (_s2)->buffers[(_i2)].fail; \ + (_s1)->buffers[(_i1)].passDepthFail = (_s2)->buffers[(_i2)].passDepthFail; \ + (_s1)->buffers[(_i1)].passDepthPass = (_s2)->buffers[(_i2)].passDepthPass; \ + } while (0) + + +void crStateStencilDiff(CRStencilBits *b, CRbitvalue *bitID, + CRContext *fromCtx, CRContext *toCtx) +{ + CRStencilState *from = &(fromCtx->stencil); + CRStencilState *to = &(toCtx->stencil); + unsigned int j, i; + GLenum activeFace; + GLboolean backIsSet = GL_FALSE, frontIsSet = GL_FALSE, frontBackDirty, frontDirty, backDirty; + GLchar frontMatch = -1, backMatch = -1, toFrontBackMatch = -1; + CRbitvalue nbitID[CR_MAX_BITARRAY]; + for (j=0;j<CR_MAX_BITARRAY;j++) + nbitID[j] = ~bitID[j]; + i = 0; /* silence compiler */ + + if (CHECKDIRTY(b->enable, bitID)) + { + glAble able[2]; + able[0] = diff_api.Disable; + able[1] = diff_api.Enable; + if (from->stencilTest != to->stencilTest) + { + able[to->stencilTest](GL_STENCIL_TEST); + from->stencilTest = to->stencilTest; + } + CLEARDIRTY(b->enable, nbitID); + } + + if (CHECKDIRTY(b->enableTwoSideEXT, bitID)) + { + glAble able[2]; + able[0] = diff_api.Disable; + able[1] = diff_api.Enable; + if (from->stencilTwoSideEXT != to->stencilTwoSideEXT) + { + able[to->stencilTwoSideEXT](GL_STENCIL_TEST_TWO_SIDE_EXT); + from->stencilTwoSideEXT = to->stencilTwoSideEXT; + } + CLEARDIRTY(b->enableTwoSideEXT, nbitID); + } + + if (CHECKDIRTY(b->clearValue, bitID)) + { + if (from->clearValue != to->clearValue) + { + diff_api.ClearStencil (to->clearValue); + from->clearValue = to->clearValue; + } + CLEARDIRTY(b->clearValue, nbitID); + } + + activeFace = to->activeStencilFace; + + + /* func */ + frontBackDirty = CHECKDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT_AND_BACK].func, bitID); + frontDirty = CHECKDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT].func, bitID); + backDirty = CHECKDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_BACK].func, bitID); +#define CR_STATE_STENCIL_FUNC_FRONT_MATCH() ( \ + frontMatch >= 0 ? \ + frontMatch \ + : (frontMatch = CR_STATE_STENCIL_FUNC_MATCH(from, CRSTATE_STENCIL_BUFFER_ID_FRONT, to, CRSTATE_STENCIL_BUFFER_ID_FRONT))) + +#define CR_STATE_STENCIL_FUNC_BACK_MATCH() ( \ + backMatch >= 0 ? \ + backMatch \ + : (backMatch = CR_STATE_STENCIL_FUNC_MATCH(from, CRSTATE_STENCIL_BUFFER_ID_BACK, to, CRSTATE_STENCIL_BUFFER_ID_BACK))) + +#define CR_STATE_STENCIL_FUNC_TO_FRONT_BACK_MATCH() ( \ + toFrontBackMatch >= 0 ? \ + toFrontBackMatch \ + : (toFrontBackMatch = CR_STATE_STENCIL_FUNC_MATCH(to, CRSTATE_STENCIL_BUFFER_ID_FRONT, to, CRSTATE_STENCIL_BUFFER_ID_BACK))) + + if (frontBackDirty) + { + if (!CR_STATE_STENCIL_FUNC_FRONT_MATCH() + || !CR_STATE_STENCIL_FUNC_BACK_MATCH()) + { + if (CR_STATE_STENCIL_FUNC_TO_FRONT_BACK_MATCH()) + { + if (activeFace == GL_BACK) + { + diff_api.ActiveStencilFaceEXT(GL_FRONT); + activeFace = GL_FRONT; + } + + diff_api.StencilFunc (to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].func, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].ref, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].mask); + + CR_STATE_STENCIL_FUNC_COPY(from, CRSTATE_STENCIL_BUFFER_ID_FRONT, to, CRSTATE_STENCIL_BUFFER_ID_FRONT); + CR_STATE_STENCIL_FUNC_COPY(from, CRSTATE_STENCIL_BUFFER_ID_BACK, to, CRSTATE_STENCIL_BUFFER_ID_FRONT); + frontIsSet = GL_TRUE; + backIsSet = GL_TRUE; + } + else if (!CR_STATE_STENCIL_FUNC_FRONT_MATCH()) + { + if (activeFace == GL_BACK) + { + diff_api.ActiveStencilFaceEXT(GL_FRONT); + activeFace = GL_FRONT; + } + + diff_api.StencilFuncSeparate (GL_FRONT, to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].func, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].ref, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].mask); + + CR_STATE_STENCIL_FUNC_COPY(from, CRSTATE_STENCIL_BUFFER_ID_FRONT, to, CRSTATE_STENCIL_BUFFER_ID_FRONT); + frontIsSet = GL_TRUE; + } + else if (!CR_STATE_STENCIL_FUNC_BACK_MATCH()) + { + if (activeFace == GL_BACK) + { + diff_api.ActiveStencilFaceEXT(GL_FRONT); + activeFace = GL_FRONT; + } + + diff_api.StencilFuncSeparate (GL_BACK, to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].func, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].ref, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].mask); + + CR_STATE_STENCIL_FUNC_COPY(from, CRSTATE_STENCIL_BUFFER_ID_BACK, to, CRSTATE_STENCIL_BUFFER_ID_BACK); + + backIsSet = GL_TRUE; + } + } + + CLEARDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT_AND_BACK].func, nbitID); + } + + if (frontDirty) + { + if (!CR_STATE_STENCIL_FUNC_FRONT_MATCH()) + { + if (CR_STATE_STENCIL_FUNC_TO_FRONT_BACK_MATCH()) + { + if (!frontIsSet || !backIsSet) + { + if (activeFace == GL_BACK) + { + diff_api.ActiveStencilFaceEXT(GL_FRONT); + activeFace = GL_FRONT; + } + + diff_api.StencilFunc (to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].func, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].ref, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].mask); + + CR_STATE_STENCIL_FUNC_COPY(from, CRSTATE_STENCIL_BUFFER_ID_FRONT, to, CRSTATE_STENCIL_BUFFER_ID_FRONT); + CR_STATE_STENCIL_FUNC_COPY(from, CRSTATE_STENCIL_BUFFER_ID_BACK, to, CRSTATE_STENCIL_BUFFER_ID_FRONT); + + frontIsSet = GL_TRUE; + backIsSet = GL_TRUE; + } + } + else if (!CR_STATE_STENCIL_FUNC_FRONT_MATCH()) + { + if (!frontIsSet) + { + if (activeFace == GL_BACK) + { + diff_api.ActiveStencilFaceEXT(GL_FRONT); + activeFace = GL_FRONT; + } + + diff_api.StencilFuncSeparate (GL_FRONT, to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].func, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].ref, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].mask); + + CR_STATE_STENCIL_FUNC_COPY(from, CRSTATE_STENCIL_BUFFER_ID_FRONT, to, CRSTATE_STENCIL_BUFFER_ID_FRONT); + frontIsSet = GL_TRUE; + } + } + else if (!CR_STATE_STENCIL_FUNC_BACK_MATCH()) + { + if (!backIsSet) + { + if (activeFace == GL_BACK) + { + diff_api.ActiveStencilFaceEXT(GL_FRONT); + activeFace = GL_FRONT; + } + + diff_api.StencilFuncSeparate (GL_BACK, to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].func, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].ref, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].mask); + CR_STATE_STENCIL_FUNC_COPY(from, CRSTATE_STENCIL_BUFFER_ID_BACK, to, CRSTATE_STENCIL_BUFFER_ID_BACK); + backIsSet = GL_TRUE; + } + } + } + CLEARDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT].func, nbitID); + } + + + if (backDirty) + { + if (!CR_STATE_STENCIL_FUNC_FRONT_MATCH()) + { + if (CR_STATE_STENCIL_FUNC_TO_FRONT_BACK_MATCH()) + { + if (!frontIsSet || !backIsSet) + { + if (activeFace == GL_BACK) + { + diff_api.ActiveStencilFaceEXT(GL_FRONT); + activeFace = GL_FRONT; + } + + diff_api.StencilFunc (to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].func, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].ref, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].mask); + + CR_STATE_STENCIL_FUNC_COPY(from, CRSTATE_STENCIL_BUFFER_ID_FRONT, to, CRSTATE_STENCIL_BUFFER_ID_FRONT); + CR_STATE_STENCIL_FUNC_COPY(from, CRSTATE_STENCIL_BUFFER_ID_BACK, to, CRSTATE_STENCIL_BUFFER_ID_FRONT); + + frontIsSet = GL_TRUE; + backIsSet = GL_TRUE; + } + } + else if (!CR_STATE_STENCIL_FUNC_FRONT_MATCH()) + { + if (!frontIsSet) + { + if (activeFace == GL_BACK) + { + diff_api.ActiveStencilFaceEXT(GL_FRONT); + activeFace = GL_FRONT; + } + + diff_api.StencilFuncSeparate (GL_FRONT, to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].func, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].ref, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].mask); + + CR_STATE_STENCIL_FUNC_COPY(from, CRSTATE_STENCIL_BUFFER_ID_FRONT, to, CRSTATE_STENCIL_BUFFER_ID_FRONT); + frontIsSet = GL_TRUE; + } + } + else if (!CR_STATE_STENCIL_FUNC_BACK_MATCH()) + { + if (!backIsSet) + { + if (activeFace == GL_BACK) + { + diff_api.ActiveStencilFaceEXT(GL_FRONT); + activeFace = GL_FRONT; + } + + diff_api.StencilFuncSeparate (GL_BACK, to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].func, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].ref, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].mask); + CR_STATE_STENCIL_FUNC_COPY(from, CRSTATE_STENCIL_BUFFER_ID_BACK, to, CRSTATE_STENCIL_BUFFER_ID_BACK); + backIsSet = GL_TRUE; + } + } + } + CLEARDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_BACK].func, nbitID); + } + + if (CHECKDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_TWO_SIDE_BACK].func, bitID)) + { + if (!CR_STATE_STENCIL_FUNC_MATCH(from, CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK, to, CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK)) + { + if (activeFace == GL_FRONT) + { + diff_api.ActiveStencilFaceEXT(GL_BACK); + activeFace = GL_BACK; + } + + diff_api.StencilFunc (to->buffers[CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].func, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].ref, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].mask); + CR_STATE_STENCIL_FUNC_COPY(from, CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK, to, CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK); + } + CLEARDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_TWO_SIDE_BACK].func, nbitID); + } + +#undef CR_STATE_STENCIL_FUNC_FRONT_MATCH +#undef CR_STATE_STENCIL_FUNC_BACK_MATCH +#undef CR_STATE_STENCIL_FUNC_TO_FRONT_BACK_MATCH + + /* op */ + backIsSet = GL_FALSE, frontIsSet = GL_FALSE; + frontMatch = -1, backMatch = -1, toFrontBackMatch = -1; + frontBackDirty = CHECKDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT_AND_BACK].op, bitID); + frontDirty = CHECKDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT].op, bitID); + backDirty = CHECKDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_BACK].op, bitID); + +#define CR_STATE_STENCIL_OP_FRONT_MATCH() ( \ + frontMatch >= 0 ? \ + frontMatch \ + : (frontMatch = CR_STATE_STENCIL_OP_MATCH(from, CRSTATE_STENCIL_BUFFER_ID_FRONT, to, CRSTATE_STENCIL_BUFFER_ID_FRONT))) + +#define CR_STATE_STENCIL_OP_BACK_MATCH() ( \ + backMatch >= 0 ? \ + backMatch \ + : (backMatch = CR_STATE_STENCIL_OP_MATCH(from, CRSTATE_STENCIL_BUFFER_ID_BACK, to, CRSTATE_STENCIL_BUFFER_ID_BACK))) + +#define CR_STATE_STENCIL_OP_TO_FRONT_BACK_MATCH() ( \ + toFrontBackMatch >= 0 ? \ + toFrontBackMatch \ + : (toFrontBackMatch = CR_STATE_STENCIL_OP_MATCH(to, CRSTATE_STENCIL_BUFFER_ID_FRONT, to, CRSTATE_STENCIL_BUFFER_ID_BACK))) + + if (frontBackDirty) + { + if (!CR_STATE_STENCIL_OP_FRONT_MATCH() + || !CR_STATE_STENCIL_OP_BACK_MATCH()) + { + if (CR_STATE_STENCIL_OP_TO_FRONT_BACK_MATCH()) + { + if (activeFace == GL_BACK) + { + diff_api.ActiveStencilFaceEXT(GL_FRONT); + activeFace = GL_FRONT; + } + + diff_api.StencilOp (to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].fail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthFail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthPass); + + CR_STATE_STENCIL_OP_COPY(from, CRSTATE_STENCIL_BUFFER_ID_FRONT, to, CRSTATE_STENCIL_BUFFER_ID_FRONT); + CR_STATE_STENCIL_OP_COPY(from, CRSTATE_STENCIL_BUFFER_ID_BACK, to, CRSTATE_STENCIL_BUFFER_ID_FRONT); + + frontIsSet = GL_TRUE; + backIsSet = GL_TRUE; + } + else if (!CR_STATE_STENCIL_OP_FRONT_MATCH()) + { + if (activeFace == GL_BACK) + { + diff_api.ActiveStencilFaceEXT(GL_FRONT); + activeFace = GL_FRONT; + } + + diff_api.StencilOpSeparate (GL_FRONT, to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].fail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthFail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthPass); + CR_STATE_STENCIL_OP_COPY(from, CRSTATE_STENCIL_BUFFER_ID_FRONT, to, CRSTATE_STENCIL_BUFFER_ID_FRONT); + frontIsSet = GL_TRUE; + } + else if (!CR_STATE_STENCIL_OP_BACK_MATCH()) + { + if (activeFace == GL_BACK) + { + diff_api.ActiveStencilFaceEXT(GL_FRONT); + activeFace = GL_FRONT; + } + + diff_api.StencilOpSeparate (GL_BACK, to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].fail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].passDepthFail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].passDepthPass); + CR_STATE_STENCIL_OP_COPY(from, CRSTATE_STENCIL_BUFFER_ID_BACK, to, CRSTATE_STENCIL_BUFFER_ID_BACK); + backIsSet = GL_TRUE; + } + } + + CLEARDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT_AND_BACK].op, nbitID); + } + + if (frontDirty) + { + if (!CR_STATE_STENCIL_OP_FRONT_MATCH()) + { + if (CR_STATE_STENCIL_OP_TO_FRONT_BACK_MATCH()) + { + if (!frontIsSet || !backIsSet) + { + if (activeFace == GL_BACK) + { + diff_api.ActiveStencilFaceEXT(GL_FRONT); + activeFace = GL_FRONT; + } + + diff_api.StencilOp (to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].fail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthFail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthPass); + + CR_STATE_STENCIL_OP_COPY(from, CRSTATE_STENCIL_BUFFER_ID_FRONT, to, CRSTATE_STENCIL_BUFFER_ID_FRONT); + CR_STATE_STENCIL_OP_COPY(from, CRSTATE_STENCIL_BUFFER_ID_BACK, to, CRSTATE_STENCIL_BUFFER_ID_FRONT); + + frontIsSet = GL_TRUE; + backIsSet = GL_TRUE; + } + } + else if (!CR_STATE_STENCIL_OP_FRONT_MATCH()) + { + if (!frontIsSet) + { + if (activeFace == GL_BACK) + { + diff_api.ActiveStencilFaceEXT(GL_FRONT); + activeFace = GL_FRONT; + } + + diff_api.StencilOpSeparate (GL_FRONT, to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].fail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthFail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthPass); + + CR_STATE_STENCIL_OP_COPY(from, CRSTATE_STENCIL_BUFFER_ID_FRONT, to, CRSTATE_STENCIL_BUFFER_ID_FRONT); + + frontIsSet = GL_TRUE; + } + } + else if (!CR_STATE_STENCIL_OP_BACK_MATCH()) + { + if (!backIsSet) + { + if (activeFace == GL_BACK) + { + diff_api.ActiveStencilFaceEXT(GL_FRONT); + activeFace = GL_FRONT; + } + + diff_api.StencilOpSeparate (GL_BACK, to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].fail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].passDepthFail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].passDepthPass); + CR_STATE_STENCIL_OP_COPY(from, CRSTATE_STENCIL_BUFFER_ID_BACK, to, CRSTATE_STENCIL_BUFFER_ID_BACK); + backIsSet = GL_TRUE; + } + } + } + CLEARDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT].op, nbitID); + } + + + if (backDirty) + { + if (!CR_STATE_STENCIL_OP_FRONT_MATCH()) + { + if (CR_STATE_STENCIL_OP_TO_FRONT_BACK_MATCH()) + { + if (!frontIsSet || !backIsSet) + { + if (activeFace == GL_BACK) + { + diff_api.ActiveStencilFaceEXT(GL_FRONT); + activeFace = GL_FRONT; + } + + diff_api.StencilOp (to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].fail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthFail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthPass); + + CR_STATE_STENCIL_OP_COPY(from, CRSTATE_STENCIL_BUFFER_ID_FRONT, to, CRSTATE_STENCIL_BUFFER_ID_FRONT); + CR_STATE_STENCIL_OP_COPY(from, CRSTATE_STENCIL_BUFFER_ID_BACK, to, CRSTATE_STENCIL_BUFFER_ID_FRONT); + + frontIsSet = GL_TRUE; + backIsSet = GL_TRUE; + } + } + else if (!CR_STATE_STENCIL_OP_FRONT_MATCH()) + { + if (!frontIsSet) + { + if (activeFace == GL_BACK) + { + diff_api.ActiveStencilFaceEXT(GL_FRONT); + activeFace = GL_FRONT; + } + + diff_api.StencilOpSeparate (GL_FRONT, to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].fail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthFail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthPass); + + CR_STATE_STENCIL_OP_COPY(from, CRSTATE_STENCIL_BUFFER_ID_FRONT, to, CRSTATE_STENCIL_BUFFER_ID_FRONT); + + frontIsSet = GL_TRUE; + } + } + else if (!CR_STATE_STENCIL_OP_BACK_MATCH()) + { + if (!backIsSet) + { + if (activeFace == GL_BACK) + { + diff_api.ActiveStencilFaceEXT(GL_FRONT); + activeFace = GL_FRONT; + } + + diff_api.StencilOpSeparate (GL_BACK, to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].fail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].passDepthFail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].passDepthPass); + CR_STATE_STENCIL_OP_COPY(from, CRSTATE_STENCIL_BUFFER_ID_BACK, to, CRSTATE_STENCIL_BUFFER_ID_BACK); + backIsSet = GL_TRUE; + } + } + } + CLEARDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_BACK].op, nbitID); + } + + if (CHECKDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_TWO_SIDE_BACK].op, bitID)) + { + if (!CR_STATE_STENCIL_OP_MATCH(from, CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK, to, CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK)) + { + if (activeFace == GL_FRONT) + { + diff_api.ActiveStencilFaceEXT(GL_BACK); + activeFace = GL_BACK; + } + + diff_api.StencilOp (to->buffers[CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].fail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].passDepthFail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].passDepthPass); + CR_STATE_STENCIL_OP_COPY(from, CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK, to, CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK); + } + CLEARDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_TWO_SIDE_BACK].op, nbitID); + } + +#undef CR_STATE_STENCIL_OP_FRONT_MATCH +#undef CR_STATE_STENCIL_OP_BACK_MATCH +#undef CR_STATE_STENCIL_OP_TO_FRONT_BACK_MATCH + + + if (activeFace != to->activeStencilFace) + { + diff_api.ActiveStencilFaceEXT(activeFace); + } + + if (CHECKDIRTY(b->activeStencilFace, bitID)) + { + if (from->activeStencilFace != to->activeStencilFace) + { + /* we already did it ( see above )*/ + /* diff_api.ActiveStencilFaceEXT(to->activeStencilFace); */ + from->activeStencilFace = to->activeStencilFace; + } + CLEARDIRTY(b->activeStencilFace, nbitID); + } + + if (CHECKDIRTY(b->writeMask, bitID)) + { + if (from->writeMask != to->writeMask) + { + diff_api.StencilMask (to->writeMask); + from->writeMask = to->writeMask; + } + CLEARDIRTY(b->writeMask, nbitID); + } + CLEARDIRTY(b->dirty, nbitID); +} + +void crStateStencilSwitch(CRStencilBits *b, CRbitvalue *bitID, + CRContext *fromCtx, CRContext *toCtx) +{ + CRStencilState *from = &(fromCtx->stencil); + CRStencilState *to = &(toCtx->stencil); + unsigned int j, i; + GLenum activeFace; + GLboolean backIsSet = GL_FALSE, frontIsSet = GL_FALSE, frontBackDirty, frontDirty, backDirty; + GLchar frontMatch = -1, backMatch = -1, toFrontBackMatch = -1; + CRbitvalue nbitID[CR_MAX_BITARRAY]; + for (j=0;j<CR_MAX_BITARRAY;j++) + nbitID[j] = ~bitID[j]; + i = 0; /* silence compiler */ + + if (CHECKDIRTY(b->enable, bitID)) + { + glAble able[2]; + able[0] = diff_api.Disable; + able[1] = diff_api.Enable; + if (from->stencilTest != to->stencilTest) + { + CRSTATE_CHECKGLERR(able[to->stencilTest](GL_STENCIL_TEST)); + FILLDIRTY(b->enable); + FILLDIRTY(b->dirty); + } + CLEARDIRTY(b->enable, nbitID); + } + if (CHECKDIRTY(b->enableTwoSideEXT, bitID)) + { + glAble able[2]; + able[0] = diff_api.Disable; + able[1] = diff_api.Enable; + if (from->stencilTwoSideEXT != to->stencilTwoSideEXT) + { + CRSTATE_CHECKGLERR(able[to->stencilTwoSideEXT](GL_STENCIL_TEST_TWO_SIDE_EXT)); + FILLDIRTY(b->enableTwoSideEXT); + FILLDIRTY(b->dirty); + } + CLEARDIRTY(b->enableTwoSideEXT, nbitID); + } + if (CHECKDIRTY(b->clearValue, bitID)) + { + if (from->clearValue != to->clearValue) + { + CRSTATE_CHECKGLERR(diff_api.ClearStencil (to->clearValue)); + FILLDIRTY(b->clearValue); + FILLDIRTY(b->dirty); + } + CLEARDIRTY(b->clearValue, nbitID); + } + + activeFace = from->activeStencilFace; + + /* func */ + frontBackDirty = CHECKDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT_AND_BACK].func, bitID); + frontDirty = CHECKDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT].func, bitID); + backDirty = CHECKDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_BACK].func, bitID); +#define CR_STATE_STENCIL_FUNC_FRONT_MATCH() ( \ + frontMatch >= 0 ? \ + frontMatch \ + : (frontMatch = CR_STATE_STENCIL_FUNC_MATCH(from, CRSTATE_STENCIL_BUFFER_ID_FRONT, to, CRSTATE_STENCIL_BUFFER_ID_FRONT))) + +#define CR_STATE_STENCIL_FUNC_BACK_MATCH() ( \ + backMatch >= 0 ? \ + backMatch \ + : (backMatch = CR_STATE_STENCIL_FUNC_MATCH(from, CRSTATE_STENCIL_BUFFER_ID_BACK, to, CRSTATE_STENCIL_BUFFER_ID_BACK))) + +#define CR_STATE_STENCIL_FUNC_TO_FRONT_BACK_MATCH() ( \ + toFrontBackMatch >= 0 ? \ + toFrontBackMatch \ + : (toFrontBackMatch = CR_STATE_STENCIL_FUNC_MATCH(to, CRSTATE_STENCIL_BUFFER_ID_FRONT, to, CRSTATE_STENCIL_BUFFER_ID_BACK))) + + if (frontBackDirty) + { + if (!CR_STATE_STENCIL_FUNC_FRONT_MATCH() + || !CR_STATE_STENCIL_FUNC_BACK_MATCH()) + { + if (CR_STATE_STENCIL_FUNC_TO_FRONT_BACK_MATCH()) + { + if (activeFace == GL_BACK) + { + diff_api.ActiveStencilFaceEXT(GL_FRONT); + activeFace = GL_FRONT; + } + + CRSTATE_CHECKGLERR(diff_api.StencilFunc (to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].func, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].ref, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].mask)); + + frontIsSet = GL_TRUE; + backIsSet = GL_TRUE; + } + else if (!CR_STATE_STENCIL_FUNC_FRONT_MATCH()) + { + if (activeFace == GL_BACK) + { + diff_api.ActiveStencilFaceEXT(GL_FRONT); + activeFace = GL_FRONT; + } + + CRSTATE_CHECKGLERR(diff_api.StencilFuncSeparate (GL_FRONT, to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].func, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].ref, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].mask)); + frontIsSet = GL_TRUE; + } + else if (!CR_STATE_STENCIL_FUNC_BACK_MATCH()) + { + if (activeFace == GL_BACK) + { + diff_api.ActiveStencilFaceEXT(GL_FRONT); + activeFace = GL_FRONT; + } + + CRSTATE_CHECKGLERR(diff_api.StencilFuncSeparate (GL_BACK, to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].func, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].ref, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].mask)); + backIsSet = GL_TRUE; + } + FILLDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT_AND_BACK].func); + FILLDIRTY(b->dirty); + } + + CLEARDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT_AND_BACK].func, nbitID); + } + + if (frontDirty) + { + if (!CR_STATE_STENCIL_FUNC_FRONT_MATCH()) + { + if (CR_STATE_STENCIL_FUNC_TO_FRONT_BACK_MATCH()) + { + if (!frontIsSet || !backIsSet) + { + if (activeFace == GL_BACK) + { + diff_api.ActiveStencilFaceEXT(GL_FRONT); + activeFace = GL_FRONT; + } + + CRSTATE_CHECKGLERR(diff_api.StencilFunc (to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].func, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].ref, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].mask)); + + frontIsSet = GL_TRUE; + backIsSet = GL_TRUE; + } + } + else if (!CR_STATE_STENCIL_FUNC_FRONT_MATCH()) + { + if (!frontIsSet) + { + if (activeFace == GL_BACK) + { + diff_api.ActiveStencilFaceEXT(GL_FRONT); + activeFace = GL_FRONT; + } + + CRSTATE_CHECKGLERR(diff_api.StencilFuncSeparate (GL_FRONT, to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].func, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].ref, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].mask)); + frontIsSet = GL_TRUE; + } + } + else if (!CR_STATE_STENCIL_FUNC_BACK_MATCH()) + { + if (!backIsSet) + { + if (activeFace == GL_BACK) + { + diff_api.ActiveStencilFaceEXT(GL_FRONT); + activeFace = GL_FRONT; + } + + CRSTATE_CHECKGLERR(diff_api.StencilFuncSeparate (GL_BACK, to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].func, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].ref, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].mask)); + backIsSet = GL_TRUE; + } + } + FILLDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT].func); + FILLDIRTY(b->dirty); + } + CLEARDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT].func, nbitID); + } + + + if (backDirty) + { + if (!CR_STATE_STENCIL_FUNC_BACK_MATCH()) + { + if (CR_STATE_STENCIL_FUNC_TO_FRONT_BACK_MATCH()) + { + if (!frontIsSet || !backIsSet) + { + if (activeFace == GL_BACK) + { + diff_api.ActiveStencilFaceEXT(GL_FRONT); + activeFace = GL_FRONT; + } + + CRSTATE_CHECKGLERR(diff_api.StencilFunc (to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].func, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].ref, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].mask)); + + frontIsSet = GL_TRUE; + backIsSet = GL_TRUE; + } + } + else if (!CR_STATE_STENCIL_FUNC_FRONT_MATCH()) + { + if (!frontIsSet) + { + if (activeFace == GL_BACK) + { + diff_api.ActiveStencilFaceEXT(GL_FRONT); + activeFace = GL_FRONT; + } + + CRSTATE_CHECKGLERR(diff_api.StencilFuncSeparate (GL_FRONT, to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].func, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].ref, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].mask)); + frontIsSet = GL_TRUE; + } + } + else if (!CR_STATE_STENCIL_FUNC_BACK_MATCH()) + { + if (!backIsSet) + { + if (activeFace == GL_BACK) + { + diff_api.ActiveStencilFaceEXT(GL_FRONT); + activeFace = GL_FRONT; + } + + CRSTATE_CHECKGLERR(diff_api.StencilFuncSeparate (GL_BACK, to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].func, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].ref, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].mask)); + backIsSet = GL_TRUE; + } + } + FILLDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_BACK].func); + FILLDIRTY(b->dirty); + } + CLEARDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_BACK].func, nbitID); + } + + if (CHECKDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_TWO_SIDE_BACK].func, bitID)) + { + if (!CR_STATE_STENCIL_FUNC_MATCH(from, CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK, to, CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK)) + { + if (activeFace == GL_FRONT) + { + CRSTATE_CHECKGLERR(diff_api.ActiveStencilFaceEXT(GL_BACK)); + activeFace = GL_BACK; + } + + CRSTATE_CHECKGLERR(diff_api.StencilFunc (to->buffers[CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].func, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].ref, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].mask)); + + FILLDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_TWO_SIDE_BACK].func); + FILLDIRTY(b->dirty); + } + CLEARDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_TWO_SIDE_BACK].func, nbitID); + } + +#undef CR_STATE_STENCIL_FUNC_FRONT_MATCH +#undef CR_STATE_STENCIL_FUNC_BACK_MATCH +#undef CR_STATE_STENCIL_FUNC_TO_FRONT_BACK_MATCH + + /* op */ + backIsSet = GL_FALSE, frontIsSet = GL_FALSE; + frontMatch = -1, backMatch = -1, toFrontBackMatch = -1; + frontBackDirty = CHECKDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT_AND_BACK].op, bitID); + frontDirty = CHECKDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT].op, bitID); + backDirty = CHECKDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_BACK].op, bitID); + +#define CR_STATE_STENCIL_OP_FRONT_MATCH() ( \ + frontMatch >= 0 ? \ + frontMatch \ + : (frontMatch = CR_STATE_STENCIL_OP_MATCH(from, CRSTATE_STENCIL_BUFFER_ID_FRONT, to, CRSTATE_STENCIL_BUFFER_ID_FRONT))) + +#define CR_STATE_STENCIL_OP_BACK_MATCH() ( \ + backMatch >= 0 ? \ + backMatch \ + : (backMatch = CR_STATE_STENCIL_OP_MATCH(from, CRSTATE_STENCIL_BUFFER_ID_BACK, to, CRSTATE_STENCIL_BUFFER_ID_BACK))) + +#define CR_STATE_STENCIL_OP_TO_FRONT_BACK_MATCH() ( \ + toFrontBackMatch >= 0 ? \ + toFrontBackMatch \ + : (toFrontBackMatch = CR_STATE_STENCIL_OP_MATCH(to, CRSTATE_STENCIL_BUFFER_ID_FRONT, to, CRSTATE_STENCIL_BUFFER_ID_BACK))) + + if (frontBackDirty) + { + if (!CR_STATE_STENCIL_OP_FRONT_MATCH() + || !CR_STATE_STENCIL_OP_BACK_MATCH()) + { + if (CR_STATE_STENCIL_OP_TO_FRONT_BACK_MATCH()) + { + if (activeFace == GL_BACK) + { + CRSTATE_CHECKGLERR(diff_api.ActiveStencilFaceEXT(GL_FRONT)); + activeFace = GL_FRONT; + } + + CRSTATE_CHECKGLERR(diff_api.StencilOp (to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].fail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthFail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthPass)); + + frontIsSet = GL_TRUE; + backIsSet = GL_TRUE; + } + else if (!CR_STATE_STENCIL_OP_FRONT_MATCH()) + { + if (activeFace == GL_BACK) + { + CRSTATE_CHECKGLERR(diff_api.ActiveStencilFaceEXT(GL_FRONT)); + activeFace = GL_FRONT; + } + + CRSTATE_CHECKGLERR(diff_api.StencilOpSeparate (GL_FRONT, to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].fail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthFail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthPass)); + frontIsSet = GL_TRUE; + } + else if (!CR_STATE_STENCIL_OP_BACK_MATCH()) + { + if (activeFace == GL_BACK) + { + CRSTATE_CHECKGLERR(diff_api.ActiveStencilFaceEXT(GL_FRONT)); + activeFace = GL_FRONT; + } + + CRSTATE_CHECKGLERR(diff_api.StencilOpSeparate (GL_BACK, to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].fail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].passDepthFail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].passDepthPass)); + backIsSet = GL_TRUE; + } + FILLDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT_AND_BACK].op); + FILLDIRTY(b->dirty); + } + + CLEARDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT_AND_BACK].op, nbitID); + } + + if (frontDirty) + { + if (!CR_STATE_STENCIL_OP_FRONT_MATCH()) + { + if (CR_STATE_STENCIL_OP_TO_FRONT_BACK_MATCH()) + { + if (!frontIsSet || !backIsSet) + { + if (activeFace == GL_BACK) + { + CRSTATE_CHECKGLERR(diff_api.ActiveStencilFaceEXT(GL_FRONT)); + activeFace = GL_FRONT; + } + + CRSTATE_CHECKGLERR(diff_api.StencilOp (to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].fail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthFail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthPass)); + + frontIsSet = GL_TRUE; + backIsSet = GL_TRUE; + } + } + else if (!CR_STATE_STENCIL_OP_FRONT_MATCH()) + { + if (!frontIsSet) + { + if (activeFace == GL_BACK) + { + CRSTATE_CHECKGLERR(diff_api.ActiveStencilFaceEXT(GL_FRONT)); + activeFace = GL_FRONT; + } + + CRSTATE_CHECKGLERR(diff_api.StencilOpSeparate (GL_FRONT, to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].fail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthFail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthPass)); + frontIsSet = GL_TRUE; + } + } + else if (!CR_STATE_STENCIL_OP_BACK_MATCH()) + { + if (!backIsSet) + { + if (activeFace == GL_BACK) + { + CRSTATE_CHECKGLERR(diff_api.ActiveStencilFaceEXT(GL_FRONT)); + activeFace = GL_FRONT; + } + + CRSTATE_CHECKGLERR(diff_api.StencilOpSeparate (GL_BACK, to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].fail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].passDepthFail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].passDepthPass)); + backIsSet = GL_TRUE; + } + } + + FILLDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT].op); + FILLDIRTY(b->dirty); + } + CLEARDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_FRONT].op, nbitID); + } + + + if (backDirty) + { + if (!CR_STATE_STENCIL_OP_BACK_MATCH()) + { + if (CR_STATE_STENCIL_OP_TO_FRONT_BACK_MATCH()) + { + if (!frontIsSet || !backIsSet) + { + if (activeFace == GL_BACK) + { + CRSTATE_CHECKGLERR(diff_api.ActiveStencilFaceEXT(GL_FRONT)); + activeFace = GL_FRONT; + } + + CRSTATE_CHECKGLERR(diff_api.StencilOp (to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].fail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthFail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthPass)); + + frontIsSet = GL_TRUE; + backIsSet = GL_TRUE; + } + } + else if (!CR_STATE_STENCIL_OP_FRONT_MATCH()) + { + if (!frontIsSet) + { + if (activeFace == GL_BACK) + { + CRSTATE_CHECKGLERR(diff_api.ActiveStencilFaceEXT(GL_FRONT)); + activeFace = GL_FRONT; + } + + CRSTATE_CHECKGLERR(diff_api.StencilOpSeparate (GL_FRONT, to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].fail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthFail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_FRONT].passDepthPass)); + frontIsSet = GL_TRUE; + } + } + else if (!CR_STATE_STENCIL_OP_BACK_MATCH()) + { + if (!backIsSet) + { + if (activeFace == GL_BACK) + { + CRSTATE_CHECKGLERR(diff_api.ActiveStencilFaceEXT(GL_FRONT)); + activeFace = GL_FRONT; + } + + CRSTATE_CHECKGLERR(diff_api.StencilOpSeparate (GL_BACK, to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].fail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].passDepthFail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_BACK].passDepthPass)); + backIsSet = GL_TRUE; + } + } + + FILLDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_BACK].op); + FILLDIRTY(b->dirty); + } + CLEARDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_BACK].op, nbitID); + } + + if (CHECKDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_TWO_SIDE_BACK].op, bitID)) + { + if (!CR_STATE_STENCIL_OP_MATCH(from, CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK, to, CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK)) + { + if (activeFace == GL_FRONT) + { + CRSTATE_CHECKGLERR(diff_api.ActiveStencilFaceEXT(GL_BACK)); + activeFace = GL_BACK; + } + + CRSTATE_CHECKGLERR(diff_api.StencilOp (to->buffers[CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].fail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].passDepthFail, + to->buffers[CRSTATE_STENCIL_BUFFER_ID_TWO_SIDE_BACK].passDepthPass)); + + FILLDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_TWO_SIDE_BACK].op); + FILLDIRTY(b->dirty); + } + CLEARDIRTY(b->bufferRefs[CRSTATE_STENCIL_BUFFER_REF_ID_TWO_SIDE_BACK].op, nbitID); + } + +#undef CR_STATE_STENCIL_OP_FRONT_MATCH +#undef CR_STATE_STENCIL_OP_BACK_MATCH +#undef CR_STATE_STENCIL_OP_TO_FRONT_BACK_MATCH + + if (activeFace != to->activeStencilFace) + { + CRSTATE_CHECKGLERR(diff_api.ActiveStencilFaceEXT(activeFace)); + } + + if (CHECKDIRTY(b->activeStencilFace, bitID)) + { + if (from->activeStencilFace != to->activeStencilFace) + { + /* we already did it ( see above )*/ + /* diff_api.ActiveStencilFaceEXT(to->activeStencilFace); */ + FILLDIRTY(b->activeStencilFace); + FILLDIRTY(b->dirty); + } + CLEARDIRTY(b->activeStencilFace, nbitID); + } + + if (CHECKDIRTY(b->writeMask, bitID)) + { + if (from->writeMask != to->writeMask) + { + CRSTATE_CHECKGLERR(diff_api.StencilMask (to->writeMask)); + FILLDIRTY(b->writeMask); + FILLDIRTY(b->dirty); + } + CLEARDIRTY(b->writeMask, nbitID); + } + + CLEARDIRTY(b->dirty, nbitID); +} + diff --git a/src/VBox/GuestHost/OpenGL/state_tracker/state_texdiff.c b/src/VBox/GuestHost/OpenGL/state_tracker/state_texdiff.c index 00adbfff..5ac9028a 100644 --- a/src/VBox/GuestHost/OpenGL/state_tracker/state_texdiff.c +++ b/src/VBox/GuestHost/OpenGL/state_tracker/state_texdiff.c @@ -603,6 +603,10 @@ crStateTextureObjectDiff(CRContext *fromCtx, CRTextureState *from = &(fromCtx->texture); glAble able[2]; int u = 0; /* always use texture unit 0 for diff'ing */ + GLuint hwid = crStateGetTextureObjHWID(tobj); + + if (!hwid) + return; able[0] = diff_api.Disable; able[1] = diff_api.Enable; @@ -619,7 +623,7 @@ crStateTextureObjectDiff(CRContext *fromCtx, } #endif - diff_api.BindTexture(tobj->target, crStateGetTextureObjHWID(tobj)); + diff_api.BindTexture(tobj->target, hwid); if (alwaysDirty || CHECKDIRTY(tobj->paramsBit[u], bitID)) { @@ -1448,7 +1452,7 @@ crStateDiffAllTextureObjects( CRContext *g, CRbitvalue *bitID, GLboolean bForceU #endif /* restore bindings */ - diff_api.ActiveTextureARB(GL_TEXTURE0_ARB + origUnit); + /* first restore unit 0 bindings the unit 0 is active currently */ diff_api.BindTexture(GL_TEXTURE_1D, orig1D); diff_api.BindTexture(GL_TEXTURE_2D, orig2D); diff_api.BindTexture(GL_TEXTURE_3D, orig3D); @@ -1458,4 +1462,6 @@ crStateDiffAllTextureObjects( CRContext *g, CRbitvalue *bitID, GLboolean bForceU #ifdef CR_NV_texture_rectangle diff_api.BindTexture(GL_TEXTURE_RECTANGLE_NV, origRect); #endif + /* now restore the proper active unit */ + diff_api.ActiveTextureARB(GL_TEXTURE0_ARB + origUnit); } diff --git a/src/VBox/GuestHost/OpenGL/state_tracker/state_teximage.c b/src/VBox/GuestHost/OpenGL/state_tracker/state_teximage.c index 6917197b..41d96125 100644 --- a/src/VBox/GuestHost/OpenGL/state_tracker/state_teximage.c +++ b/src/VBox/GuestHost/OpenGL/state_tracker/state_teximage.c @@ -245,7 +245,7 @@ crStateGetTextureObjectAndImage(CRContext *g, GLenum texTarget, GLint level, return; default: /* fall-through */ - ; + ; } #ifdef CR_NV_texture_rectangle @@ -308,6 +308,7 @@ crStateGetTextureObjectAndImage(CRContext *g, GLenum texTarget, GLint level, } #endif + crWarning("unexpected texTarget 0x%x", texTarget); *obj = NULL; *img = NULL; } @@ -971,6 +972,13 @@ crStateTexSubImage1D(GLenum target, GLint level, GLint xoffset, return; /* GL error state already set */ } +#ifdef DEBUG_misha + CRASSERT(tl->bytes); + CRASSERT(tl->height); + CRASSERT(tl->width); + CRASSERT(tl->depth); +#endif + #ifndef CR_STATE_NO_TEXTURE_IMAGE_STORE xoffset += tl->border; @@ -1024,6 +1032,13 @@ crStateTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, CRASSERT(tobj); CRASSERT(tl); +#ifdef DEBUG_misha + CRASSERT(tl->bytes); + CRASSERT(tl->height); + CRASSERT(tl->width); + CRASSERT(tl->depth); +#endif + #ifndef CR_STATE_NO_TEXTURE_IMAGE_STORE xoffset += tl->border; yoffset += tl->border; @@ -1109,6 +1124,14 @@ crStateTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, return; /* GL error state already set */ } +#ifdef DEBUG_misha + CRASSERT(target == GL_TEXTURE_3D); + CRASSERT(tl->bytes); + CRASSERT(tl->height); + CRASSERT(tl->width); + CRASSERT(tl->depth); +#endif + #ifndef CR_STATE_NO_TEXTURE_IMAGE_STORE xoffset += tl->border; yoffset += tl->border; @@ -1416,6 +1439,14 @@ crStateCompressedTexSubImage1DARB(GLenum target, GLint level, GLint xoffset, return; /* GL error state already set */ } +#ifdef DEBUG_misha + CRASSERT(target == GL_TEXTURE_1D); + CRASSERT(tl->bytes); + CRASSERT(tl->height); + CRASSERT(tl->width); + CRASSERT(tl->depth); +#endif + #ifndef CR_STATE_NO_TEXTURE_IMAGE_STORE xoffset += tl->border; @@ -1456,11 +1487,19 @@ crStateCompressedTexSubImage2DARB(GLenum target, GLint level, GLint xoffset, CRStateBits *sb = GetCurrentBits(); CRTextureBits *tb = &(sb->texture); CRTextureUnit *unit = t->unit + t->curTextureUnit; - CRTextureObj *tobj = unit->currentTexture1D; + CRTextureObj *tobj = unit->currentTexture2D; CRTextureLevel *tl = tobj->level[0] + level; FLUSH(); +#ifdef DEBUG_misha + CRASSERT(target == GL_TEXTURE_2D); + CRASSERT(tl->bytes); + CRASSERT(tl->height); + CRASSERT(tl->width); + CRASSERT(tl->depth); +#endif + if (ErrorCheckTexSubImage(2, target, level, xoffset, yoffset, 0, width, height, 1)) { return; /* GL error state already set */ @@ -1510,11 +1549,19 @@ crStateCompressedTexSubImage3DARB(GLenum target, GLint level, GLint xoffset, CRStateBits *sb = GetCurrentBits(); CRTextureBits *tb = &(sb->texture); CRTextureUnit *unit = t->unit + t->curTextureUnit; - CRTextureObj *tobj = unit->currentTexture1D; + CRTextureObj *tobj = unit->currentTexture3D; CRTextureLevel *tl = tobj->level[0] + level; FLUSH(); +#ifdef DEBUG_misha + CRASSERT(target == GL_TEXTURE_3D); + CRASSERT(tl->bytes); + CRASSERT(tl->height); + CRASSERT(tl->width); + CRASSERT(tl->depth); +#endif + if (ErrorCheckTexSubImage(3, target, level, xoffset, yoffset, zoffset, width, height, depth)) { return; /* GL error state already set */ @@ -1580,6 +1627,13 @@ crStateGetCompressedTexImageARB(GLenum target, GLint level, GLvoid * img) return; } +#ifdef DEBUG_misha + CRASSERT(tl->bytes); + CRASSERT(tl->height); + CRASSERT(tl->width); + CRASSERT(tl->depth); +#endif + #ifndef CR_STATE_NO_TEXTURE_IMAGE_STORE crMemcpy(img, tl->img, tl->bytes); #else @@ -1616,6 +1670,13 @@ crStateGetTexImage(GLenum target, GLint level, GLenum format, return; } +#ifdef DEBUG_misha + CRASSERT(tl->bytes); + CRASSERT(tl->height); + CRASSERT(tl->width); + CRASSERT(tl->depth); +#endif + switch (format) { case GL_RED: diff --git a/src/VBox/GuestHost/OpenGL/state_tracker/state_texture.c b/src/VBox/GuestHost/OpenGL/state_tracker/state_texture.c index 951a0e55..5da27393 100644 --- a/src/VBox/GuestHost/OpenGL/state_tracker/state_texture.c +++ b/src/VBox/GuestHost/OpenGL/state_tracker/state_texture.c @@ -250,10 +250,8 @@ crStateTextureInitTextureObj(CRContext *ctx, CRTextureObj *tobj, RESET(tobj->paramsBit[i], ctx->bitid); } -#ifndef IN_GUEST CR_STATE_SHAREDOBJ_USAGE_INIT(tobj); CR_STATE_SHAREDOBJ_USAGE_SET(tobj, ctx); -#endif } @@ -620,9 +618,29 @@ crStateDeleteTextureObject(CRTextureObj *tobj) crFree(tobj); } -void STATE_APIENTRY crStateGenTextures(GLsizei n, GLuint *textures) +void crStateRegNames(CRContext *g, CRHashTable *table, GLsizei n, GLuint *names) +{ + GLint i; + for (i = 0; i < n; i++) + { + if (names[i]) + { + GLboolean isNewKey = crHashtableAllocRegisterKey(table, names[i]); + CRASSERT(isNewKey); + } + else + crWarning("RegNames: requested to register a null name"); + } +} + +void crStateRegTextures(GLsizei n, GLuint *names) { CRContext *g = GetCurrentContext(); + crStateRegNames(g, g->shared->textureTable, n, names); +} + +void crStateGenNames(CRContext *g, CRHashTable *table, GLsizei n, GLuint *names) +{ GLint start; FLUSH(); @@ -630,23 +648,23 @@ void STATE_APIENTRY crStateGenTextures(GLsizei n, GLuint *textures) if (g->current.inBeginEnd) { crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION, - "glGenTextures called in Begin/End"); + "crStateGenNames called in Begin/End"); return; } if (n < 0) { crStateError(__LINE__, __FILE__, GL_INVALID_VALUE, - "Negative n passed to glGenTextures: %d", n); + "Negative n passed to crStateGenNames: %d", n); return; } - start = crHashtableAllocKeys(g->shared->textureTable, n); + start = crHashtableAllocKeys(table, n); if (start) { GLint i; for (i = 0; i < n; i++) - textures[i] = (GLuint) (start + i); + names[i] = (GLuint) (start + i); } else { @@ -654,6 +672,12 @@ void STATE_APIENTRY crStateGenTextures(GLsizei n, GLuint *textures) } } +void STATE_APIENTRY crStateGenTextures(GLsizei n, GLuint *textures) +{ + CRContext *g = GetCurrentContext(); + crStateGenNames(g, g->shared->textureTable, n, textures); +} + static void crStateTextureCheckFBOAPs(GLenum target, GLuint texture) { GLuint u; @@ -730,6 +754,7 @@ static void crStateCleanupTextureRefs(CRContext *g, CRTextureObj *tObj) #endif } + CR_STATE_SHAREDOBJ_USAGE_CLEAR(tObj, g); } void STATE_APIENTRY crStateDeleteTextures(GLsizei n, const GLuint *textures) @@ -760,15 +785,39 @@ void STATE_APIENTRY crStateDeleteTextures(GLsizei n, const GLuint *textures) { GLuint name = textures[i]; CRTextureObj *tObj; + if (!name) + continue; + GET_TOBJ(tObj, g, name); - if (name && tObj) + if (tObj) { + GLuint j; + crStateCleanupTextureRefs(g, tObj); + CR_STATE_SHAREDOBJ_USAGE_FOREACH_USED_IDX(tObj, j) + { + /* saved state version <= SHCROGL_SSM_VERSION_BEFORE_CTXUSAGE_BITS does not have usage bits info, + * so on restore, we set mark bits as used. + * This is why g_pAvailableContexts[j] could be NULL + * also g_pAvailableContexts[0] will hold default context, which we should discard */ + CRContext *ctx = g_pAvailableContexts[j]; + if (j && ctx) + crStateCleanupTextureRefs(ctx, tObj); + else + CR_STATE_SHAREDOBJ_USAGE_CLEAR_IDX(tObj, j); + } + /* on the host side, ogl texture object is deleted by a separate cr_server.head_spu->dispatch_table.DeleteTextures(n, newTextures); * in crServerDispatchDeleteTextures, we just delete a state object here, which crStateDeleteTextureObject does */ crHashtableDelete(g->shared->textureTable, name, (CRHashtableCallback)crStateDeleteTextureObject); } + else + { + /* call crHashtableDelete in any way, to ensure the allocated key is freed */ + Assert(crHashtableIsKeyUsed(g->shared->textureTable, name)); + crHashtableDelete(g->shared->textureTable, name, NULL); + } } DIRTY(tb->dirty, g->neg_bitid); @@ -858,8 +907,17 @@ DECLEXPORT(void) crStateSetTextureUsed(GLuint texture, GLboolean used) GET_TOBJ(tobj, g, texture); if (!tobj) { - crWarning("crStateSetTextureUsed: failed to fined a HW name for texture(%d)!", texture); - return; +#ifdef IN_GUEST + if (used) + { + tobj = crStateTextureAllocate_t(g, texture); + } + else +#endif + { + crWarning("crStateSetTextureUsed: failed to fined a HW name for texture(%d)!", texture); + return; + } } if (used) @@ -870,8 +928,6 @@ DECLEXPORT(void) crStateSetTextureUsed(GLuint texture, GLboolean used) CRTextureBits *tb = &(sb->texture); CRTextureState *t = &(g->texture); - CR_STATE_SHAREDOBJ_USAGE_CLEAR(tobj, g); - crStateCleanupTextureRefs(g, tobj); if (!CR_STATE_SHAREDOBJ_USAGE_IS_USED(tobj)) @@ -953,12 +1009,11 @@ void STATE_APIENTRY crStateBindTexture(GLenum target, GLuint texture) GET_TOBJ(tobj, g, texture); if (!tobj) { + Assert(crHashtableIsKeyUsed(g->shared->textureTable, texture)); tobj = crStateTextureAllocate_t(g, texture); } -#ifndef IN_GUEST CR_STATE_SHAREDOBJ_USAGE_SET(tobj, g); -#endif /* Check the targets */ if (tobj->target == GL_NONE) @@ -3204,10 +3259,28 @@ void STATE_APIENTRY crStatePrioritizeTextures(GLsizei n, const GLuint *textures, const GLclampf *priorities) { - UNUSED(n); - UNUSED(textures); + CRContext *g = GetCurrentContext(); + CRTextureObj *tobj; + GLsizei i; UNUSED(priorities); - /* TODO: */ + + for (i = 0; i < n; ++i) + { + GLuint tex = textures[i]; + GET_TOBJ(tobj, g, tex); + if (!tobj) + { + Assert(crHashtableIsKeyUsed(g->shared->textureTable, tex)); + tobj = crStateTextureAllocate_t(g, tex); + } + + /* so far the code just ensures the tex object is created to make + * the crserverlib code be able to pass it to host ogl */ + + /* TODO: store texture priorities in the state data to be able to restore it properly + * on save state load */ + } + return; } @@ -3259,7 +3332,9 @@ DECLEXPORT(GLuint) STATE_APIENTRY crStateTextureHWIDtoID(GLuint hwid) DECLEXPORT(GLuint) STATE_APIENTRY crStateGetTextureHWID(GLuint id) { CRContext *g = GetCurrentContext(); - CRTextureObj *tobj = GET_TOBJ(tobj, g, id); + CRTextureObj *tobj; + + GET_TOBJ(tobj, g, id); #ifdef DEBUG_misha if (id) |
