/* $Id: dump.cpp 69500 2017-10-28 15:14:05Z vboxsync $ */ /** @file * Blitter API implementation */ /* * Copyright (C) 2013-2017 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 #include "cr_pixeldata.h" #include #include #include #include #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; ipDispatch->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; ipDispatch->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; j1) { 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; ipDispatch->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; ipDispatch->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; j1) { 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("%s, ( %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, "
%s
\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, "
%s
\"%s\"

\n", pszFileName, pszEntryDesc, pszFileName, pszEntryDesc); fflush(pHtmlDumper->pFile); } static void crDmpHtmlPrintHeader(struct CR_HTML_DUMPER * pDumper) { fprintf(pDumper->pFile, "\n"); fflush(pDumper->pFile); } static void crDmpHtmlPrintFooter(struct CR_HTML_DUMPER * pDumper) { fprintf(pDumper->pFile, "\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