diff options
Diffstat (limited to 'src/VBox/GuestHost/OpenGL/state_tracker/state_snapshot.c')
-rw-r--r-- | src/VBox/GuestHost/OpenGL/state_tracker/state_snapshot.c | 2678 |
1 files changed, 2678 insertions, 0 deletions
diff --git a/src/VBox/GuestHost/OpenGL/state_tracker/state_snapshot.c b/src/VBox/GuestHost/OpenGL/state_tracker/state_snapshot.c new file mode 100644 index 00000000..ee17cd37 --- /dev/null +++ b/src/VBox/GuestHost/OpenGL/state_tracker/state_snapshot.c @@ -0,0 +1,2678 @@ +/* $Id: state_snapshot.c $ */ +/** @file + * VBox Context state saving/loading used by VM snapshot + */ + +/* + * Copyright (C) 2008-2019 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 "state.h" +#include "state_internals.h" +#include "state/cr_statetypes.h" +#include "state/cr_texture.h" +#include "cr_mem.h" +#include "cr_string.h" +#include "cr_pixeldata.h" +#include <stdio.h> + +#include <iprt/assert.h> +#include <iprt/types.h> +#include <iprt/err.h> +#include <VBox/err.h> +#include <VBox/log.h> + +/** @todo + * We have two ways of saving/loading states. + * + * First which is being used atm, just pure saving/loading of structures. + * The drawback is we have to deal with all the pointers around those structures, + * we'd have to update this code if we'd change state tracking. + * On the bright side it's fast, though it's not really needed as it's not that often operation. + * It could also worth to split those functions into appropriate parts, + * similar to the way context creation is being done. + * + * Second way would be to implement full dispatch api table and substitute diff_api during saving/loading. + * Then if we implement that api in a similar way to packer/unpacker with a change to store/load + * via provided pSSM handle instead of pack buffer, + * saving state could be done by simple diffing against empty "dummy" context. + * Restoring state in such case would look like unpacking commands from pSSM instead of network buffer. + * This would be slower (who cares) but most likely will not require any code changes to support in future. + * We will reduce amount of saved data as we'd save only changed state parts, but I doubt it'd be that much. + * It could be done for the first way as well, but requires tons of bit checks. + */ + +static int32_t crStateAllocAndSSMR3GetMem(PSSMHANDLE pSSM, void **pBuffer, size_t cbBuffer) +{ + CRASSERT(pSSM && pBuffer && cbBuffer>0); + + *pBuffer = crAlloc((unsigned int /* this case is just so stupid */)cbBuffer); + if (!*pBuffer) + return VERR_NO_MEMORY; + + return SSMR3GetMem(pSSM, *pBuffer, cbBuffer); +} + +#define SHCROGL_GET_STRUCT_PART(_pPtr, _type, _from, _to) do { \ + rc = SSMR3GetMem(pSSM, &(_pPtr)->_from, RT_UOFFSETOF(_type, _to) - RT_UOFFSETOF(_type, _from)); \ + AssertRCReturn(rc, rc); \ + } while (0) + +#define SHCROGL_GET_STRUCT_TAIL(_pPtr, _type, _from) do { \ + rc = SSMR3GetMem(pSSM, &(_pPtr)->_from, sizeof (_type) - RT_UOFFSETOF(_type, _from)); \ + AssertRCReturn(rc, rc); \ + } while (0) + +#define SHCROGL_GET_STRUCT_HEAD(_pPtr, _type, _to) do { \ + rc = SSMR3GetMem(pSSM, (_pPtr), RT_UOFFSETOF(_type, _to)); \ + AssertRCReturn(rc, rc); \ + } while (0) + +#define SHCROGL_CUT_FIELD_ALIGNMENT_SIZE(_type, _prevField, _field) (RT_UOFFSETOF(_type, _field) - RT_UOFFSETOF(_type, _prevField) - RT_SIZEOFMEMB(_type, _prevField)) +#define SHCROGL_CUT_FIELD_ALIGNMENT(_type, _prevField, _field) do { \ + const int32_t cbAlignment = SHCROGL_CUT_FIELD_ALIGNMENT_SIZE(_type, _prevField, _field) ; \ + /*AssertCompile(SHCROGL_CUT_FIELD_ALIGNMENT_SIZE(_type, _prevField, _field) >= 0 && SHCROGL_CUT_FIELD_ALIGNMENT_SIZE(_type, _prevField, _field) < sizeof (void*));*/ \ + if (cbAlignment) { \ + rc = SSMR3Skip(pSSM, cbAlignment); \ + } \ + } 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_UOFFSETOF(_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_UOFFSETOF(_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); \ + /*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) + +static int32_t crStateLoadTextureObj_v_BEFORE_CTXUSAGE_BITS(CRTextureObj *pTexture, PSSMHANDLE pSSM) +{ + int32_t rc; + uint32_t cbObj = RT_UOFFSETOF(CRTextureObj, ctxUsage); + cbObj = ((cbObj + sizeof (void*) - 1) & ~(sizeof (void*) - 1)); + rc = SSMR3GetMem(pSSM, pTexture, cbObj); + AssertRCReturn(rc, rc); + /* just make all bits are used so that we fall back to the pre-ctxUsage behavior, + * i.e. all shared resources will be destructed on last shared context termination */ + FILLDIRTY(pTexture->ctxUsage); + return rc; +} + +static int32_t crStateLoadTextureUnit_v_BEFORE_CTXUSAGE_BITS(CRTextureUnit *t, PSSMHANDLE pSSM) +{ + int32_t rc; + SHCROGL_GET_STRUCT_HEAD(t, CRTextureUnit, Saved1D); + rc = crStateLoadTextureObj_v_BEFORE_CTXUSAGE_BITS(&t->Saved1D, pSSM); + AssertRCReturn(rc, rc); + SHCROGL_CUT_FIELD_ALIGNMENT(CRTextureUnit, Saved1D, Saved2D); + rc = crStateLoadTextureObj_v_BEFORE_CTXUSAGE_BITS(&t->Saved2D, pSSM); + AssertRCReturn(rc, rc); + SHCROGL_CUT_FIELD_ALIGNMENT(CRTextureUnit, Saved2D, Saved3D); + rc = crStateLoadTextureObj_v_BEFORE_CTXUSAGE_BITS(&t->Saved3D, pSSM); + AssertRCReturn(rc, rc); +#ifdef CR_ARB_texture_cube_map + SHCROGL_CUT_FIELD_ALIGNMENT(CRTextureUnit, Saved3D, SavedCubeMap); + rc = crStateLoadTextureObj_v_BEFORE_CTXUSAGE_BITS(&t->SavedCubeMap, pSSM); + AssertRCReturn(rc, rc); +# define SHCROGL_INTERNAL_LAST_FIELD SavedCubeMap +#else +# define SHCROGL_INTERNAL_LAST_FIELD Saved3D +#endif +#ifdef CR_NV_texture_rectangle + SHCROGL_CUT_FIELD_ALIGNMENT(CRTextureUnit, SHCROGL_INTERNAL_LAST_FIELD, SavedRect); + rc = crStateLoadTextureObj_v_BEFORE_CTXUSAGE_BITS(&t->SavedRect, pSSM); + AssertRCReturn(rc, rc); +# undef SHCROGL_INTERNAL_LAST_FIELD +# define SHCROGL_INTERNAL_LAST_FIELD SavedRect +#endif + SHCROGL_CUT_TAIL_ALIGNMENT(CRTextureUnit, SHCROGL_INTERNAL_LAST_FIELD); +#undef SHCROGL_INTERNAL_LAST_FIELD + 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; + int32_t rc = crStateLoadTextureObj_v_BEFORE_CTXUSAGE_BITS(&t->base1D, pSSM); + AssertRCReturn(rc, rc); + SHCROGL_CUT_FIELD_ALIGNMENT(CRTextureState, base1D, base2D); + rc = crStateLoadTextureObj_v_BEFORE_CTXUSAGE_BITS(&t->base2D, pSSM); + AssertRCReturn(rc, rc); + rc = crStateLoadTextureObj_v_BEFORE_CTXUSAGE_BITS(&t->base3D, pSSM); + SHCROGL_CUT_FIELD_ALIGNMENT(CRTextureState, base2D, base3D); + AssertRCReturn(rc, rc); +#ifdef CR_ARB_texture_cube_map + SHCROGL_CUT_FIELD_ALIGNMENT(CRTextureState, base3D, baseCubeMap); + rc = crStateLoadTextureObj_v_BEFORE_CTXUSAGE_BITS(&t->baseCubeMap, pSSM); + AssertRCReturn(rc, rc); +# define SHCROGL_INTERNAL_LAST_FIELD baseCubeMap +#else +# define SHCROGL_INTERNAL_LAST_FIELD base3D +#endif +#ifdef CR_NV_texture_rectangle + SHCROGL_CUT_FIELD_ALIGNMENT(CRTextureState, SHCROGL_INTERNAL_LAST_FIELD, baseRect); + rc = crStateLoadTextureObj_v_BEFORE_CTXUSAGE_BITS(&t->baseRect, pSSM); + AssertRCReturn(rc, rc); +# undef SHCROGL_INTERNAL_LAST_FIELD +# define SHCROGL_INTERNAL_LAST_FIELD baseRect +#endif + SHCROGL_CUT_FIELD_ALIGNMENT(CRTextureState, SHCROGL_INTERNAL_LAST_FIELD, proxy1D); + rc = crStateLoadTextureObj_v_BEFORE_CTXUSAGE_BITS(&t->proxy1D, pSSM); + AssertRCReturn(rc, rc); +#undef SHCROGL_INTERNAL_LAST_FIELD + SHCROGL_CUT_FIELD_ALIGNMENT(CRTextureState, proxy1D, proxy2D); + rc = crStateLoadTextureObj_v_BEFORE_CTXUSAGE_BITS(&t->proxy2D, pSSM); + AssertRCReturn(rc, rc); + SHCROGL_CUT_FIELD_ALIGNMENT(CRTextureState, proxy2D, proxy3D); + rc = crStateLoadTextureObj_v_BEFORE_CTXUSAGE_BITS(&t->proxy3D, pSSM); + AssertRCReturn(rc, rc); +#ifdef CR_ARB_texture_cube_map + SHCROGL_CUT_FIELD_ALIGNMENT(CRTextureState, proxy3D, proxyCubeMap); + rc = crStateLoadTextureObj_v_BEFORE_CTXUSAGE_BITS(&t->proxyCubeMap, pSSM); + AssertRCReturn(rc, rc); +# define SHCROGL_INTERNAL_LAST_FIELD proxyCubeMap +#else +# define SHCROGL_INTERNAL_LAST_FIELD proxy3D +#endif +#ifdef CR_NV_texture_rectangle + SHCROGL_CUT_FIELD_ALIGNMENT(CRTextureState, SHCROGL_INTERNAL_LAST_FIELD, proxyRect); + rc = crStateLoadTextureObj_v_BEFORE_CTXUSAGE_BITS(&t->proxyRect, pSSM); + AssertRCReturn(rc, rc); +# undef SHCROGL_INTERNAL_LAST_FIELD +# define SHCROGL_INTERNAL_LAST_FIELD proxyRect +#endif + SHCROGL_CUT_FIELD_ALIGNMENT(CRTextureState, SHCROGL_INTERNAL_LAST_FIELD, curTextureUnit); +# undef SHCROGL_INTERNAL_LAST_FIELD + SHCROGL_GET_STRUCT_PART(t, CRTextureState, curTextureUnit, unit); + + for (i = 0; i < CR_MAX_TEXTURE_UNITS; ++i) + { + rc = crStateLoadTextureUnit_v_BEFORE_CTXUSAGE_BITS(&t->unit[i], pSSM); + AssertRCReturn(rc, rc); + } + + 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)); + AssertLogRelReturn(rc, rc); + + 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; +} + +static int32_t crStateLoadTextureStack_v_BEFORE_CTXUSAGE_BITS(CRTextureStack *t, PSSMHANDLE pSSM) +{ + int32_t i, rc; + SHCROGL_GET_STRUCT_HEAD(t, CRTextureStack, unit); + for (i = 0; i < CR_MAX_TEXTURE_UNITS; ++i) + { + rc = crStateLoadTextureUnit_v_BEFORE_CTXUSAGE_BITS(&t->unit[i], pSSM); + AssertRCReturn(rc, rc); + } + SHCROGL_CUT_TAIL_ALIGNMENT(CRTextureStack, unit); + return rc; +} + +static int32_t crStateLoadAttribState_v_BEFORE_CTXUSAGE_BITS(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_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); + AssertRCReturn(rc, rc); + } + SHCROGL_GET_STRUCT_TAIL(t, CRAttribState, transformStackDepth); + return rc; +} + + +static int32_t crStateLoadTextureObj(CRTextureObj *pTexture, PSSMHANDLE pSSM, uint32_t u32Version) +{ + int32_t rc; + if (u32Version == SHCROGL_SSM_VERSION_BEFORE_CTXUSAGE_BITS) + return crStateLoadTextureObj_v_BEFORE_CTXUSAGE_BITS(pTexture, pSSM); + rc = SSMR3GetMem(pSSM, pTexture, sizeof (*pTexture)); + AssertRCReturn(rc, rc); + return rc; +} + +static int32_t crStateLoadBufferObject(CRBufferObject *pBufferObj, PSSMHANDLE pSSM, uint32_t u32Version) +{ + int32_t rc; + if (u32Version == SHCROGL_SSM_VERSION_BEFORE_CTXUSAGE_BITS) + { + uint32_t cbObj = RT_UOFFSETOF(CRBufferObject, ctxUsage); + cbObj = ((cbObj + sizeof (void*) - 1) & ~(sizeof (void*) - 1)); + rc = SSMR3GetMem(pSSM, pBufferObj, cbObj); + AssertRCReturn(rc, rc); + /* just make all bits are used so that we fall back to the pre-ctxUsage behavior, + * i.e. all shared resources will be destructed on last shared context termination */ + FILLDIRTY(pBufferObj->ctxUsage); + } + else + { + rc = SSMR3GetMem(pSSM, pBufferObj, sizeof(*pBufferObj)); + AssertRCReturn(rc, rc); + } + return rc; +} + +static int32_t crStateLoadFramebufferObject(CRFramebufferObject *pFBO, PSSMHANDLE pSSM, uint32_t u32Version) +{ + int32_t rc; + if (u32Version == SHCROGL_SSM_VERSION_BEFORE_CTXUSAGE_BITS) + { + uint32_t cbObj = RT_UOFFSETOF(CRFramebufferObject, ctxUsage); + cbObj = ((cbObj + sizeof (void*) - 1) & ~(sizeof (void*) - 1)); + rc = SSMR3GetMem(pSSM, pFBO, cbObj); + AssertRCReturn(rc, rc); + /* just make all bits are used so that we fall back to the pre-ctxUsage behavior, + * i.e. all shared resources will be destructed on last shared context termination */ + FILLDIRTY(pFBO->ctxUsage); + } + else + { + rc = SSMR3GetMem(pSSM, pFBO, sizeof(*pFBO)); + AssertRCReturn(rc, rc); + } + return rc; +} + +static int32_t crStateLoadRenderbufferObject(CRRenderbufferObject *pRBO, PSSMHANDLE pSSM, uint32_t u32Version) +{ + int32_t rc; + if (u32Version == SHCROGL_SSM_VERSION_BEFORE_CTXUSAGE_BITS) + { + uint32_t cbObj = RT_UOFFSETOF(CRRenderbufferObject, ctxUsage); + cbObj = ((cbObj + sizeof (void*) - 1) & ~(sizeof (void*) - 1)); + rc = SSMR3GetMem(pSSM, pRBO, cbObj); + AssertRCReturn(rc, rc); + /* just make all bits are used so that we fall back to the pre-ctxUsage behavior, + * i.e. all shared resources will be destructed on last shared context termination */ + FILLDIRTY(pRBO->ctxUsage); + } + else + { + rc = SSMR3GetMem(pSSM, pRBO, sizeof(*pRBO)); + AssertRCReturn(rc, rc); + } + return rc; +} + +static int32_t crStateSaveTextureObjData(CRTextureObj *pTexture, PSSMHANDLE pSSM) +{ + int32_t rc, face, i; + GLint bound = 0; + + CRASSERT(pTexture && pSSM); + + crDebug("crStateSaveTextureObjData %u. START", pTexture->id); + + for (face = 0; face < 6; face++) { + CRASSERT(pTexture->level[face]); + + for (i = 0; i < CR_MAX_MIPMAP_LEVELS; i++) { + CRTextureLevel *ptl = &(pTexture->level[face][i]); + rc = SSMR3PutMem(pSSM, ptl, sizeof(*ptl)); + AssertRCReturn(rc, rc); + if (ptl->img) + { + CRASSERT(ptl->bytes); + rc = SSMR3PutMem(pSSM, ptl->img, ptl->bytes); + AssertRCReturn(rc, rc); + } +#ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE + /* Note, this is not a bug. + * Even with CR_STATE_NO_TEXTURE_IMAGE_STORE defined, it's possible that ptl->img!=NULL. + * For ex. we're saving snapshot right after it was loaded + * and some context hasn't been used by the guest application yet + * (pContext->shared->bTexResyncNeeded==GL_TRUE). + */ + else if (ptl->bytes) + { + char *pImg; + GLenum target; + + if (!bound) + { + GLenum getEnum; + diff_api.BindTexture(pTexture->target, pTexture->hwid); + bound = 1; + + /* osx nvidia drivers seem to have a bug that 1x1 TEXTURE_2D texture becmes inaccessible for some reason + * saw that for 1x1 dummy textures generated by wine + * to avoid crashes we skip texture data save if that is the case */ + switch (pTexture->target) + { + case GL_TEXTURE_1D: + getEnum = GL_TEXTURE_BINDING_1D; + break; + case GL_TEXTURE_2D: + getEnum = GL_TEXTURE_BINDING_2D; + break; + case GL_TEXTURE_3D: + getEnum = GL_TEXTURE_BINDING_3D; + break; + case GL_TEXTURE_RECTANGLE_ARB: + getEnum = GL_TEXTURE_BINDING_RECTANGLE_ARB; + break; + case GL_TEXTURE_CUBE_MAP_ARB: + getEnum = GL_TEXTURE_BINDING_CUBE_MAP_ARB; + break; + default: + crWarning("unknown texture target: 0x%x", pTexture->target); + getEnum = 0; + break; + } + + if (getEnum) + { + GLint curTex; + diff_api.GetIntegerv(getEnum, &curTex); + if ((GLuint)curTex != pTexture->hwid) + { + crWarning("texture not bound properly: expected %d, but was %d. Texture state data: target(0x%x), id(%d), w(%d), h(%d)", + pTexture->hwid, curTex, + pTexture->target, + pTexture->id, + ptl->width, + ptl->height); + bound = -1; + } + } + + } + + if (pTexture->target!=GL_TEXTURE_CUBE_MAP_ARB) + { + target = pTexture->target; + } + else + { + target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + face; + } + +#ifdef DEBUG + pImg = crAlloc(ptl->bytes+4); +#else + pImg = crAlloc(ptl->bytes); +#endif + if (!pImg) return VERR_NO_MEMORY; + +#ifdef DEBUG + *(int*)((char*)pImg+ptl->bytes) = 0xDEADDEAD; +#endif + if (bound > 0) + { +#ifdef DEBUG + { + GLint w,h=0; + crDebug("get image: compressed %i, face %i, level %i, width %i, height %i, bytes %i", + ptl->compressed, face, i, ptl->width, ptl->height, ptl->bytes); + diff_api.GetTexLevelParameteriv(target, i, GL_TEXTURE_WIDTH, &w); + diff_api.GetTexLevelParameteriv(target, i, GL_TEXTURE_HEIGHT, &h); + if (w!=ptl->width || h!=ptl->height) + { + crWarning("!!!tex size mismatch %i, %i!!!", w, h); + } + } +#endif + + /** @todo ugly workaround for crashes inside ati driver, + * they overwrite their own allocated memory in cases where texlevel >=4 + and width or height <=2. + */ + if (i<4 || (ptl->width>2 && ptl->height>2)) + { + if (!ptl->compressed) + { + diff_api.GetTexImage(target, i, ptl->format, ptl->type, pImg); + } + else + { + diff_api.GetCompressedTexImageARB(target, i, pImg); + } + } + } + else + { + crMemset(pImg, 0, ptl->bytes); + } + +#ifdef DEBUG + if (*(int*)((char*)pImg+ptl->bytes) != 0xDEADDEAD) + { + crWarning("Texture is bigger than expected!!!"); + } +#endif + + rc = SSMR3PutMem(pSSM, pImg, ptl->bytes); + crFree(pImg); + AssertRCReturn(rc, rc); + } +#endif + } + } + + crDebug("crStateSaveTextureObjData %u. END", pTexture->id); + + return VINF_SUCCESS; +} + +static int32_t crStateLoadTextureObjData(CRTextureObj *pTexture, PSSMHANDLE pSSM) +{ + int32_t rc, face, i; + + CRASSERT(pTexture && pSSM); + + for (face = 0; face < 6; face++) { + CRASSERT(pTexture->level[face]); + + for (i = 0; i < CR_MAX_MIPMAP_LEVELS; i++) { + CRTextureLevel *ptl = &(pTexture->level[face][i]); + CRASSERT(!ptl->img); + + rc = SSMR3GetMem(pSSM, ptl, sizeof(*ptl)); + AssertRCReturn(rc, rc); + if (ptl->img) + { + CRASSERT(ptl->bytes); + + ptl->img = crAlloc(ptl->bytes); + if (!ptl->img) return VERR_NO_MEMORY; + + rc = SSMR3GetMem(pSSM, ptl->img, ptl->bytes); + AssertRCReturn(rc, rc); + } +#ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE + /* Same story as in crStateSaveTextureObjData */ + else if (ptl->bytes) + { + ptl->img = crAlloc(ptl->bytes); + if (!ptl->img) return VERR_NO_MEMORY; + + rc = SSMR3GetMem(pSSM, ptl->img, ptl->bytes); + AssertRCReturn(rc, rc); + } +#endif + crStateTextureInitTextureFormat(ptl, ptl->internalFormat); + } + } + + return VINF_SUCCESS; +} + +static void crStateSaveSharedTextureCB(unsigned long key, void *data1, void *data2) +{ + CRTextureObj *pTexture = (CRTextureObj *) data1; + PSSMHANDLE pSSM = (PSSMHANDLE) data2; + int32_t rc; + + CRASSERT(pTexture && pSSM); + + rc = SSMR3PutMem(pSSM, &key, sizeof(key)); + CRASSERT(rc == VINF_SUCCESS); + rc = SSMR3PutMem(pSSM, pTexture, sizeof(*pTexture)); + CRASSERT(rc == VINF_SUCCESS); + rc = crStateSaveTextureObjData(pTexture, pSSM); + CRASSERT(rc == VINF_SUCCESS); +} + +static int32_t crStateSaveMatrixStack(CRMatrixStack *pStack, PSSMHANDLE pSSM) +{ + return SSMR3PutMem(pSSM, pStack->stack, sizeof(CRmatrix) * pStack->maxDepth); +} + +static int32_t crStateLoadMatrixStack(CRMatrixStack *pStack, PSSMHANDLE pSSM) +{ + int32_t rc; + + CRASSERT(pStack && pSSM); + + rc = SSMR3GetMem(pSSM, pStack->stack, sizeof(CRmatrix) * pStack->maxDepth); + /* fixup stack top pointer */ + pStack->top = &pStack->stack[pStack->depth]; + return rc; +} + +static int32_t crStateSaveTextureObjPtr(CRTextureObj *pTexture, PSSMHANDLE pSSM) +{ + /* Current texture pointer can't be NULL for real texture unit states, + * but it could be NULL for unused attribute stack depths. + */ + if (pTexture) + return SSMR3PutU32(pSSM, pTexture->id); + else + return VINF_SUCCESS; +} + +static int32_t crStateLoadTextureObjPtr(CRTextureObj **pTexture, CRContext *pContext, GLenum target, PSSMHANDLE pSSM) +{ + uint32_t texName; + int32_t rc; + + /* We're loading attrib stack with unused state */ + if (!*pTexture) + return VINF_SUCCESS; + + rc = SSMR3GetU32(pSSM, &texName); + AssertRCReturn(rc, rc); + + if (texName) + { + *pTexture = (CRTextureObj *) crHashtableSearch(pContext->shared->textureTable, texName); + } + else + { + switch (target) + { + case GL_TEXTURE_1D: + *pTexture = &(pContext->texture.base1D); + break; + case GL_TEXTURE_2D: + *pTexture = &(pContext->texture.base2D); + break; +#ifdef CR_OPENGL_VERSION_1_2 + case GL_TEXTURE_3D: + *pTexture = &(pContext->texture.base3D); + break; +#endif +#ifdef CR_ARB_texture_cube_map + case GL_TEXTURE_CUBE_MAP_ARB: + *pTexture = &(pContext->texture.baseCubeMap); + break; +#endif +#ifdef CR_NV_texture_rectangle + case GL_TEXTURE_RECTANGLE_NV: + *pTexture = &(pContext->texture.baseRect); + break; +#endif + default: + crError("LoadTextureObjPtr: Unknown texture target %d", target); + } + } + + return rc; +} + +static int32_t crStateSaveTexUnitCurrentTexturePtrs(CRTextureUnit *pTexUnit, PSSMHANDLE pSSM) +{ + int32_t rc; + + rc = crStateSaveTextureObjPtr(pTexUnit->currentTexture1D, pSSM); + AssertRCReturn(rc, rc); + rc = crStateSaveTextureObjPtr(pTexUnit->currentTexture2D, pSSM); + AssertRCReturn(rc, rc); + rc = crStateSaveTextureObjPtr(pTexUnit->currentTexture3D, pSSM); + AssertRCReturn(rc, rc); +#ifdef CR_ARB_texture_cube_map + rc = crStateSaveTextureObjPtr(pTexUnit->currentTextureCubeMap, pSSM); + AssertRCReturn(rc, rc); +#endif +#ifdef CR_NV_texture_rectangle + rc = crStateSaveTextureObjPtr(pTexUnit->currentTextureRect, pSSM); + AssertRCReturn(rc, rc); +#endif + + return rc; +} + +static int32_t crStateLoadTexUnitCurrentTexturePtrs(CRTextureUnit *pTexUnit, CRContext *pContext, PSSMHANDLE pSSM) +{ + int32_t rc; + + rc = crStateLoadTextureObjPtr(&pTexUnit->currentTexture1D, pContext, GL_TEXTURE_1D, pSSM); + AssertRCReturn(rc, rc); + rc = crStateLoadTextureObjPtr(&pTexUnit->currentTexture2D, pContext, GL_TEXTURE_1D, pSSM); + AssertRCReturn(rc, rc); + rc = crStateLoadTextureObjPtr(&pTexUnit->currentTexture3D, pContext, GL_TEXTURE_2D, pSSM); + AssertRCReturn(rc, rc); +#ifdef CR_ARB_texture_cube_map + rc = crStateLoadTextureObjPtr(&pTexUnit->currentTextureCubeMap, pContext, GL_TEXTURE_CUBE_MAP_ARB, pSSM); + AssertRCReturn(rc, rc); +#endif +#ifdef CR_NV_texture_rectangle + rc = crStateLoadTextureObjPtr(&pTexUnit->currentTextureRect, pContext, GL_TEXTURE_RECTANGLE_NV, pSSM); + AssertRCReturn(rc, rc); +#endif + + return rc; +} + +static int32_t crSateSaveEvalCoeffs1D(CREvaluator1D *pEval, PSSMHANDLE pSSM) +{ + int32_t rc, i; + + for (i=0; i<GLEVAL_TOT; ++i) + { + if (pEval[i].coeff) + { + rc = SSMR3PutMem(pSSM, pEval[i].coeff, pEval[i].order * gleval_sizes[i] * sizeof(GLfloat)); + AssertRCReturn(rc, rc); + } + } + + return VINF_SUCCESS; +} + +static int32_t crSateSaveEvalCoeffs2D(CREvaluator2D *pEval, PSSMHANDLE pSSM) +{ + int32_t rc, i; + + for (i=0; i<GLEVAL_TOT; ++i) + { + if (pEval[i].coeff) + { + rc = SSMR3PutMem(pSSM, pEval[i].coeff, pEval[i].uorder * pEval[i].vorder * gleval_sizes[i] * sizeof(GLfloat)); + AssertRCReturn(rc, rc); + } + } + + return VINF_SUCCESS; +} + +static int32_t crSateLoadEvalCoeffs1D(CREvaluator1D *pEval, GLboolean bReallocMem, PSSMHANDLE pSSM) +{ + int32_t rc, i; + size_t size; + + for (i=0; i<GLEVAL_TOT; ++i) + { + if (pEval[i].coeff) + { + size = pEval[i].order * gleval_sizes[i] * sizeof(GLfloat); + if (bReallocMem) + { + pEval[i].coeff = (GLfloat*) crAlloc((unsigned int /* this case is just so stupid */)size); + if (!pEval[i].coeff) return VERR_NO_MEMORY; + } + rc = SSMR3GetMem(pSSM, pEval[i].coeff, size); + AssertRCReturn(rc, rc); + } + } + + return VINF_SUCCESS; +} + +static int32_t crSateLoadEvalCoeffs2D(CREvaluator2D *pEval, GLboolean bReallocMem, PSSMHANDLE pSSM) +{ + int32_t rc, i; + size_t size; + + for (i=0; i<GLEVAL_TOT; ++i) + { + if (pEval[i].coeff) + { + size = pEval[i].uorder * pEval[i].vorder * gleval_sizes[i] * sizeof(GLfloat); + if (bReallocMem) + { + pEval[i].coeff = (GLfloat*) crAlloc((unsigned int /* this case is just so stupid */)size); + if (!pEval[i].coeff) return VERR_NO_MEMORY; + } + rc = SSMR3GetMem(pSSM, pEval[i].coeff, size); + AssertRCReturn(rc, rc); + } + } + + return VINF_SUCCESS; +} + +static void crStateCopyEvalPtrs1D(CREvaluator1D *pDst, CREvaluator1D *pSrc) +{ + int32_t i; + + for (i=0; i<GLEVAL_TOT; ++i) + pDst[i].coeff = pSrc[i].coeff; + + /* + pDst[GL_MAP1_VERTEX_3-GL_MAP1_COLOR_4].coeff = pSrc[GL_MAP1_VERTEX_3-GL_MAP1_COLOR_4].coeff; + pDst[GL_MAP1_VERTEX_4-GL_MAP1_COLOR_4].coeff = pSrc[GL_MAP1_VERTEX_4-GL_MAP1_COLOR_4].coeff; + pDst[GL_MAP1_INDEX-GL_MAP1_COLOR_4].coeff = pSrc[GL_MAP1_INDEX-GL_MAP1_COLOR_4].coeff; + pDst[GL_MAP1_COLOR_4-GL_MAP1_COLOR_4].coeff = pSrc[GL_MAP1_COLOR_4-GL_MAP1_COLOR_4].coeff; + pDst[GL_MAP1_NORMAL-GL_MAP1_COLOR_4].coeff = pSrc[GL_MAP1_NORMAL-GL_MAP1_COLOR_4].coeff; + pDst[GL_MAP1_TEXTURE_COORD_1-GL_MAP1_COLOR_4].coeff = pSrc[GL_MAP1_TEXTURE_COORD_1-GL_MAP1_COLOR_4].coeff; + pDst[GL_MAP1_TEXTURE_COORD_2-GL_MAP1_COLOR_4].coeff = pSrc[GL_MAP1_TEXTURE_COORD_2-GL_MAP1_COLOR_4].coeff; + pDst[GL_MAP1_TEXTURE_COORD_3-GL_MAP1_COLOR_4].coeff = pSrc[GL_MAP1_TEXTURE_COORD_3-GL_MAP1_COLOR_4].coeff; + pDst[GL_MAP1_TEXTURE_COORD_4-GL_MAP1_COLOR_4].coeff = pSrc[GL_MAP1_TEXTURE_COORD_4-GL_MAP1_COLOR_4].coeff; + */ +} + +static void crStateCopyEvalPtrs2D(CREvaluator2D *pDst, CREvaluator2D *pSrc) +{ + int32_t i; + + for (i=0; i<GLEVAL_TOT; ++i) + pDst[i].coeff = pSrc[i].coeff; + + /* + pDst[GL_MAP2_VERTEX_3-GL_MAP2_COLOR_4].coeff = pSrc[GL_MAP2_VERTEX_3-GL_MAP2_COLOR_4].coeff; + pDst[GL_MAP2_VERTEX_4-GL_MAP2_COLOR_4].coeff = pSrc[GL_MAP2_VERTEX_4-GL_MAP2_COLOR_4].coeff; + pDst[GL_MAP2_INDEX-GL_MAP2_COLOR_4].coeff = pSrc[GL_MAP2_INDEX-GL_MAP2_COLOR_4].coeff; + pDst[GL_MAP2_COLOR_4-GL_MAP2_COLOR_4].coeff = pSrc[GL_MAP2_COLOR_4-GL_MAP2_COLOR_4].coeff; + pDst[GL_MAP2_NORMAL-GL_MAP2_COLOR_4].coeff = pSrc[GL_MAP2_NORMAL-GL_MAP2_COLOR_4].coeff; + pDst[GL_MAP2_TEXTURE_COORD_1-GL_MAP2_COLOR_4].coeff = pSrc[GL_MAP2_TEXTURE_COORD_1-GL_MAP2_COLOR_4].coeff; + pDst[GL_MAP2_TEXTURE_COORD_2-GL_MAP2_COLOR_4].coeff = pSrc[GL_MAP2_TEXTURE_COORD_2-GL_MAP2_COLOR_4].coeff; + pDst[GL_MAP2_TEXTURE_COORD_3-GL_MAP2_COLOR_4].coeff = pSrc[GL_MAP2_TEXTURE_COORD_3-GL_MAP2_COLOR_4].coeff; + pDst[GL_MAP2_TEXTURE_COORD_4-GL_MAP2_COLOR_4].coeff = pSrc[GL_MAP2_TEXTURE_COORD_4-GL_MAP2_COLOR_4].coeff; + */ +} + +static void crStateSaveBufferObjectCB(unsigned long key, void *data1, void *data2) +{ + CRBufferObject *pBufferObj = (CRBufferObject *) data1; + PSSMHANDLE pSSM = (PSSMHANDLE) data2; + int32_t rc; + + CRASSERT(pBufferObj && pSSM); + + rc = SSMR3PutMem(pSSM, &key, sizeof(key)); + CRASSERT(rc == VINF_SUCCESS); + rc = SSMR3PutMem(pSSM, pBufferObj, sizeof(*pBufferObj)); + CRASSERT(rc == VINF_SUCCESS); + + if (pBufferObj->data) + { + /*We could get here even though retainBufferData is false on host side, in case when we're taking snapshot + after state load and before this context was ever made current*/ + CRASSERT(pBufferObj->size>0); + rc = SSMR3PutMem(pSSM, pBufferObj->data, pBufferObj->size); + CRASSERT(rc == VINF_SUCCESS); + } + else if (pBufferObj->id!=0 && pBufferObj->size>0) + { + diff_api.BindBufferARB(GL_ARRAY_BUFFER_ARB, pBufferObj->hwid); + pBufferObj->pointer = diff_api.MapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB); + rc = SSMR3PutMem(pSSM, &pBufferObj->pointer, sizeof(pBufferObj->pointer)); + CRASSERT(rc == VINF_SUCCESS); + if (pBufferObj->pointer) + { + rc = SSMR3PutMem(pSSM, pBufferObj->pointer, pBufferObj->size); + CRASSERT(rc == VINF_SUCCESS); + } + diff_api.UnmapBufferARB(GL_ARRAY_BUFFER_ARB); + pBufferObj->pointer = NULL; + } +} + +static void crStateSaveProgramCB(unsigned long key, void *data1, void *data2) +{ + CRProgram *pProgram = (CRProgram *) data1; + PSSMHANDLE pSSM = (PSSMHANDLE) data2; + CRProgramSymbol *pSymbol; + int32_t rc; + + CRASSERT(pProgram && pSSM); + + rc = SSMR3PutMem(pSSM, &key, sizeof(key)); + CRASSERT(rc == VINF_SUCCESS); + rc = SSMR3PutMem(pSSM, pProgram, sizeof(*pProgram)); + CRASSERT(rc == VINF_SUCCESS); + if (pProgram->string) + { + CRASSERT(pProgram->length); + rc = SSMR3PutMem(pSSM, pProgram->string, pProgram->length); + CRASSERT(rc == VINF_SUCCESS); + } + + for (pSymbol = pProgram->symbolTable; pSymbol; pSymbol=pSymbol->next) + { + rc = SSMR3PutMem(pSSM, pSymbol, sizeof(*pSymbol)); + CRASSERT(rc == VINF_SUCCESS); + if (pSymbol->name) + { + CRASSERT(pSymbol->cbName>0); + rc = SSMR3PutMem(pSSM, pSymbol->name, pSymbol->cbName); + CRASSERT(rc == VINF_SUCCESS); + } + } +} + +static void crStateSaveFramebuffersCB(unsigned long key, void *data1, void *data2) +{ + CRFramebufferObject *pFBO = (CRFramebufferObject*) data1; + PSSMHANDLE pSSM = (PSSMHANDLE) data2; + int32_t rc; + + rc = SSMR3PutMem(pSSM, &key, sizeof(key)); + CRASSERT(rc == VINF_SUCCESS); + + rc = SSMR3PutMem(pSSM, pFBO, sizeof(*pFBO)); + CRASSERT(rc == VINF_SUCCESS); +} + +static void crStateSaveRenderbuffersCB(unsigned long key, void *data1, void *data2) +{ + CRRenderbufferObject *pRBO = (CRRenderbufferObject*) data1; + PSSMHANDLE pSSM = (PSSMHANDLE) data2; + int32_t rc; + + rc = SSMR3PutMem(pSSM, &key, sizeof(key)); + CRASSERT(rc == VINF_SUCCESS); + + rc = SSMR3PutMem(pSSM, pRBO, sizeof(*pRBO)); + CRASSERT(rc == VINF_SUCCESS); +} + +static int32_t crStateLoadProgram(CRProgram **ppProgram, PSSMHANDLE pSSM) +{ + CRProgramSymbol **ppSymbol; + int32_t rc; + unsigned long key; + + rc = SSMR3GetMem(pSSM, &key, sizeof(key)); + AssertRCReturn(rc, rc); + + /* we're loading default vertex or pixel program*/ + if (*ppProgram) + { + if (key!=0) return VERR_SSM_UNEXPECTED_DATA; + } + else + { + *ppProgram = (CRProgram*) crAlloc(sizeof(CRProgram)); + if (!ppProgram) return VERR_NO_MEMORY; + if (key==0) return VERR_SSM_UNEXPECTED_DATA; + } + + rc = SSMR3GetMem(pSSM, *ppProgram, sizeof(**ppProgram)); + AssertRCReturn(rc, rc); + + if ((*ppProgram)->string) + { + CRASSERT((*ppProgram)->length); + (*ppProgram)->string = crAlloc((*ppProgram)->length); + if (!(*ppProgram)->string) return VERR_NO_MEMORY; + rc = SSMR3GetMem(pSSM, (void*) (*ppProgram)->string, (*ppProgram)->length); + AssertRCReturn(rc, rc); + } + + for (ppSymbol = &(*ppProgram)->symbolTable; *ppSymbol; ppSymbol=&(*ppSymbol)->next) + { + *ppSymbol = crAlloc(sizeof(CRProgramSymbol)); + if (!ppSymbol) return VERR_NO_MEMORY; + + rc = SSMR3GetMem(pSSM, *ppSymbol, sizeof(**ppSymbol)); + AssertRCReturn(rc, rc); + + if ((*ppSymbol)->name) + { + CRASSERT((*ppSymbol)->cbName>0); + (*ppSymbol)->name = crAlloc((*ppSymbol)->cbName); + if (!(*ppSymbol)->name) return VERR_NO_MEMORY; + + rc = SSMR3GetMem(pSSM, (void*) (*ppSymbol)->name, (*ppSymbol)->cbName); + AssertRCReturn(rc, rc); + } + } + + return VINF_SUCCESS; +} + +static void crStateSaveString(const char *pStr, PSSMHANDLE pSSM) +{ + int32_t len; + int32_t rc; + + if (pStr) + { + len = crStrlen(pStr)+1; + + rc = SSMR3PutS32(pSSM, len); + CRASSERT(rc == VINF_SUCCESS); + + rc = SSMR3PutMem(pSSM, pStr, len*sizeof(*pStr)); + CRASSERT(rc == VINF_SUCCESS); + } + else + { + rc = SSMR3PutS32(pSSM, 0); + CRASSERT(rc == VINF_SUCCESS); + } +} + +static char* crStateLoadString(PSSMHANDLE pSSM) +{ + int32_t len, rc; + char* pStr = NULL; + + rc = SSMR3GetS32(pSSM, &len); + CRASSERT(rc == VINF_SUCCESS); + + if (len!=0) + { + pStr = crAlloc(len*sizeof(*pStr)); + + rc = SSMR3GetMem(pSSM, pStr, len*sizeof(*pStr)); + CRASSERT(rc == VINF_SUCCESS); + } + + return pStr; +} + +static void crStateSaveGLSLShaderCB(unsigned long key, void *data1, void *data2) +{ + CRGLSLShader *pShader = (CRGLSLShader*) data1; + PSSMHANDLE pSSM = (PSSMHANDLE) data2; + int32_t rc; + + rc = SSMR3PutMem(pSSM, &key, sizeof(key)); + CRASSERT(rc == VINF_SUCCESS); + + rc = SSMR3PutMem(pSSM, pShader, sizeof(*pShader)); + CRASSERT(rc == VINF_SUCCESS); + + if (pShader->source) + { + crStateSaveString(pShader->source, pSSM); + } + else + { + GLint sLen=0; + GLchar *source=NULL; + + diff_api.GetShaderiv(pShader->hwid, GL_SHADER_SOURCE_LENGTH, &sLen); + if (sLen>0) + { + source = (GLchar*) crAlloc(sLen); + diff_api.GetShaderSource(pShader->hwid, sLen, NULL, source); + } + + crStateSaveString(source, pSSM); + if (source) crFree(source); + } +} + +static CRGLSLShader* crStateLoadGLSLShader(PSSMHANDLE pSSM) +{ + CRGLSLShader *pShader; + int32_t rc; + unsigned long key; + + pShader = crAlloc(sizeof(*pShader)); + if (!pShader) return NULL; + + rc = SSMR3GetMem(pSSM, &key, sizeof(key)); + CRASSERT(rc == VINF_SUCCESS); + + rc = SSMR3GetMem(pSSM, pShader, sizeof(*pShader)); + CRASSERT(rc == VINF_SUCCESS); + + pShader->source = crStateLoadString(pSSM); + + return pShader; +} + + +static void crStateSaveGLSLShaderKeyCB(unsigned long key, void *data1, void *data2) +{ + //CRGLSLShader *pShader = (CRGLSLShader*) data1; + PSSMHANDLE pSSM = (PSSMHANDLE) data2; + int32_t rc; + + rc = SSMR3PutMem(pSSM, &key, sizeof(key)); + CRASSERT(rc == VINF_SUCCESS); +} + +static void crStateSaveGLSLProgramAttribs(CRGLSLProgramState *pState, PSSMHANDLE pSSM) +{ + GLuint i; + int32_t rc; + + for (i=0; i<pState->cAttribs; ++i) + { + rc = SSMR3PutMem(pSSM, &pState->pAttribs[i].index, sizeof(pState->pAttribs[i].index)); + CRASSERT(rc == VINF_SUCCESS); + crStateSaveString(pState->pAttribs[i].name, pSSM); + } +} + +static void crStateSaveGLSLProgramCB(unsigned long key, void *data1, void *data2) +{ + CRGLSLProgram *pProgram = (CRGLSLProgram*) data1; + PSSMHANDLE pSSM = (PSSMHANDLE) data2; + int32_t rc; + uint32_t ui32; + GLint maxUniformLen, activeUniforms=0, uniformsCount=0, i, j; + GLchar *name = NULL; + GLenum type; + GLint size, location; + + rc = SSMR3PutMem(pSSM, &key, sizeof(key)); + CRASSERT(rc == VINF_SUCCESS); + + rc = SSMR3PutMem(pSSM, pProgram, sizeof(*pProgram)); + CRASSERT(rc == VINF_SUCCESS); + + ui32 = crHashtableNumElements(pProgram->currentState.attachedShaders); + rc = SSMR3PutU32(pSSM, ui32); + CRASSERT(rc == VINF_SUCCESS); + + crHashtableWalk(pProgram->currentState.attachedShaders, crStateSaveGLSLShaderKeyCB, pSSM); + + if (pProgram->activeState.attachedShaders) + { + ui32 = crHashtableNumElements(pProgram->activeState.attachedShaders); + rc = SSMR3PutU32(pSSM, ui32); + CRASSERT(rc == VINF_SUCCESS); + crHashtableWalk(pProgram->currentState.attachedShaders, crStateSaveGLSLShaderCB, pSSM); + } + + crStateSaveGLSLProgramAttribs(&pProgram->currentState, pSSM); + crStateSaveGLSLProgramAttribs(&pProgram->activeState, pSSM); + + 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)); + + if (!name) + { + crWarning("crStateSaveGLSLProgramCB: out of memory"); + return; + } + } + + for (i=0; i<activeUniforms; ++i) + { + diff_api.GetActiveUniform(pProgram->hwid, i, maxUniformLen, NULL, &size, &type, name); + uniformsCount += size; + } + CRASSERT(uniformsCount>=activeUniforms); + + rc = SSMR3PutS32(pSSM, uniformsCount); + CRASSERT(rc == VINF_SUCCESS); + + if (activeUniforms>0) + { + GLfloat fdata[16]; + GLint idata[16]; + char *pIndexStr=NULL; + + for (i=0; i<activeUniforms; ++i) + { + diff_api.GetActiveUniform(pProgram->hwid, i, maxUniformLen, NULL, &size, &type, name); + + if (size>1) + { + pIndexStr = crStrchr(name, '['); + if (!pIndexStr) + { + pIndexStr = name+crStrlen(name); + } + } + + for (j=0; j<size; ++j) + { + if (size>1) + { + sprintf(pIndexStr, "[%i]", j); + } + location = diff_api.GetUniformLocation(pProgram->hwid, name); + + rc = SSMR3PutMem(pSSM, &type, sizeof(type)); + CRASSERT(rc == VINF_SUCCESS); + + crStateSaveString(name, pSSM); + + if (crStateIsIntUniform(type)) + { + diff_api.GetUniformiv(pProgram->hwid, location, &idata[0]); + rc = SSMR3PutMem(pSSM, &idata[0], crStateGetUniformSize(type)*sizeof(idata[0])); + CRASSERT(rc == VINF_SUCCESS); + } + else + { + diff_api.GetUniformfv(pProgram->hwid, location, &fdata[0]); + rc = SSMR3PutMem(pSSM, &fdata[0], crStateGetUniformSize(type)*sizeof(fdata[0])); + CRASSERT(rc == VINF_SUCCESS); + } + } + } + + crFree(name); + } +} + +static int32_t crStateSaveClientPointer(CRVertexArrays *pArrays, int32_t index, PSSMHANDLE pSSM) +{ + int32_t rc; + CRClientPointer *cp; + + cp = crStateGetClientPointerByIndex(index, pArrays); + + if (cp->buffer) + rc = SSMR3PutU32(pSSM, cp->buffer->id); + else + rc = SSMR3PutU32(pSSM, 0); + + AssertRCReturn(rc, rc); + +#ifdef CR_EXT_compiled_vertex_array + if (cp->locked) + { + CRASSERT(cp->p); + rc = SSMR3PutMem(pSSM, cp->p, cp->stride*(pArrays->lockFirst+pArrays->lockCount)); + AssertRCReturn(rc, rc); + } +#endif + + return VINF_SUCCESS; +} + +static int32_t crStateLoadClientPointer(CRVertexArrays *pArrays, int32_t index, CRContext *pContext, PSSMHANDLE pSSM) +{ + int32_t rc; + uint32_t ui; + CRClientPointer *cp; + + cp = crStateGetClientPointerByIndex(index, pArrays); + + rc = SSMR3GetU32(pSSM, &ui); + AssertRCReturn(rc, rc); + cp->buffer = ui==0 ? pContext->bufferobject.nullBuffer : crHashtableSearch(pContext->shared->buffersTable, ui); + + if (!cp->buffer) + { + crWarning("crStateLoadClientPointer: ui=%d loaded as NULL buffer!", ui); + } + +#ifdef CR_EXT_compiled_vertex_array + if (cp->locked) + { + rc = crStateAllocAndSSMR3GetMem(pSSM, (void**)&cp->p, cp->stride*(pArrays->lockFirst+pArrays->lockCount)); + AssertRCReturn(rc, rc); + } +#endif + + return VINF_SUCCESS; +} + +static int32_t crStateSaveCurrentBits(CRStateBits *pBits, PSSMHANDLE pSSM) +{ + int32_t rc, i; + + rc = SSMR3PutMem(pSSM, pBits, sizeof(*pBits)); + AssertRCReturn(rc, rc); + + rc = SSMR3PutMem(pSSM, pBits->client.v, GLCLIENT_BIT_ALLOC*sizeof(CRbitvalue)); + AssertRCReturn(rc, rc); + rc = SSMR3PutMem(pSSM, pBits->client.n, GLCLIENT_BIT_ALLOC*sizeof(CRbitvalue)); + AssertRCReturn(rc, rc); + rc = SSMR3PutMem(pSSM, pBits->client.c, GLCLIENT_BIT_ALLOC*sizeof(CRbitvalue)); + AssertRCReturn(rc, rc); + rc = SSMR3PutMem(pSSM, pBits->client.s, GLCLIENT_BIT_ALLOC*sizeof(CRbitvalue)); + AssertRCReturn(rc, rc); + rc = SSMR3PutMem(pSSM, pBits->client.i, GLCLIENT_BIT_ALLOC*sizeof(CRbitvalue)); + AssertRCReturn(rc, rc); + for (i=0; i<CR_MAX_TEXTURE_UNITS; i++) + { + rc = SSMR3PutMem(pSSM, pBits->client.t[i], GLCLIENT_BIT_ALLOC*sizeof(CRbitvalue)); + AssertRCReturn(rc, rc); + } + rc = SSMR3PutMem(pSSM, pBits->client.e, GLCLIENT_BIT_ALLOC*sizeof(CRbitvalue)); + AssertRCReturn(rc, rc); + rc = SSMR3PutMem(pSSM, pBits->client.f, GLCLIENT_BIT_ALLOC*sizeof(CRbitvalue)); + AssertRCReturn(rc, rc); +#ifdef CR_NV_vertex_program + for (i=0; i<CR_MAX_VERTEX_ATTRIBS; i++) + { + rc = SSMR3PutMem(pSSM, pBits->client.a[i], GLCLIENT_BIT_ALLOC*sizeof(CRbitvalue)); + AssertRCReturn(rc, rc); + } +#endif + + rc = SSMR3PutMem(pSSM, pBits->lighting.light, CR_MAX_LIGHTS*sizeof(pBits->lighting.light)); + AssertRCReturn(rc, rc); + + return VINF_SUCCESS; +} + +static int32_t crStateLoadCurrentBits(CRStateBits *pBits, PSSMHANDLE pSSM) +{ + int32_t rc, i; + CRClientBits client; + CRLightingBits lighting; + + CRASSERT(pBits); + + client.v = pBits->client.v; + client.n = pBits->client.n; + client.c = pBits->client.c; + client.s = pBits->client.s; + client.i = pBits->client.i; + client.e = pBits->client.e; + client.f = pBits->client.f; + for (i=0; i<CR_MAX_TEXTURE_UNITS; i++) + { + client.t[i] = pBits->client.t[i]; + } +#ifdef CR_NV_vertex_program + for (i=0; i<CR_MAX_VERTEX_ATTRIBS; i++) + { + client.a[i] = pBits->client.a[i]; + } +#endif + lighting.light = pBits->lighting.light; + + rc = SSMR3GetMem(pSSM, pBits, sizeof(*pBits)); + AssertRCReturn(rc, rc); + + pBits->client.v = client.v; + rc = SSMR3GetMem(pSSM, pBits->client.v, GLCLIENT_BIT_ALLOC*sizeof(CRbitvalue)); + AssertRCReturn(rc, rc); + pBits->client.n = client.n; + rc = SSMR3GetMem(pSSM, pBits->client.n, GLCLIENT_BIT_ALLOC*sizeof(CRbitvalue)); + AssertRCReturn(rc, rc); + pBits->client.c = client.c; + rc = SSMR3GetMem(pSSM, pBits->client.c, GLCLIENT_BIT_ALLOC*sizeof(CRbitvalue)); + AssertRCReturn(rc, rc); + pBits->client.s = client.s; + rc = SSMR3GetMem(pSSM, pBits->client.s, GLCLIENT_BIT_ALLOC*sizeof(CRbitvalue)); + AssertRCReturn(rc, rc); + pBits->client.i = client.i; + rc = SSMR3GetMem(pSSM, pBits->client.i, GLCLIENT_BIT_ALLOC*sizeof(CRbitvalue)); + AssertRCReturn(rc, rc); + pBits->client.e = client.e; + rc = SSMR3GetMem(pSSM, pBits->client.e, GLCLIENT_BIT_ALLOC*sizeof(CRbitvalue)); + AssertRCReturn(rc, rc); + pBits->client.f = client.f; + rc = SSMR3GetMem(pSSM, pBits->client.f, GLCLIENT_BIT_ALLOC*sizeof(CRbitvalue)); + AssertRCReturn(rc, rc); + for (i=0; i<CR_MAX_TEXTURE_UNITS; i++) + { + pBits->client.t[i] = client.t[i]; + rc = SSMR3GetMem(pSSM, pBits->client.t[i], GLCLIENT_BIT_ALLOC*sizeof(CRbitvalue)); + AssertRCReturn(rc, rc); + } +#ifdef CR_NV_vertex_program + for (i=0; i<CR_MAX_VERTEX_ATTRIBS; i++) + { + pBits->client.a[i] = client.a[i]; + rc = SSMR3GetMem(pSSM, pBits->client.a[i], GLCLIENT_BIT_ALLOC*sizeof(CRbitvalue)); + AssertRCReturn(rc, rc); + } +#endif + + pBits->lighting.light = lighting.light; + rc = SSMR3GetMem(pSSM, pBits->lighting.light, CR_MAX_LIGHTS*sizeof(pBits->lighting.light)); + AssertRCReturn(rc, rc); + + 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); NOREF(fIsNew); +#if 0 //def DEBUG_misha + CRASSERT(fIsNew); +#endif + } + } + } + /* not reached*/ +} + + +int32_t crStateSaveContext(CRContext *pContext, PSSMHANDLE pSSM) +{ + int32_t rc, i; + uint32_t ui32, j; + GLboolean bSaveShared = GL_TRUE; + + CRASSERT(pContext && pSSM); + + CRASSERT(pContext->client.attribStackDepth == 0); + + /* this stuff is not used anymore, zero it up for sanity */ + pContext->buffer.storedWidth = 0; + pContext->buffer.storedHeight = 0; + + CRASSERT(VBoxTlsRefIsFunctional(pContext)); + + /* 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, sizeof (*pContext)); + AssertRCReturn(rc, rc); + + if (crHashtableNumElements(pContext->shared->dlistTable)>0) + crWarning("Saving state with %d display lists, unsupported", crHashtableNumElements(pContext->shared->dlistTable)); + + if (crHashtableNumElements(pContext->program.programHash)>0) + crDebug("Saving state with %d programs", crHashtableNumElements(pContext->program.programHash)); + + rc = SSMR3PutS32(pSSM, pContext->shared->id); + AssertRCReturn(rc, rc); + + rc = SSMR3PutS32(pSSM, crStateContextIsShared(pContext)); + AssertRCReturn(rc, rc); + + if (pContext->shared->refCount>1) + { + bSaveShared = pContext->shared->saveCount==0; + + ++pContext->shared->saveCount; + if (pContext->shared->saveCount == pContext->shared->refCount) + { + pContext->shared->saveCount=0; + } + } + + /* Save transform state */ + rc = SSMR3PutMem(pSSM, pContext->transform.clipPlane, sizeof(GLvectord)*CR_MAX_CLIP_PLANES); + AssertRCReturn(rc, rc); + rc = SSMR3PutMem(pSSM, pContext->transform.clip, sizeof(GLboolean)*CR_MAX_CLIP_PLANES); + AssertRCReturn(rc, rc); + rc = crStateSaveMatrixStack(&pContext->transform.modelViewStack, pSSM); + AssertRCReturn(rc, rc); + rc = crStateSaveMatrixStack(&pContext->transform.projectionStack, pSSM); + AssertRCReturn(rc, rc); + rc = crStateSaveMatrixStack(&pContext->transform.colorStack, pSSM); + AssertRCReturn(rc, rc); + for (i = 0 ; i < CR_MAX_TEXTURE_UNITS ; i++) + { + rc = crStateSaveMatrixStack(&pContext->transform.textureStack[i], pSSM); + AssertRCReturn(rc, rc); + } + for (i = 0 ; i < CR_MAX_PROGRAM_MATRICES ; i++) + { + rc = crStateSaveMatrixStack(&pContext->transform.programStack[i], pSSM); + AssertRCReturn(rc, rc); + } + + /* Save textures */ + rc = crStateSaveTextureObjData(&pContext->texture.base1D, pSSM); + AssertRCReturn(rc, rc); + rc = crStateSaveTextureObjData(&pContext->texture.base2D, pSSM); + AssertRCReturn(rc, rc); + rc = crStateSaveTextureObjData(&pContext->texture.base3D, pSSM); + AssertRCReturn(rc, rc); + rc = crStateSaveTextureObjData(&pContext->texture.proxy1D, pSSM); + AssertRCReturn(rc, rc); + rc = crStateSaveTextureObjData(&pContext->texture.proxy2D, pSSM); + AssertRCReturn(rc, rc); + rc = crStateSaveTextureObjData(&pContext->texture.proxy3D, pSSM); +#ifdef CR_ARB_texture_cube_map + rc = crStateSaveTextureObjData(&pContext->texture.baseCubeMap, pSSM); + AssertRCReturn(rc, rc); + rc = crStateSaveTextureObjData(&pContext->texture.proxyCubeMap, pSSM); + AssertRCReturn(rc, rc); +#endif +#ifdef CR_NV_texture_rectangle + rc = crStateSaveTextureObjData(&pContext->texture.baseRect, pSSM); + AssertRCReturn(rc, rc); + rc = crStateSaveTextureObjData(&pContext->texture.proxyRect, pSSM); + AssertRCReturn(rc, rc); +#endif + + /* Save shared textures */ + 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); + crHashtableWalk(pContext->shared->textureTable, crStateSaveSharedTextureCB, pSSM); + +#ifdef CR_STATE_NO_TEXTURE_IMAGE_STORE + /* Restore previous texture bindings via diff_api */ + if (ui32) + { + CRTextureUnit *pTexUnit; + + pTexUnit = &pContext->texture.unit[pContext->texture.curTextureUnit]; + + diff_api.BindTexture(GL_TEXTURE_1D, pTexUnit->currentTexture1D->hwid); + diff_api.BindTexture(GL_TEXTURE_2D, pTexUnit->currentTexture2D->hwid); + diff_api.BindTexture(GL_TEXTURE_3D, pTexUnit->currentTexture3D->hwid); +#ifdef CR_ARB_texture_cube_map + diff_api.BindTexture(GL_TEXTURE_CUBE_MAP_ARB, pTexUnit->currentTextureCubeMap->hwid); +#endif +#ifdef CR_NV_texture_rectangle + diff_api.BindTexture(GL_TEXTURE_RECTANGLE_NV, pTexUnit->currentTextureRect->hwid); +#endif + } +#endif + } + + /* Save current texture pointers */ + for (i=0; i<CR_MAX_TEXTURE_UNITS; ++i) + { + rc = crStateSaveTexUnitCurrentTexturePtrs(&pContext->texture.unit[i], pSSM); + AssertRCReturn(rc, rc); + } + + /* Save lights */ + CRASSERT(pContext->lighting.light); + rc = SSMR3PutMem(pSSM, pContext->lighting.light, CR_MAX_LIGHTS * sizeof(*pContext->lighting.light)); + AssertRCReturn(rc, rc); + + /* Save attrib stack*/ + /** @todo could go up to used stack depth here?*/ + for ( i = 0 ; i < CR_MAX_ATTRIB_STACK_DEPTH ; i++) + { + if (pContext->attrib.enableStack[i].clip) + { + rc = SSMR3PutMem(pSSM, pContext->attrib.enableStack[i].clip, + pContext->limits.maxClipPlanes*sizeof(GLboolean)); + AssertRCReturn(rc, rc); + } + + if (pContext->attrib.enableStack[i].light) + { + rc = SSMR3PutMem(pSSM, pContext->attrib.enableStack[i].light, + pContext->limits.maxLights*sizeof(GLboolean)); + AssertRCReturn(rc, rc); + } + + if (pContext->attrib.lightingStack[i].light) + { + rc = SSMR3PutMem(pSSM, pContext->attrib.lightingStack[i].light, + pContext->limits.maxLights*sizeof(CRLight)); + AssertRCReturn(rc, rc); + } + + for (j=0; j<pContext->limits.maxTextureUnits; ++j) + { + rc = crStateSaveTexUnitCurrentTexturePtrs(&pContext->attrib.textureStack[i].unit[j], pSSM); + AssertRCReturn(rc, rc); + } + + if (pContext->attrib.transformStack[i].clip) + { + rc = SSMR3PutMem(pSSM, pContext->attrib.transformStack[i].clip, + pContext->limits.maxClipPlanes*sizeof(GLboolean)); + AssertRCReturn(rc, rc); + } + + if (pContext->attrib.transformStack[i].clipPlane) + { + rc = SSMR3PutMem(pSSM, pContext->attrib.transformStack[i].clipPlane, + pContext->limits.maxClipPlanes*sizeof(GLvectord)); + AssertRCReturn(rc, rc); + } + + rc = crSateSaveEvalCoeffs1D(pContext->attrib.evalStack[i].eval1D, pSSM); + AssertRCReturn(rc, rc); + rc = crSateSaveEvalCoeffs2D(pContext->attrib.evalStack[i].eval2D, pSSM); + AssertRCReturn(rc, rc); + } + + /* Save evaluator coeffs */ + rc = crSateSaveEvalCoeffs1D(pContext->eval.eval1D, pSSM); + AssertRCReturn(rc, rc); + rc = crSateSaveEvalCoeffs2D(pContext->eval.eval2D, pSSM); + AssertRCReturn(rc, rc); + +#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); + + /* Save default one*/ + crStateSaveBufferObjectCB(0, pContext->bufferobject.nullBuffer, pSSM); + + if (bSaveShared) + { + /* Save all the rest */ + crHashtableWalk(pContext->shared->buffersTable, crStateSaveBufferObjectCB, pSSM); + } + + /* Restore binding */ + diff_api.BindBufferARB(GL_ARRAY_BUFFER_ARB, pContext->bufferobject.arrayBuffer->hwid); + + /* Save pointers */ + rc = SSMR3PutU32(pSSM, pContext->bufferobject.arrayBuffer->id); + AssertRCReturn(rc, rc); + rc = SSMR3PutU32(pSSM, pContext->bufferobject.elementsBuffer->id); + AssertRCReturn(rc, rc); +#ifdef CR_ARB_pixel_buffer_object + rc = SSMR3PutU32(pSSM, pContext->bufferobject.packBuffer->id); + AssertRCReturn(rc, rc); + rc = SSMR3PutU32(pSSM, pContext->bufferobject.unpackBuffer->id); + AssertRCReturn(rc, rc); +#endif + /* Save clint pointers and buffer bindings*/ + for (i=0; i<CRSTATECLIENT_MAX_VERTEXARRAYS; ++i) + { + rc = crStateSaveClientPointer(&pContext->client.array, i, pSSM); + AssertRCReturn(rc, rc); + } + + crDebug("client.vertexArrayStackDepth %i", pContext->client.vertexArrayStackDepth); + for (i=0; i<pContext->client.vertexArrayStackDepth; ++i) + { + CRVertexArrays *pArray = &pContext->client.vertexArrayStack[i]; + for (j=0; j<CRSTATECLIENT_MAX_VERTEXARRAYS; ++j) + { + rc = crStateSaveClientPointer(pArray, j, pSSM); + AssertRCReturn(rc, rc); + } + } +#endif /*CR_ARB_vertex_buffer_object*/ + + /* Save pixel/vertex programs */ + ui32 = crHashtableNumElements(pContext->program.programHash); + rc = SSMR3PutU32(pSSM, ui32); + AssertRCReturn(rc, rc); + /* Save defaults programs */ + crStateSaveProgramCB(0, pContext->program.defaultVertexProgram, pSSM); + crStateSaveProgramCB(0, pContext->program.defaultFragmentProgram, pSSM); + /* Save all the rest */ + crHashtableWalk(pContext->program.programHash, crStateSaveProgramCB, pSSM); + /* Save Pointers */ + rc = SSMR3PutU32(pSSM, pContext->program.currentVertexProgram->id); + AssertRCReturn(rc, rc); + rc = SSMR3PutU32(pSSM, pContext->program.currentFragmentProgram->id); + AssertRCReturn(rc, rc); + /* This one is unused it seems*/ + CRASSERT(!pContext->program.errorString); + +#ifdef CR_EXT_framebuffer_object + /* 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); + crHashtableWalk(pContext->shared->rbTable, crStateSaveRenderbuffersCB, pSSM); + } + rc = SSMR3PutU32(pSSM, pContext->framebufferobject.drawFB?pContext->framebufferobject.drawFB->id:0); + AssertRCReturn(rc, rc); + rc = SSMR3PutU32(pSSM, pContext->framebufferobject.readFB?pContext->framebufferobject.readFB->id:0); + AssertRCReturn(rc, rc); + rc = SSMR3PutU32(pSSM, pContext->framebufferobject.renderbuffer?pContext->framebufferobject.renderbuffer->id:0); + AssertRCReturn(rc, rc); +#endif + +#ifdef CR_OPENGL_VERSION_2_0 + /* Save GLSL related info */ + ui32 = crHashtableNumElements(pContext->glsl.shaders); + rc = SSMR3PutU32(pSSM, ui32); + AssertRCReturn(rc, rc); + crHashtableWalk(pContext->glsl.shaders, crStateSaveGLSLShaderCB, pSSM); + ui32 = crHashtableNumElements(pContext->glsl.programs); + rc = SSMR3PutU32(pSSM, ui32); + AssertRCReturn(rc, rc); + crHashtableWalk(pContext->glsl.programs, crStateSaveGLSLProgramCB, pSSM); + rc = SSMR3PutU32(pSSM, pContext->glsl.activeProgram?pContext->glsl.activeProgram->id:0); + AssertRCReturn(rc, rc); +#endif + + return VINF_SUCCESS; +} + +typedef struct _crFindSharedCtxParms { + PFNCRSTATE_CONTEXT_GET pfnCtxGet; + CRContext *pSrcCtx, *pDstCtx; +} crFindSharedCtxParms_t; + +static void crStateFindSharedCB(unsigned long key, void *data1, void *data2) +{ + crFindSharedCtxParms_t *pParms = (crFindSharedCtxParms_t *) data2; + CRContext *pContext = pParms->pfnCtxGet(data1); + (void) key; + + if (pContext!=pParms->pSrcCtx && pContext->shared->id==pParms->pSrcCtx->shared->id) + { + pParms->pDstCtx->shared = pContext->shared; + } +} + +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) + +AssertCompile(VBOXTLSREFDATA_SIZE() <= CR_MAX_BITARRAY); +AssertCompile(VBOXTLSREFDATA_STATE_INITIALIZED != 0); +AssertCompile(RTASSERT_OFFSET_OF(CRContext, shared) >= VBOXTLSREFDATA_ASSERT_OFFSET(CRContext) + + VBOXTLSREFDATA_SIZE() + + RT_SIZEOFMEMB(CRContext, bitid) + + RT_SIZEOFMEMB(CRContext, neg_bitid)); + +int32_t crStateLoadContext(CRContext *pContext, CRHashTable * pCtxTable, PFNCRSTATE_CONTEXT_GET pfnCtxGet, PSSMHANDLE pSSM, uint32_t u32Version) +{ + CRContext* pTmpContext; + int32_t rc, i, j; + uint32_t uiNumElems, ui, k; + unsigned long key; + GLboolean bLoadShared = GL_TRUE; + GLenum err; + + CRASSERT(pContext && pSSM); + + /* This one is rather big for stack allocation and causes macs to crash */ + pTmpContext = (CRContext*)crAlloc(sizeof(*pTmpContext)); + if (!pTmpContext) + return VERR_NO_MEMORY; + + CRASSERT(VBoxTlsRefIsFunctional(pContext)); + + if (u32Version <= SHCROGL_SSM_VERSION_WITH_INVALID_ERROR_STATE) + { + 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); + + /* 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) + { + /* 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 = VBOXTLSREFDATA_OFFSET(CRContext) + VBOXTLSREFDATA_SIZE() + sizeof (pTmpContext->bitid) + sizeof (pTmpContext->neg_bitid); + ui = RT_UOFFSETOF(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); + + /* 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); + + ui &= (sizeof (void*) - 1); + } + + 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_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, 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); + } + 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 + { + 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; + int32_t shared; + + rc = SSMR3GetS32(pSSM, &pContext->shared->id); + AssertRCReturn(rc, rc); + + rc = SSMR3GetS32(pSSM, &shared); + AssertRCReturn(rc, rc); + + pTmpContext->shared = NULL; + parms.pfnCtxGet = pfnCtxGet; + parms.pSrcCtx = pContext; + parms.pDstCtx = pTmpContext; + crHashtableWalk(pCtxTable, crStateFindSharedCB, &parms); + + if (pTmpContext->shared) + { + CRASSERT(pContext->shared->refCount==1); + bLoadShared = GL_FALSE; + crStateFreeShared(pContext, pContext->shared); + pContext->shared = NULL; + pTmpContext->shared->refCount++; + } + else + { + SLC_COPYPTR(shared); + } + + if (bLoadShared && shared) + { + crStateSetSharedContext(pTmpContext); + } + } + + SLC_COPYPTR(flush_func); + SLC_COPYPTR(flush_arg); + + /* We're supposed to be loading into an empty context, so those pointers should be NULL */ + for ( i = 0 ; i < CR_MAX_ATTRIB_STACK_DEPTH ; i++) + { + SLC_ASSSERT_NULL_PTR(attrib.enableStack[i].clip); + SLC_ASSSERT_NULL_PTR(attrib.enableStack[i].light); + + SLC_ASSSERT_NULL_PTR(attrib.lightingStack[i].light); + SLC_ASSSERT_NULL_PTR(attrib.transformStack[i].clip); + SLC_ASSSERT_NULL_PTR(attrib.transformStack[i].clipPlane); + + for (j=0; j<GLEVAL_TOT; ++j) + { + SLC_ASSSERT_NULL_PTR(attrib.evalStack[i].eval1D[j].coeff); + SLC_ASSSERT_NULL_PTR(attrib.evalStack[i].eval2D[j].coeff); + } + } + +#ifdef CR_ARB_vertex_buffer_object + SLC_COPYPTR(bufferobject.nullBuffer); +#endif + +/*@todo, that should be removed probably as those should hold the offset values, so loading should be fine + but better check*/ +#if 0 +#ifdef CR_EXT_compiled_vertex_array + SLC_COPYPTR(client.array.v.prevPtr); + SLC_COPYPTR(client.array.c.prevPtr); + SLC_COPYPTR(client.array.f.prevPtr); + SLC_COPYPTR(client.array.s.prevPtr); + SLC_COPYPTR(client.array.e.prevPtr); + SLC_COPYPTR(client.array.i.prevPtr); + SLC_COPYPTR(client.array.n.prevPtr); + for (i = 0 ; i < CR_MAX_TEXTURE_UNITS ; i++) + { + SLC_COPYPTR(client.array.t[i].prevPtr); + } + +# ifdef CR_NV_vertex_program + for (i = 0; i < CR_MAX_VERTEX_ATTRIBS; i++) + { + SLC_COPYPTR(client.array.a[i].prevPtr); + } +# endif +#endif +#endif + +#ifdef CR_ARB_vertex_buffer_object + /*That just sets those pointers to NULL*/ + SLC_COPYPTR(client.array.v.buffer); + SLC_COPYPTR(client.array.c.buffer); + SLC_COPYPTR(client.array.f.buffer); + SLC_COPYPTR(client.array.s.buffer); + SLC_COPYPTR(client.array.e.buffer); + SLC_COPYPTR(client.array.i.buffer); + SLC_COPYPTR(client.array.n.buffer); + for (i = 0 ; i < CR_MAX_TEXTURE_UNITS ; i++) + { + SLC_COPYPTR(client.array.t[i].buffer); + } +# ifdef CR_NV_vertex_program + for (i = 0; i < CR_MAX_VERTEX_ATTRIBS; i++) + { + SLC_COPYPTR(client.array.a[i].buffer); + } +# endif +#endif /*CR_ARB_vertex_buffer_object*/ + + /** @todo CR_NV_vertex_program*/ + crStateCopyEvalPtrs1D(pTmpContext->eval.eval1D, pContext->eval.eval1D); + crStateCopyEvalPtrs2D(pTmpContext->eval.eval2D, pContext->eval.eval2D); + + SLC_COPYPTR(feedback.buffer); /** @todo */ + SLC_COPYPTR(selection.buffer); /** @todo */ + + SLC_COPYPTR(lighting.light); + + /*This one could be tricky if we're loading snapshot on host with different GPU*/ + SLC_COPYPTR(limits.extensions); + +#if CR_ARB_occlusion_query + SLC_COPYPTR(occlusion.objects); /** @todo */ +#endif + + SLC_COPYPTR(program.errorString); + SLC_COPYPTR(program.programHash); + SLC_COPYPTR(program.defaultVertexProgram); + SLC_COPYPTR(program.defaultFragmentProgram); + + /* Texture pointers */ + for (i=0; i<6; ++i) + { + SLC_COPYPTR(texture.base1D.level[i]); + SLC_COPYPTR(texture.base2D.level[i]); + SLC_COPYPTR(texture.base3D.level[i]); + SLC_COPYPTR(texture.proxy1D.level[i]); + SLC_COPYPTR(texture.proxy2D.level[i]); + SLC_COPYPTR(texture.proxy3D.level[i]); +#ifdef CR_ARB_texture_cube_map + SLC_COPYPTR(texture.baseCubeMap.level[i]); + SLC_COPYPTR(texture.proxyCubeMap.level[i]); +#endif +#ifdef CR_NV_texture_rectangle + SLC_COPYPTR(texture.baseRect.level[i]); + SLC_COPYPTR(texture.proxyRect.level[i]); +#endif + } + + /* Load transform state */ + SLC_COPYPTR(transform.clipPlane); + SLC_COPYPTR(transform.clip); + /* Don't have to worry about pContext->transform.current as it'd be set in crStateSetCurrent call */ + /*SLC_COPYPTR(transform.currentStack);*/ + SLC_COPYPTR(transform.modelViewStack.stack); + SLC_COPYPTR(transform.projectionStack.stack); + SLC_COPYPTR(transform.colorStack.stack); + + for (i = 0 ; i < CR_MAX_TEXTURE_UNITS ; i++) + { + SLC_COPYPTR(transform.textureStack[i].stack); + } + for (i = 0 ; i < CR_MAX_PROGRAM_MATRICES ; i++) + { + SLC_COPYPTR(transform.programStack[i].stack); + } + +#ifdef CR_OPENGL_VERSION_2_0 + SLC_COPYPTR(glsl.shaders); + SLC_COPYPTR(glsl.programs); +#endif + + /* Have to preserve original context id */ + CRASSERT(pTmpContext->id == pContext->id); + CRASSERT(VBOXTLSREFDATA_EQUAL(pContext, pTmpContext)); + /* Copy ordinary state to real context */ + crMemcpy(pContext, pTmpContext, sizeof(*pTmpContext)); + crFree(pTmpContext); + pTmpContext = NULL; + + /* Now deal with pointers */ + + /* Load transform state */ + rc = SSMR3GetMem(pSSM, pContext->transform.clipPlane, sizeof(GLvectord)*CR_MAX_CLIP_PLANES); + AssertRCReturn(rc, rc); + rc = SSMR3GetMem(pSSM, pContext->transform.clip, sizeof(GLboolean)*CR_MAX_CLIP_PLANES); + AssertRCReturn(rc, rc); + rc = crStateLoadMatrixStack(&pContext->transform.modelViewStack, pSSM); + AssertRCReturn(rc, rc); + rc = crStateLoadMatrixStack(&pContext->transform.projectionStack, pSSM); + AssertRCReturn(rc, rc); + rc = crStateLoadMatrixStack(&pContext->transform.colorStack, pSSM); + AssertRCReturn(rc, rc); + for (i = 0 ; i < CR_MAX_TEXTURE_UNITS ; i++) + { + rc = crStateLoadMatrixStack(&pContext->transform.textureStack[i], pSSM); + AssertRCReturn(rc, rc); + } + for (i = 0 ; i < CR_MAX_PROGRAM_MATRICES ; i++) + { + rc = crStateLoadMatrixStack(&pContext->transform.programStack[i], pSSM); + AssertRCReturn(rc, rc); + } + + /* Load Textures */ + rc = crStateLoadTextureObjData(&pContext->texture.base1D, pSSM); + AssertRCReturn(rc, rc); + rc = crStateLoadTextureObjData(&pContext->texture.base2D, pSSM); + AssertRCReturn(rc, rc); + rc = crStateLoadTextureObjData(&pContext->texture.base3D, pSSM); + AssertRCReturn(rc, rc); + rc = crStateLoadTextureObjData(&pContext->texture.proxy1D, pSSM); + AssertRCReturn(rc, rc); + rc = crStateLoadTextureObjData(&pContext->texture.proxy2D, pSSM); + AssertRCReturn(rc, rc); + rc = crStateLoadTextureObjData(&pContext->texture.proxy3D, pSSM); + AssertRCReturn(rc, rc); +#ifdef CR_ARB_texture_cube_map + rc = crStateLoadTextureObjData(&pContext->texture.baseCubeMap, pSSM); + AssertRCReturn(rc, rc); + rc = crStateLoadTextureObjData(&pContext->texture.proxyCubeMap, pSSM); + AssertRCReturn(rc, rc); +#endif +#ifdef CR_NV_texture_rectangle + rc = crStateLoadTextureObjData(&pContext->texture.baseRect, pSSM); + AssertRCReturn(rc, rc); + rc = crStateLoadTextureObjData(&pContext->texture.proxyRect, pSSM); + AssertRCReturn(rc, rc); +#endif + + if (bLoadShared) + { + /* 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) + { + CRTextureObj *pTexture; + + rc = SSMR3GetMem(pSSM, &key, sizeof(key)); + AssertRCReturn(rc, rc); + + pTexture = (CRTextureObj *) crCalloc(sizeof(CRTextureObj)); + if (!pTexture) return VERR_NO_MEMORY; + + rc = crStateLoadTextureObj(pTexture, pSSM, u32Version); + AssertRCReturn(rc, rc); + + pTexture->hwid = 0; + + /*allocate actual memory*/ + for (i=0; i<6; ++i) { + pTexture->level[i] = (CRTextureLevel *) crCalloc(sizeof(CRTextureLevel) * CR_MAX_MIPMAP_LEVELS); + if (!pTexture->level[i]) return VERR_NO_MEMORY; + } + + rc = crStateLoadTextureObjData(pTexture, pSSM); + AssertRCReturn(rc, rc); + + crHashtableAdd(pContext->shared->textureTable, key, pTexture); + } + } + + /* Load current texture pointers */ + for (i=0; i<CR_MAX_TEXTURE_UNITS; ++i) + { + rc = crStateLoadTexUnitCurrentTexturePtrs(&pContext->texture.unit[i], pContext, pSSM); + AssertRCReturn(rc, rc); + } + + /* Mark textures for resending to GPU */ + pContext->shared->bTexResyncNeeded = GL_TRUE; + + /* Load lights */ + CRASSERT(pContext->lighting.light); + rc = SSMR3GetMem(pSSM, pContext->lighting.light, CR_MAX_LIGHTS * sizeof(*pContext->lighting.light)); + AssertRCReturn(rc, rc); + + /* Load attrib stack*/ + for ( i = 0 ; i < CR_MAX_ATTRIB_STACK_DEPTH ; i++) + { + if (pContext->attrib.enableStack[i].clip) + { + rc = crStateAllocAndSSMR3GetMem(pSSM, (void**)&pContext->attrib.enableStack[i].clip, + pContext->limits.maxClipPlanes*sizeof(GLboolean)); + AssertRCReturn(rc, rc); + } + + if (pContext->attrib.enableStack[i].light) + { + rc = crStateAllocAndSSMR3GetMem(pSSM, (void**)&pContext->attrib.enableStack[i].light, + pContext->limits.maxLights*sizeof(GLboolean)); + AssertRCReturn(rc, rc); + } + + if (pContext->attrib.lightingStack[i].light) + { + rc = crStateAllocAndSSMR3GetMem(pSSM, (void**)&pContext->attrib.lightingStack[i].light, + pContext->limits.maxLights*sizeof(CRLight)); + AssertRCReturn(rc, rc); + } + + for (k=0; k<pContext->limits.maxTextureUnits; ++k) + { + rc = crStateLoadTexUnitCurrentTexturePtrs(&pContext->attrib.textureStack[i].unit[k], pContext, pSSM); + AssertRCReturn(rc, rc); + } + + if (pContext->attrib.transformStack[i].clip) + { + rc = crStateAllocAndSSMR3GetMem(pSSM, (void*)&pContext->attrib.transformStack[i].clip, + pContext->limits.maxClipPlanes*sizeof(GLboolean)); + AssertRCReturn(rc, rc); + } + + if (pContext->attrib.transformStack[i].clipPlane) + { + rc = crStateAllocAndSSMR3GetMem(pSSM, (void**)&pContext->attrib.transformStack[i].clipPlane, + pContext->limits.maxClipPlanes*sizeof(GLvectord)); + AssertRCReturn(rc, rc); + } + rc = crSateLoadEvalCoeffs1D(pContext->attrib.evalStack[i].eval1D, GL_TRUE, pSSM); + AssertRCReturn(rc, rc); + rc = crSateLoadEvalCoeffs2D(pContext->attrib.evalStack[i].eval2D, GL_TRUE, pSSM); + AssertRCReturn(rc, rc); + } + + /* Load evaluator coeffs */ + rc = crSateLoadEvalCoeffs1D(pContext->eval.eval1D, GL_FALSE, pSSM); + AssertRCReturn(rc, rc); + rc = crSateLoadEvalCoeffs2D(pContext->eval.eval2D, GL_FALSE, pSSM); + AssertRCReturn(rc, rc); + + /* 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*/ + { + CRBufferObject *pBufferObj; + + rc = SSMR3GetMem(pSSM, &key, sizeof(key)); + AssertRCReturn(rc, rc); + + /* default one should be already allocated */ + if (key==0) + { + pBufferObj = pContext->bufferobject.nullBuffer; + if (!pBufferObj) return VERR_SSM_UNEXPECTED_DATA; + } + else + { + pBufferObj = (CRBufferObject *) crCalloc(sizeof(*pBufferObj)); + if (!pBufferObj) return VERR_NO_MEMORY; + } + + rc = crStateLoadBufferObject(pBufferObj, pSSM, u32Version); + AssertRCReturn(rc, rc); + + pBufferObj->hwid = 0; + + if (pBufferObj->data) + { + CRASSERT(pBufferObj->size>0); + pBufferObj->data = crAlloc(pBufferObj->size); + rc = SSMR3GetMem(pSSM, pBufferObj->data, pBufferObj->size); + AssertRCReturn(rc, rc); + } + else if (pBufferObj->id!=0 && pBufferObj->size>0) + { + rc = SSMR3GetMem(pSSM, &pBufferObj->data, sizeof(pBufferObj->data)); + AssertRCReturn(rc, rc); + + if (pBufferObj->data) + { + pBufferObj->data = crAlloc(pBufferObj->size); + rc = SSMR3GetMem(pSSM, pBufferObj->data, pBufferObj->size); + AssertRCReturn(rc, rc); + } + } + + + if (key!=0) + crHashtableAdd(pContext->shared->buffersTable, key, pBufferObj); + } + /* Load pointers */ +#define CRS_GET_BO(name) (((name)==0) ? (pContext->bufferobject.nullBuffer) : crHashtableSearch(pContext->shared->buffersTable, name)) + rc = SSMR3GetU32(pSSM, &ui); + AssertRCReturn(rc, rc); + pContext->bufferobject.arrayBuffer = CRS_GET_BO(ui); + rc = SSMR3GetU32(pSSM, &ui); + AssertRCReturn(rc, rc); + pContext->bufferobject.elementsBuffer = CRS_GET_BO(ui); +#ifdef CR_ARB_pixel_buffer_object + rc = SSMR3GetU32(pSSM, &ui); + AssertRCReturn(rc, rc); + pContext->bufferobject.packBuffer = CRS_GET_BO(ui); + rc = SSMR3GetU32(pSSM, &ui); + AssertRCReturn(rc, rc); + pContext->bufferobject.unpackBuffer = CRS_GET_BO(ui); +#endif +#undef CRS_GET_BO + + /* Load client pointers and array buffer bindings*/ + for (i=0; i<CRSTATECLIENT_MAX_VERTEXARRAYS; ++i) + { + rc = crStateLoadClientPointer(&pContext->client.array, i, pContext, pSSM); + AssertRCReturn(rc, rc); + } + for (j=0; j<pContext->client.vertexArrayStackDepth; ++j) + { + CRVertexArrays *pArray = &pContext->client.vertexArrayStack[j]; + for (i=0; i<CRSTATECLIENT_MAX_VERTEXARRAYS; ++i) + { + rc = crStateLoadClientPointer(pArray, i, pContext, pSSM); + AssertRCReturn(rc, rc); + } + } + + pContext->shared->bVBOResyncNeeded = GL_TRUE; +#endif + + /* Load pixel/vertex programs */ + rc = SSMR3GetU32(pSSM, &uiNumElems); + AssertRCReturn(rc, rc); + /* Load defaults programs */ + rc = crStateLoadProgram(&pContext->program.defaultVertexProgram, pSSM); + AssertRCReturn(rc, rc); + rc = crStateLoadProgram(&pContext->program.defaultFragmentProgram, pSSM); + AssertRCReturn(rc, rc); + /* Load all the rest */ + for (ui=0; ui<uiNumElems; ++ui) + { + CRProgram *pProgram = NULL; + rc = crStateLoadProgram(&pProgram, pSSM); + AssertRCReturn(rc, rc); + crHashtableAdd(pContext->program.programHash, pProgram->id, pProgram); + //DIRTY(pProgram->dirtyProgram, pContext->neg_bitid); + + } + /* Load Pointers */ + rc = SSMR3GetU32(pSSM, &ui); + AssertRCReturn(rc, rc); + pContext->program.currentVertexProgram = ui==0 ? pContext->program.defaultVertexProgram + : crHashtableSearch(pContext->program.programHash, ui); + rc = SSMR3GetU32(pSSM, &ui); + AssertRCReturn(rc, rc); + pContext->program.currentFragmentProgram = ui==0 ? pContext->program.defaultFragmentProgram + : crHashtableSearch(pContext->program.programHash, ui); + + /* Mark programs for resending to GPU */ + pContext->program.bResyncNeeded = GL_TRUE; + +#ifdef CR_EXT_framebuffer_object + /* 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) + { + CRFramebufferObject *pFBO; + pFBO = crAlloc(sizeof(*pFBO)); + if (!pFBO) return VERR_NO_MEMORY; + + rc = SSMR3GetMem(pSSM, &key, sizeof(key)); + AssertRCReturn(rc, rc); + + 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) + { + CRRenderbufferObject *pRBO; + pRBO = crAlloc(sizeof(*pRBO)); + if (!pRBO) return VERR_NO_MEMORY; + + rc = SSMR3GetMem(pSSM, &key, sizeof(key)); + AssertRCReturn(rc, rc); + + rc = crStateLoadRenderbufferObject(pRBO, pSSM, u32Version); + AssertRCReturn(rc, rc); + + crHashtableAdd(pContext->shared->rbTable, key, pRBO); + } + } + + rc = SSMR3GetU32(pSSM, &ui); + AssertRCReturn(rc, rc); + pContext->framebufferobject.drawFB = ui==0 ? NULL + : crHashtableSearch(pContext->shared->fbTable, ui); + + rc = SSMR3GetU32(pSSM, &ui); + AssertRCReturn(rc, rc); + pContext->framebufferobject.readFB = ui==0 ? NULL + : crHashtableSearch(pContext->shared->fbTable, ui); + + rc = SSMR3GetU32(pSSM, &ui); + AssertRCReturn(rc, rc); + pContext->framebufferobject.renderbuffer = ui==0 ? NULL + : crHashtableSearch(pContext->shared->rbTable, ui); + + /* Mark FBOs/RBOs for resending to GPU */ + pContext->shared->bFBOResyncNeeded = GL_TRUE; +#endif + +#ifdef CR_OPENGL_VERSION_2_0 + /* Load GLSL related info */ + rc = SSMR3GetU32(pSSM, &uiNumElems); + AssertRCReturn(rc, rc); + + 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); + } + + rc = SSMR3GetU32(pSSM, &uiNumElems); + AssertRCReturn(rc, rc); + + for (ui=0; ui<uiNumElems; ++ui) + { + CRGLSLProgram *pProgram; + uint32_t numShaders; + + pProgram = crAlloc(sizeof(*pProgram)); + if (!pProgram) return VERR_NO_MEMORY; + + rc = SSMR3GetMem(pSSM, &key, sizeof(key)); + AssertRCReturn(rc, rc); + + rc = SSMR3GetMem(pSSM, pProgram, sizeof(*pProgram)); + AssertRCReturn(rc, rc); + + crHashtableAdd(pContext->glsl.programs, key, pProgram); + + pProgram->currentState.attachedShaders = crAllocHashtable(); + + rc = SSMR3GetU32(pSSM, &numShaders); + AssertRCReturn(rc, rc); + + for (k=0; k<numShaders; ++k) + { + rc = SSMR3GetMem(pSSM, &key, sizeof(key)); + AssertRCReturn(rc, rc); + crHashtableAdd(pProgram->currentState.attachedShaders, key, crHashtableSearch(pContext->glsl.shaders, key)); + } + + if (pProgram->activeState.attachedShaders) + { + pProgram->activeState.attachedShaders = crAllocHashtable(); + + rc = SSMR3GetU32(pSSM, &numShaders); + AssertRCReturn(rc, rc); + + for (k=0; k<numShaders; ++k) + { + CRGLSLShader *pShader = crStateLoadGLSLShader(pSSM); + if (!pShader) return VERR_SSM_UNEXPECTED_DATA; + crHashtableAdd(pProgram->activeState.attachedShaders, pShader->id, pShader); + } + } + + if (pProgram->currentState.cAttribs) + pProgram->currentState.pAttribs = (CRGLSLAttrib*) crAlloc(pProgram->currentState.cAttribs*sizeof(CRGLSLAttrib)); + for (k=0; k<pProgram->currentState.cAttribs; ++k) + { + rc = SSMR3GetMem(pSSM, &pProgram->currentState.pAttribs[k].index, sizeof(pProgram->currentState.pAttribs[k].index)); + AssertRCReturn(rc, rc); + pProgram->currentState.pAttribs[k].name = crStateLoadString(pSSM); + } + + if (pProgram->activeState.cAttribs) + pProgram->activeState.pAttribs = (CRGLSLAttrib*) crAlloc(pProgram->activeState.cAttribs*sizeof(CRGLSLAttrib)); + for (k=0; k<pProgram->activeState.cAttribs; ++k) + { + rc = SSMR3GetMem(pSSM, &pProgram->activeState.pAttribs[k].index, sizeof(pProgram->activeState.pAttribs[k].index)); + AssertRCReturn(rc, rc); + pProgram->activeState.pAttribs[k].name = crStateLoadString(pSSM); + } + + { + int32_t cUniforms; + rc = SSMR3GetS32(pSSM, &cUniforms); + pProgram->cUniforms = cUniforms; + AssertRCReturn(rc, rc); + } + + if (pProgram->cUniforms) + { + pProgram->pUniforms = crAlloc(pProgram->cUniforms*sizeof(CRGLSLUniform)); + if (!pProgram->pUniforms) return VERR_NO_MEMORY; + + for (k=0; k<pProgram->cUniforms; ++k) + { + size_t itemsize, datasize; + + rc = SSMR3GetMem(pSSM, &pProgram->pUniforms[k].type, sizeof(GLenum)); + AssertRCReturn(rc, rc); + pProgram->pUniforms[k].name = crStateLoadString(pSSM); + + if (crStateIsIntUniform(pProgram->pUniforms[k].type)) + { + itemsize = sizeof(GLint); + } else itemsize = sizeof(GLfloat); + + datasize = crStateGetUniformSize(pProgram->pUniforms[k].type)*itemsize; + pProgram->pUniforms[k].data = crAlloc((unsigned int /* this case is just so stupid */)datasize); + if (!pProgram->pUniforms[k].data) return VERR_NO_MEMORY; + + rc = SSMR3GetMem(pSSM, pProgram->pUniforms[k].data, datasize); + AssertRCReturn(rc, rc); + } + } + } + + rc = SSMR3GetU32(pSSM, &ui); + AssertRCReturn(rc, rc); + pContext->glsl.activeProgram = ui==0 ? NULL + : crHashtableSearch(pContext->glsl.programs, ui); + + /*Mark for resending to GPU*/ + pContext->glsl.bResyncNeeded = GL_TRUE; +#endif + + if (pContext->error != err) + { + 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; +} |