VirtualBox

source: vbox/trunk/src/VBox/GuestHost/OpenGL/state_tracker/dump.cpp@ 71930

Last change on this file since 71930 was 69500, checked in by vboxsync, 7 years ago

*: scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 53.8 KB
Line 
1/* $Id: dump.cpp 69500 2017-10-28 15:14:05Z vboxsync $ */
2
3/** @file
4 * Blitter API implementation
5 */
6/*
7 * Copyright (C) 2013-2017 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17#include "cr_blitter.h"
18#include "cr_spu.h"
19#include "chromium.h"
20#include "cr_error.h"
21#include "cr_net.h"
22#include "cr_rand.h"
23#include "cr_mem.h"
24#include "cr_string.h"
25#include <cr_dump.h>
26#include "cr_pixeldata.h"
27
28#include <iprt/cdefs.h>
29#include <iprt/types.h>
30#include <iprt/mem.h>
31
32#include <stdio.h>
33
34#ifdef VBOX_WITH_CRDUMPER
35
36static uint32_t g_CrDbgDumpRecTexInfo = 1;
37static uint32_t g_CrDbgDumpAlphaData = 1;
38
39/* dump stuff */
40#pragma pack(1)
41typedef struct VBOX_BITMAPFILEHEADER {
42 uint16_t bfType;
43 uint32_t bfSize;
44 uint16_t bfReserved1;
45 uint16_t bfReserved2;
46 uint32_t bfOffBits;
47} VBOX_BITMAPFILEHEADER;
48
49typedef struct VBOX_BITMAPINFOHEADER {
50 uint32_t biSize;
51 int32_t biWidth;
52 int32_t biHeight;
53 uint16_t biPlanes;
54 uint16_t biBitCount;
55 uint32_t biCompression;
56 uint32_t biSizeImage;
57 int32_t biXPelsPerMeter;
58 int32_t biYPelsPerMeter;
59 uint32_t biClrUsed;
60 uint32_t biClrImportant;
61} VBOX_BITMAPINFOHEADER;
62#pragma pack()
63
64void crDmpImgBmp(CR_BLITTER_IMG *pImg, const char *pszFilename)
65{
66 static int sIdx = 0;
67
68 if ( pImg->bpp != 16
69 && pImg->bpp != 24
70 && pImg->bpp != 32)
71 {
72 crWarning("not supported bpp %d", pImg->bpp);
73 return;
74 }
75
76 FILE *f = fopen (pszFilename, "wb");
77 if (!f)
78 {
79 crWarning("fopen failed");
80 return;
81 }
82
83 VBOX_BITMAPFILEHEADER bf;
84
85 bf.bfType = 'MB';
86 bf.bfSize = sizeof (VBOX_BITMAPFILEHEADER) + sizeof (VBOX_BITMAPINFOHEADER) + pImg->cbData;
87 bf.bfReserved1 = 0;
88 bf.bfReserved2 = 0;
89 bf.bfOffBits = sizeof (VBOX_BITMAPFILEHEADER) + sizeof (VBOX_BITMAPINFOHEADER);
90
91 VBOX_BITMAPINFOHEADER bi;
92
93 bi.biSize = sizeof (bi);
94 bi.biWidth = pImg->width;
95 bi.biHeight = pImg->height;
96 bi.biPlanes = 1;
97 bi.biBitCount = pImg->bpp;
98 bi.biCompression = 0;
99 bi.biSizeImage = pImg->cbData;
100 bi.biXPelsPerMeter = 0;
101 bi.biYPelsPerMeter = 0;
102 bi.biClrUsed = 0;
103 bi.biClrImportant = 0;
104
105 fwrite (&bf, 1, sizeof (bf), f);
106 fwrite (&bi, 1, sizeof (bi), f);
107 fwrite (pImg->pvData, 1, pImg->cbData, f);
108
109 fclose (f);
110}
111
112typedef struct CRDUMPGETHWID_DATA
113{
114 GLuint hwid;
115 PFNCRDUMPGETHWID pfnGetHwid;
116 unsigned long Key;
117 void* pvObj;
118} CRDUMPGETHWID_DATA;
119
120static void crDmpHashtableSearchByHwidCB(unsigned long key, void *pData1, void *pData2)
121{
122 CRDUMPGETHWID_DATA *pData = (CRDUMPGETHWID_DATA*)pData2;
123 if (pData->pvObj)
124 return;
125
126 if (pData->hwid == pData->pfnGetHwid(pData1))
127 {
128 pData->Key = key;
129 pData->pvObj = pData1;
130 }
131}
132
133void* crDmpHashtableSearchByHwid(CRHashTable *pHash, GLuint hwid, PFNCRDUMPGETHWID pfnGetHwid, unsigned long *pKey)
134{
135 CRDUMPGETHWID_DATA Data = {0};
136 Data.hwid = hwid;
137 Data.pfnGetHwid = pfnGetHwid;
138 crHashtableWalk(pHash, crDmpHashtableSearchByHwidCB, &Data);
139
140 Assert(Data.pvObj);
141
142 if (pKey)
143 *pKey = Data.Key;
144 return Data.pvObj;
145}
146
147#if 0
148typedef struct CR_SERVER_DUMP_FIND_TEX
149{
150 GLint hwid;
151 CRTextureObj *pTobj
152} CR_SERVER_DUMP_FIND_TEX;
153
154void crServerDumpFindTexCb(unsigned long key, void *pData1, void *pData2)
155{
156 CR_SERVER_DUMP_FIND_TEX *pTex = (CR_SERVER_DUMP_FIND_TEX*)pData2;
157 CRTextureObj *pTobj = (CRTextureObj *)pData1;
158 if (pTobj->hwid == pTex->hwid)
159 pTex->pTobj = pTobj;
160}
161#endif
162
163#define CR_DUMP_MAKE_CASE(_val) case _val: return #_val
164#define CR_DUMP_MAKE_CASE_UNKNOWN(_val, _str, _pDumper) default: { \
165 crWarning("%s %d", (_str), _val); \
166 crDmpStrF((_pDumper), "WARNING: %s %d", (_str), _val); \
167 return (_str); \
168}
169
170DECLINLINE(size_t) crDmpFormatVal(char *pString, size_t cbString, const char *pszElFormat, uint32_t cbVal, const void *pvVal)
171{
172 if (pszElFormat[0] != '%' || pszElFormat[1] == '\0')
173 {
174 crWarning("invalid format %s", pszElFormat);
175 return 0;
176 }
177 switch (cbVal)
178 {
179 case 8:
180 return sprintf_s(pString, cbString, pszElFormat, *((double*)pvVal));
181 case 4:
182 {
183 /* we do not care only about type specifiers, all the rest is not accepted */
184 switch (pszElFormat[1])
185 {
186 case 'f':
187 /* float would be promoted to double */
188 return sprintf_s(pString, cbString, pszElFormat, *((float*)pvVal));
189 default:
190 return sprintf_s(pString, cbString, pszElFormat, *((uint32_t*)pvVal));
191 }
192 }
193 case 2:
194 return sprintf_s(pString, cbString, pszElFormat, *((uint16_t*)pvVal));
195 case 1:
196 return sprintf_s(pString, cbString, pszElFormat, *((uint8_t*)pvVal));
197 default:
198 crWarning("unsupported size %d", cbVal);
199 return 0;
200 }
201}
202
203VBOXDUMPDECL(size_t) crDmpFormatRawArray(char *pString, size_t cbString, const char *pszElFormat, uint32_t cbEl, const void *pvVal, uint32_t cVal)
204{
205 if (cbString < 2)
206 {
207 crWarning("too few buffer size");
208 return 0;
209 }
210
211 const size_t cbInitString = cbString;
212 *pString++ = '{';
213 --cbString;
214 size_t cbWritten;
215 const uint8_t *pu8Val = (const uint8_t *)pvVal;
216 for (uint32_t i = 0; i < cVal; ++i)
217 {
218 cbWritten = crDmpFormatVal(pString, cbString, pszElFormat, cbEl, (const void *)pu8Val);
219 pu8Val += cbEl;
220 Assert(cbString >= cbWritten);
221 pString += cbWritten;
222 cbString -= cbWritten;
223 if (i != cVal - 1)
224 {
225 cbWritten = sprintf_s(pString, cbString, ", ");
226 Assert(cbString >= cbWritten);
227 pString += cbWritten;
228 cbString -= cbWritten;
229 }
230 }
231
232 if (!cbString)
233 {
234 crWarning("too few buffer size");
235 return 0;
236 }
237 *pString++ = '}';
238 --cbString;
239
240 if (!cbString)
241 {
242 crWarning("too few buffer size");
243 return 0;
244 }
245 *pString++ = '\0';
246
247 return cbInitString - cbString;
248}
249
250VBOXDUMPDECL(size_t) crDmpFormatMatrixArray(char *pString, size_t cbString, const char *pszElFormat, uint32_t cbEl, const void *pvVal, uint32_t cX, uint32_t cY)
251{
252 if (cbString < 2)
253 {
254 crWarning("too few buffer size");
255 return 0;
256 }
257
258 const size_t cbInitString = cbString;
259 *pString++ = '{';
260 --cbString;
261 size_t cbWritten;
262 const uint8_t *pu8Val = (const uint8_t *)pvVal;
263 for (uint32_t i = 0; i < cY; ++i)
264 {
265 cbWritten = crDmpFormatRawArray(pString, cbString, pszElFormat, cbEl, (const void *)pu8Val, cX);
266 pu8Val += (cbEl * cX);
267 Assert(cbString >= cbWritten);
268 pString += cbWritten;
269 cbString -= cbWritten;
270 if (i != cY - 1)
271 {
272 if (cbString < 3)
273 {
274 crWarning("too few buffer size");
275 return 0;
276 }
277 *pString++ = ',';
278 --cbString;
279 *pString++ = '\n';
280 --cbString;
281 }
282 }
283 if (!cbString)
284 {
285 crWarning("too few buffer size");
286 return 0;
287 }
288 *pString++ = '}';
289 --cbString;
290
291 if (!cbString)
292 {
293 crWarning("too few buffer size");
294 return 0;
295 }
296 *pString++ = '\0';
297
298 return cbInitString - cbString;
299}
300
301VBOXDUMPDECL(size_t) crDmpFormatArray(char *pString, size_t cbString, const char *pszElFormat, uint32_t cbEl, const void *pvVal, uint32_t cVal)
302{
303 switch(cVal)
304 {
305 case 1:
306 return crDmpFormatVal(pString, cbString, pszElFormat, cbEl, pvVal);
307 case 16:
308 return crDmpFormatMatrixArray(pString, cbString, pszElFormat, cbEl, pvVal, 4, 4);
309 case 9:
310 return crDmpFormatMatrixArray(pString, cbString, pszElFormat, cbEl, pvVal, 3, 3);
311 case 0:
312 crWarning("value array is empty");
313 return 0;
314 default:
315 return crDmpFormatRawArray(pString, cbString, pszElFormat, cbEl, pvVal, cVal);
316 }
317}
318
319VBOXDUMPDECL(void) crRecDumpVertAttrv(CR_RECORDER *pRec, CRContext *ctx, GLuint idx, const char*pszElFormat, uint32_t cbEl, const void *pvVal, uint32_t cVal)
320{
321 char aBuf[1024];
322 crDmpFormatRawArray(aBuf, sizeof (aBuf), pszElFormat, cbEl, pvVal, cVal);
323 crDmpStrF(pRec->pDumper, "(%u, %s)", idx, aBuf);
324}
325
326VBOXDUMPDECL(void) crRecDumpVertAttrV(CR_RECORDER *pRec, CRContext *ctx, const char*pszFormat, va_list pArgList)
327{
328 crDmpStrV(pRec->pDumper, pszFormat, pArgList);
329}
330
331VBOXDUMPDECL(void) crRecDumpVertAttrF(CR_RECORDER *pRec, CRContext *ctx, const char*pszFormat, ...)
332{
333 va_list pArgList;
334 va_start(pArgList, pszFormat);
335 crRecDumpVertAttrV(pRec, ctx, pszFormat, pArgList);
336 va_end(pArgList);
337}
338
339void crRecDumpBuffer(CR_RECORDER *pRec, CRContext *ctx, GLint idRedirFBO, VBOXVR_TEXTURE *pRedirTex)
340{
341 GLenum texTarget = 0;
342 GLint hwBuf = 0, hwDrawBuf = 0;
343 GLint hwTex = 0, hwObjType = 0, hwTexLevel = 0, hwCubeFace = 0;
344 GLint width = 0, height = 0, depth = 0;
345 GLint id = 0;
346 CR_BLITTER_IMG Img = {0};
347 VBOXVR_TEXTURE Tex;
348 int rc;
349
350 pRec->pDispatch->GetIntegerv(GL_DRAW_BUFFER, &hwDrawBuf);
351 pRec->pDispatch->GetIntegerv(GL_FRAMEBUFFER_BINDING, &hwBuf);
352 if (hwBuf)
353 {
354 pRec->pDispatch->GetFramebufferAttachmentParameterivEXT(GL_DRAW_FRAMEBUFFER, hwDrawBuf, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &hwTex);
355 pRec->pDispatch->GetFramebufferAttachmentParameterivEXT(GL_DRAW_FRAMEBUFFER, hwDrawBuf, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &hwObjType);
356 if (hwObjType == GL_TEXTURE)
357 {
358 pRec->pDispatch->GetFramebufferAttachmentParameterivEXT(GL_DRAW_FRAMEBUFFER, hwDrawBuf, GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL, &hwTexLevel);
359 pRec->pDispatch->GetFramebufferAttachmentParameterivEXT(GL_DRAW_FRAMEBUFFER, hwDrawBuf, GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE, &hwCubeFace);
360 if (hwCubeFace)
361 {
362 crWarning("cube face: unsupported");
363 return;
364 }
365
366 if (hwTexLevel)
367 {
368 crWarning("non-zero tex level attached, unsupported");
369 return;
370 }
371 }
372 else
373 {
374 crWarning("unsupported");
375 return;
376 }
377 }
378 else
379 {
380 crWarning("no buffer attached: unsupported");
381 return;
382 }
383
384 if (ctx->framebufferobject.drawFB)
385 {
386 GLuint iColor = (hwDrawBuf - GL_COLOR_ATTACHMENT0_EXT);
387 CRTextureObj *pTobj = (CRTextureObj *)crHashtableSearch(ctx->shared->textureTable, ctx->framebufferobject.drawFB->color[iColor].name);
388 CRTextureLevel *pTl = NULL;
389
390 id = pTobj->id;
391
392 Assert(iColor < RT_ELEMENTS(ctx->framebufferobject.drawFB->color));
393
394 if (!pTobj)
395 {
396 crWarning("no tobj");
397 return;
398 }
399 Assert(pTobj->hwid == hwTex);
400 Assert(pTobj);
401 Assert(ctx->framebufferobject.drawFB->hwid);
402 Assert(ctx->framebufferobject.drawFB->hwid == hwBuf);
403 Assert(ctx->framebufferobject.drawFB->drawbuffer[0] == hwDrawBuf);
404
405 Assert(ctx->framebufferobject.drawFB->color[iColor].level == hwTexLevel);
406 Assert(ctx->framebufferobject.drawFB->color[iColor].type == hwObjType);
407
408 texTarget = pTobj->target;
409
410 Assert(texTarget == GL_TEXTURE_2D);
411
412 pTl = &pTobj->level[0][hwTexLevel];
413
414 rc = CrBltEnter(pRec->pBlitter);
415 if (!RT_SUCCESS(rc))
416 {
417 crWarning("CrBltEnter failed, rc %d", rc);
418 return;
419 }
420
421 pRec->pDispatch->BindTexture(texTarget, hwTex);
422
423 pRec->pDispatch->GetTexLevelParameteriv(texTarget, hwTexLevel, GL_TEXTURE_WIDTH, &width);
424 pRec->pDispatch->GetTexLevelParameteriv(texTarget, hwTexLevel, GL_TEXTURE_HEIGHT, &height);
425 pRec->pDispatch->GetTexLevelParameteriv(texTarget, hwTexLevel, GL_TEXTURE_DEPTH, &depth);
426
427 Assert(width == pTl->width);
428 Assert(height == pTl->height);
429 Assert(depth == pTl->depth);
430
431 pRec->pDispatch->BindTexture(texTarget, 0);
432 }
433 else
434 {
435 Assert(hwBuf == idRedirFBO);
436 if (!pRedirTex)
437 {
438 crWarning("pRedirTex is expected for non-FBO state!");
439 return;
440 }
441
442 Assert(hwTex == pRedirTex->hwid);
443
444 texTarget = pRedirTex->target;
445
446 width = pRedirTex->width;
447 height = pRedirTex->height;
448
449 rc = CrBltEnter(pRec->pBlitter);
450 if (!RT_SUCCESS(rc))
451 {
452 crWarning("CrBltEnter failed, rc %d", rc);
453 return;
454 }
455 }
456
457 Tex.width = width;
458 Tex.height = height;
459 Tex.target = texTarget;
460 Tex.hwid = hwTex;
461
462 rc = CrBltImgGetTex(pRec->pBlitter, &Tex, GL_BGRA, &Img);
463 if (RT_SUCCESS(rc))
464 {
465 crDmpImgF(pRec->pDumper, &Img, "ctx(%d), BUFFER: id(%d) hwid(%d), width(%d), height(%d)", ctx, id, Tex.hwid, width, height);
466
467 if (g_CrDbgDumpAlphaData)
468 {
469 CR_BLITTER_IMG AlphaImg = {0};
470 rc = crRecAlphaImgCreate(&Img, &AlphaImg);
471 if (RT_SUCCESS(rc))
472 {
473 crDmpImgF(pRec->pDumper, &AlphaImg, "Buffer ALPHA Data");
474 crRecAlphaImgDestroy(&AlphaImg);
475 }
476 else
477 {
478 crWarning("crRecAlphaImgCreate failed rc %d", rc);
479 }
480 }
481
482 CrBltImgFree(pRec->pBlitter, &Img);
483 }
484 else
485 {
486 crWarning("CrBltImgGetTex failed, rc %d", rc);
487 }
488
489 CrBltLeave(pRec->pBlitter);
490}
491
492static const char *crRecDumpShaderTypeString(GLenum enmType, CR_DUMPER *pDumper)
493{
494 switch (enmType)
495 {
496 CR_DUMP_MAKE_CASE(GL_VERTEX_SHADER_ARB);
497 CR_DUMP_MAKE_CASE(GL_FRAGMENT_SHADER_ARB);
498 CR_DUMP_MAKE_CASE(GL_GEOMETRY_SHADER_ARB);
499 CR_DUMP_MAKE_CASE_UNKNOWN(enmType, "Unknown Shader Type", pDumper);
500 }
501}
502
503static const char *crRecDumpVarTypeString(GLenum enmType, CR_DUMPER *pDumper)
504{
505 switch (enmType)
506 {
507 CR_DUMP_MAKE_CASE(GL_BYTE);
508 CR_DUMP_MAKE_CASE(GL_UNSIGNED_BYTE);
509 CR_DUMP_MAKE_CASE(GL_SHORT);
510 CR_DUMP_MAKE_CASE(GL_UNSIGNED_SHORT);
511 CR_DUMP_MAKE_CASE(GL_FLOAT);
512 CR_DUMP_MAKE_CASE(GL_DOUBLE);
513 CR_DUMP_MAKE_CASE(GL_FLOAT_VEC2);
514 CR_DUMP_MAKE_CASE(GL_FLOAT_VEC3);
515 CR_DUMP_MAKE_CASE(GL_FLOAT_VEC4);
516 CR_DUMP_MAKE_CASE(GL_INT);
517 CR_DUMP_MAKE_CASE(GL_UNSIGNED_INT);
518 CR_DUMP_MAKE_CASE(GL_INT_VEC2);
519 CR_DUMP_MAKE_CASE(GL_INT_VEC3);
520 CR_DUMP_MAKE_CASE(GL_INT_VEC4);
521 CR_DUMP_MAKE_CASE(GL_BOOL);
522 CR_DUMP_MAKE_CASE(GL_BOOL_VEC2);
523 CR_DUMP_MAKE_CASE(GL_BOOL_VEC3);
524 CR_DUMP_MAKE_CASE(GL_BOOL_VEC4);
525 CR_DUMP_MAKE_CASE(GL_FLOAT_MAT2);
526 CR_DUMP_MAKE_CASE(GL_FLOAT_MAT3);
527 CR_DUMP_MAKE_CASE(GL_FLOAT_MAT4);
528 CR_DUMP_MAKE_CASE(GL_SAMPLER_1D);
529 CR_DUMP_MAKE_CASE(GL_SAMPLER_2D);
530 CR_DUMP_MAKE_CASE(GL_SAMPLER_3D);
531 CR_DUMP_MAKE_CASE(GL_SAMPLER_CUBE);
532 CR_DUMP_MAKE_CASE(GL_SAMPLER_1D_SHADOW);
533 CR_DUMP_MAKE_CASE(GL_SAMPLER_2D_SHADOW);
534 CR_DUMP_MAKE_CASE(GL_SAMPLER_2D_RECT_ARB);
535 CR_DUMP_MAKE_CASE(GL_SAMPLER_2D_RECT_SHADOW_ARB);
536 CR_DUMP_MAKE_CASE(GL_FLOAT_MAT2x3);
537 CR_DUMP_MAKE_CASE(GL_FLOAT_MAT2x4);
538 CR_DUMP_MAKE_CASE(GL_FLOAT_MAT3x2);
539 CR_DUMP_MAKE_CASE(GL_FLOAT_MAT3x4);
540 CR_DUMP_MAKE_CASE(GL_FLOAT_MAT4x2);
541 CR_DUMP_MAKE_CASE(GL_FLOAT_MAT4x3);
542 CR_DUMP_MAKE_CASE_UNKNOWN(enmType, "Unknown Variable Type", pDumper);
543 }
544}
545
546static char *crRecDumpGetLine(char **ppszStr, uint32_t *pcbStr)
547{
548 char *pszStr, *pNewLine;
549 const uint32_t cbStr = *pcbStr;
550
551 if (!cbStr)
552 {
553 /* zero-length string */
554 return NULL;
555 }
556
557 if ((*ppszStr)[cbStr-1] != '\0')
558 {
559 crWarning("string should be null-rerminated, forcing it!");
560 (*ppszStr)[cbStr-1] = '\0';
561 }
562 pszStr = *ppszStr;
563 if (!*pszStr)
564 {
565 *pcbStr = 0;
566 return NULL;
567 }
568
569 if (!(pNewLine = strstr(pszStr, "\n")))
570 {
571 /* the string contains a single line! */
572 *ppszStr += strlen(pszStr);
573 *pcbStr = 0;
574 return pszStr;
575 }
576
577 *pNewLine = '\0';
578 *pcbStr = cbStr - (((uintptr_t)pNewLine) - ((uintptr_t)pszStr)) - 1;
579 Assert((*pcbStr) < UINT32_MAX/2);
580 Assert((*pcbStr) < cbStr);
581 *ppszStr = pNewLine + 1;
582
583 return pszStr;
584}
585
586static void crRecDumpStrByLine(CR_DUMPER *pDumper, char *pszStr, uint32_t cbStr)
587{
588 char *pszCurLine;
589 while ((pszCurLine = crRecDumpGetLine(&pszStr, &cbStr)) != NULL)
590 {
591 crDmpStrF(pDumper, "%s", pszCurLine);
592 }
593}
594
595static DECLCALLBACK(GLuint) crDmpGetHwidShaderCB(void *pvObj)
596{
597 return ((CRGLSLShader*)pvObj)->hwid;
598}
599
600static DECLCALLBACK(GLuint) crDmpGetHwidProgramCB(void *pvObj)
601{
602 return ((CRGLSLProgram*)pvObj)->hwid;
603}
604
605/* Context activation is done by the caller. */
606void crRecDumpLog(CR_RECORDER *pRec, GLint hwid)
607{
608 GLint cbLog = 0;
609 pRec->pDispatch->GetObjectParameterivARB(hwid, GL_OBJECT_INFO_LOG_LENGTH_ARB, &cbLog);
610
611 crDmpStrF(pRec->pDumper, "Log===%d===", hwid);
612
613 if (cbLog > 1)
614 {
615 GLchar *pszLog = (GLchar *) crAlloc(cbLog*sizeof (GLchar));
616
617 pRec->pDispatch->GetInfoLogARB(hwid, cbLog, NULL, pszLog);
618
619 crRecDumpStrByLine(pRec->pDumper, pszLog, cbLog);
620
621 crFree(pszLog);
622 }
623 crDmpStrF(pRec->pDumper, "End Log======");
624}
625
626void crRecDumpShader(CR_RECORDER *pRec, CRContext *ctx, GLint id, GLint hwid)
627{
628 GLint length = 0;
629 GLint type = 0;
630 GLint compileStatus = 0;
631
632#ifndef IN_GUEST
633 CRGLSLShader *pShad;
634
635 if (!id)
636 {
637 unsigned long tstKey = 0;
638 Assert(hwid);
639 pShad = (CRGLSLShader *)crDmpHashtableSearchByHwid(ctx->glsl.shaders, hwid, crDmpGetHwidShaderCB, &tstKey);
640 Assert(pShad);
641 if (!pShad)
642 return;
643 id = pShad->id;
644 Assert(tstKey == id);
645 }
646 else
647 {
648 pShad = (CRGLSLShader *)crHashtableSearch(ctx->glsl.shaders, id);
649 Assert(pShad);
650 if (!pShad)
651 return;
652 }
653
654 if (!hwid)
655 hwid = pShad->hwid;
656
657 Assert(pShad->hwid == hwid);
658 Assert(pShad->id == id);
659#else
660 if (!id)
661 id = hwid;
662 else if (!hwid)
663 hwid = id;
664
665 Assert(id);
666 Assert(hwid);
667 Assert(hwid == id);
668#endif
669
670 pRec->pDispatch->GetObjectParameterivARB(hwid, GL_OBJECT_SUBTYPE_ARB, &type);
671 pRec->pDispatch->GetObjectParameterivARB(hwid, GL_OBJECT_COMPILE_STATUS_ARB, &compileStatus);
672 crDmpStrF(pRec->pDumper, "SHADER ctx(%d) id(%d) hwid(%d) type(%s) status(%d):", ctx->id, id, hwid, crRecDumpShaderTypeString(type, pRec->pDumper), compileStatus);
673
674 crRecDumpLog(pRec, hwid);
675
676 pRec->pDispatch->GetObjectParameterivARB(hwid, GL_OBJECT_SHADER_SOURCE_LENGTH_ARB, &length);
677
678 char *pszSource = (char*)crCalloc(length + 1);
679 if (!pszSource)
680 {
681 crWarning("crCalloc failed");
682 crDmpStrF(pRec->pDumper, "WARNING: crCalloc failed");
683 return;
684 }
685
686 pRec->pDispatch->GetShaderSource(hwid, length, NULL, pszSource);
687 crRecDumpStrByLine(pRec->pDumper, pszSource, length);
688
689 crFree(pszSource);
690
691 crDmpStr(pRec->pDumper, "===END SHADER====");
692}
693
694void crRecDumpProgram(CR_RECORDER *pRec, CRContext *ctx, GLint id, GLint hwid)
695{
696 GLint cShaders = 0, linkStatus = 0;
697 char *source = NULL;
698 CRGLSLProgram *pProg;
699
700 if (!id)
701 {
702 unsigned long tstKey = 0;
703 Assert(hwid);
704 pProg = (CRGLSLProgram*)crDmpHashtableSearchByHwid(ctx->glsl.programs, hwid, crDmpGetHwidProgramCB, &tstKey);
705 Assert(pProg);
706 if (!pProg)
707 return;
708 id = pProg->id;
709 Assert(tstKey == id);
710 }
711 else
712 {
713 pProg = (CRGLSLProgram *) crHashtableSearch(ctx->glsl.programs, id);
714 Assert(pProg);
715 if (!pProg)
716 return;
717 }
718
719 if (!hwid)
720 hwid = pProg->hwid;
721
722 Assert(pProg->hwid == hwid);
723 Assert(pProg->id == id);
724
725 pRec->pDispatch->GetObjectParameterivARB(hwid, GL_OBJECT_ATTACHED_OBJECTS_ARB, &cShaders);
726 pRec->pDispatch->GetObjectParameterivARB(hwid, GL_OBJECT_LINK_STATUS_ARB, &linkStatus);
727
728 crDmpStrF(pRec->pDumper, "PROGRAM ctx(%d) id(%d) hwid(%d) status(%d) shaders(%d):", ctx->id, id, hwid, linkStatus, cShaders);
729
730 crRecDumpLog(pRec, hwid);
731
732 VBoxGLhandleARB *pShaders = (VBoxGLhandleARB*)crCalloc(cShaders * sizeof (*pShaders));
733 if (!pShaders)
734 {
735 crWarning("crCalloc failed");
736 crDmpStrF(pRec->pDumper, "WARNING: crCalloc failed");
737 return;
738 }
739
740 pRec->pDispatch->GetAttachedObjectsARB(hwid, cShaders, NULL, pShaders);
741 for (GLint i = 0; i < cShaders; ++i)
742 {
743 if (pShaders[i])
744 crRecDumpShader(pRec, ctx, 0, pShaders[i]);
745 else
746 crDmpStrF(pRec->pDumper, "WARNING: Shader[%d] is null", i);
747 }
748
749 crFree(pShaders);
750
751 GLsizei cbLog = 0;
752
753 pRec->pDispatch->GetObjectParameterivARB(hwid, GL_OBJECT_INFO_LOG_LENGTH_ARB, &cbLog);
754 if (cbLog)
755 {
756 char *pszLog = (char *)crCalloc(cbLog+1);
757 pRec->pDispatch->GetInfoLogARB(hwid, cbLog, NULL, pszLog);
758 crDmpStrF(pRec->pDumper, "==LOG==");
759 crRecDumpStrByLine(pRec->pDumper, pszLog, cbLog);
760 crDmpStrF(pRec->pDumper, "==Done LOG==");
761 crFree(pszLog);
762 }
763 else
764 {
765 crDmpStrF(pRec->pDumper, "==No LOG==");
766 }
767
768 crDmpStr(pRec->pDumper, "===END PROGRAM====");
769}
770
771void crRecRecompileShader(CR_RECORDER *pRec, CRContext *ctx, GLint id, GLint hwid)
772{
773 GLint length = 0;
774 GLint type = 0;
775 GLint compileStatus = 0;
776 CRGLSLShader *pShad;
777
778 if (!id)
779 {
780 unsigned long tstKey = 0;
781 Assert(hwid);
782 pShad = (CRGLSLShader *)crDmpHashtableSearchByHwid(ctx->glsl.shaders, hwid, crDmpGetHwidShaderCB, &tstKey);
783 Assert(pShad);
784 if (!pShad)
785 return;
786 id = pShad->id;
787 Assert(tstKey == id);
788 }
789 else
790 {
791 pShad = (CRGLSLShader *)crHashtableSearch(ctx->glsl.shaders, id);
792 Assert(pShad);
793 if (!pShad)
794 return;
795 }
796
797 if (!hwid)
798 hwid = pShad->hwid;
799
800 Assert(pShad->hwid == hwid);
801 Assert(pShad->id == id);
802
803 pRec->pDispatch->GetObjectParameterivARB(hwid, GL_OBJECT_SUBTYPE_ARB, &type);
804 pRec->pDispatch->GetObjectParameterivARB(hwid, GL_OBJECT_COMPILE_STATUS_ARB, &compileStatus);
805 crDmpStrF(pRec->pDumper, "==RECOMPILE SHADER ctx(%d) id(%d) hwid(%d) type(%s) status(%d)==", ctx->id, id, hwid, crRecDumpShaderTypeString(type, pRec->pDumper), compileStatus);
806
807 compileStatus = 0;
808 GLenum status;
809 while ((status = pRec->pDispatch->GetError()) != GL_NO_ERROR) {/*Assert(0);*/}
810 pRec->pDispatch->CompileShader(hwid);
811 while ((status = pRec->pDispatch->GetError()) != GL_NO_ERROR) {Assert(0);}
812 pRec->pDispatch->GetObjectParameterivARB(hwid, GL_OBJECT_COMPILE_STATUS_ARB, &compileStatus);
813
814 crDmpStrF(pRec->pDumper, "==Done RECOMPILE SHADER, status(%d)==", compileStatus);
815}
816
817void crRecRecompileProgram(CR_RECORDER *pRec, CRContext *ctx, GLint id, GLint hwid)
818{
819 GLint cShaders = 0, linkStatus = 0;
820 char *source = NULL;
821 CRGLSLProgram *pProg;
822
823 if (!id)
824 {
825 unsigned long tstKey = 0;
826 Assert(hwid);
827 pProg = (CRGLSLProgram*)crDmpHashtableSearchByHwid(ctx->glsl.programs, hwid, crDmpGetHwidProgramCB, &tstKey);
828 Assert(pProg);
829 if (!pProg)
830 return;
831 id = pProg->id;
832 Assert(tstKey == id);
833 }
834 else
835 {
836 pProg = (CRGLSLProgram *) crHashtableSearch(ctx->glsl.programs, id);
837 Assert(pProg);
838 if (!pProg)
839 return;
840 }
841
842 if (!hwid)
843 hwid = pProg->hwid;
844
845 Assert(pProg->hwid == hwid);
846 Assert(pProg->id == id);
847
848 pRec->pDispatch->GetObjectParameterivARB(hwid, GL_OBJECT_ATTACHED_OBJECTS_ARB, &cShaders);
849 pRec->pDispatch->GetObjectParameterivARB(hwid, GL_OBJECT_LINK_STATUS_ARB, &linkStatus);
850
851 crDmpStrF(pRec->pDumper, "==RECOMPILE PROGRAM ctx(%d) id(%d) hwid(%d) status(%d) shaders(%d)==", ctx->id, id, hwid, linkStatus, cShaders);
852
853 VBoxGLhandleARB *pShaders = (VBoxGLhandleARB*)crCalloc(cShaders * sizeof (*pShaders));
854 if (!pShaders)
855 {
856 crWarning("crCalloc failed");
857 crDmpStrF(pRec->pDumper, "WARNING: crCalloc failed");
858 return;
859 }
860
861 pRec->pDispatch->GetAttachedObjectsARB(hwid, cShaders, NULL, pShaders);
862 for (GLint i = 0; i < cShaders; ++i)
863 {
864 crRecRecompileShader(pRec, ctx, 0, pShaders[i]);
865 }
866
867 crFree(pShaders);
868
869 linkStatus = 0;
870 GLenum status;
871 while ((status = pRec->pDispatch->GetError()) != GL_NO_ERROR) {/*Assert(0);*/}
872 pRec->pDispatch->LinkProgram(hwid);
873 while ((status = pRec->pDispatch->GetError()) != GL_NO_ERROR) {Assert(0);}
874 pRec->pDispatch->GetObjectParameterivARB(hwid, GL_OBJECT_LINK_STATUS_ARB, &linkStatus);
875
876 crDmpStrF(pRec->pDumper, "==Done RECOMPILE PROGRAM, status(%d)==", linkStatus);
877}
878
879VBOXDUMPDECL(void) crRecDumpCurrentProgram(CR_RECORDER *pRec, CRContext *ctx)
880{
881 GLint curProgram = 0;
882 pRec->pDispatch->GetIntegerv(GL_CURRENT_PROGRAM, &curProgram);
883 if (curProgram)
884 {
885 Assert(ctx->glsl.activeProgram);
886 if (!ctx->glsl.activeProgram)
887 crWarning("no active program state with active hw program");
888 else
889 Assert(ctx->glsl.activeProgram->hwid == curProgram);
890 crRecDumpProgram(pRec, ctx, 0, curProgram);
891 }
892 else
893 {
894 Assert(!ctx->glsl.activeProgram);
895 crDmpStrF(pRec->pDumper, "--no active program");
896 }
897}
898
899void crRecDumpProgramUniforms(CR_RECORDER *pRec, CRContext *ctx, GLint id, GLint hwid)
900{
901 CRGLSLProgram *pProg;
902
903 if (!id)
904 {
905 unsigned long tstKey = 0;
906 Assert(hwid);
907 pProg = (CRGLSLProgram*)crDmpHashtableSearchByHwid(ctx->glsl.programs, hwid, crDmpGetHwidProgramCB, &tstKey);
908 Assert(pProg);
909 if (!pProg)
910 return;
911 id = pProg->id;
912 Assert(tstKey == id);
913 }
914 else
915 {
916 pProg = (CRGLSLProgram *) crHashtableSearch(ctx->glsl.programs, id);
917 Assert(pProg);
918 if (!pProg)
919 return;
920 }
921
922 if (!hwid)
923 hwid = pProg->hwid;
924
925 Assert(pProg->hwid == hwid);
926 Assert(pProg->id == id);
927
928 GLint maxUniformLen = 0, activeUniforms = 0, i, j, uniformsCount = 0;
929 GLenum type;
930 GLint size, location;
931 GLchar *pszName = NULL;
932 pRec->pDispatch->GetProgramiv(hwid, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxUniformLen);
933 pRec->pDispatch->GetProgramiv(hwid, GL_ACTIVE_UNIFORMS, &activeUniforms);
934
935 if (!maxUniformLen)
936 {
937 if (activeUniforms)
938 {
939 crWarning("activeUniforms (%d), while maxUniformLen is zero", activeUniforms);
940 activeUniforms = 0;
941 }
942 }
943
944 if (activeUniforms>0)
945 {
946 pszName = (GLchar *) crAlloc((maxUniformLen+8)*sizeof(GLchar));
947
948 if (!pszName)
949 {
950 crWarning("crRecDumpProgramUniforms: out of memory");
951 return;
952 }
953 }
954
955 for (i=0; i<activeUniforms; ++i)
956 {
957 pRec->pDispatch->GetActiveUniform(hwid, i, maxUniformLen, NULL, &size, &type, pszName);
958 uniformsCount += size;
959 }
960 Assert(uniformsCount>=activeUniforms);
961
962 if (activeUniforms>0)
963 {
964 GLfloat fdata[16];
965 GLint idata[16];
966 char *pIndexStr=NULL;
967
968 for (i=0; i<activeUniforms; ++i)
969 {
970 bool fPrintBraketsWithName = false;
971 pRec->pDispatch->GetActiveUniform(hwid, i, maxUniformLen, NULL, &size, &type, pszName);
972
973 if (size>1)
974 {
975 pIndexStr = crStrchr(pszName, '[');
976 if (!pIndexStr)
977 {
978 pIndexStr = pszName+crStrlen(pszName);
979 fPrintBraketsWithName = true;
980 }
981 }
982
983 if (fPrintBraketsWithName)
984 {
985 crDmpStrF(pRec->pDumper, "%s %s[%d];", crRecDumpVarTypeString(type, pRec->pDumper), pszName, size);
986 Assert(size > 1);
987 }
988 else
989 crDmpStrF(pRec->pDumper, "%s %s;", crRecDumpVarTypeString(type, pRec->pDumper), pszName);
990
991 GLint uniformTypeSize = crStateGetUniformSize(type);
992 Assert(uniformTypeSize >= 1);
993
994 for (j=0; j<size; ++j)
995 {
996 if (size>1)
997 {
998 sprintf(pIndexStr, "[%i]", j);
999 }
1000 location = pRec->pDispatch->GetUniformLocation(hwid, pszName);
1001
1002 if (crStateIsIntUniform(type))
1003 {
1004 pRec->pDispatch->GetUniformiv(hwid, location, &idata[0]);
1005 switch (uniformTypeSize)
1006 {
1007 case 1:
1008 crDmpStrF(pRec->pDumper, "%s = %d; //location %d", pszName, idata[0], location);
1009 break;
1010 case 2:
1011 crDmpStrF(pRec->pDumper, "%s = {%d, %d}; //location %d", pszName, idata[0], idata[1], location);
1012 break;
1013 case 3:
1014 crDmpStrF(pRec->pDumper, "%s = {%d, %d, %d}; //location %d", pszName, idata[0], idata[1], idata[2], location);
1015 break;
1016 case 4:
1017 crDmpStrF(pRec->pDumper, "%s = {%d, %d, %d, %d}; //location %d", pszName, idata[0], idata[1], idata[2], idata[3], location);
1018 break;
1019 default:
1020 for (GLint k = 0; k < uniformTypeSize; ++k)
1021 {
1022 crDmpStrF(pRec->pDumper, "%s[%d] = %d; //location %d", pszName, k, idata[k], location);
1023 }
1024 break;
1025 }
1026 }
1027 else
1028 {
1029 pRec->pDispatch->GetUniformfv(hwid, location, &fdata[0]);
1030 switch (uniformTypeSize)
1031 {
1032 case 1:
1033 crDmpStrF(pRec->pDumper, "%s = %f; //location %d", pszName, fdata[0], location);
1034 break;
1035 case 2:
1036 crDmpStrF(pRec->pDumper, "%s = {%f, %f}; //location %d", pszName, fdata[0], fdata[1], location);
1037 break;
1038 case 3:
1039 crDmpStrF(pRec->pDumper, "%s = {%f, %f, %f}; //location %d", pszName, fdata[0], fdata[1], fdata[2], location);
1040 break;
1041 case 4:
1042 crDmpStrF(pRec->pDumper, "%s = {%f, %f, %f, %f}; //location %d", pszName, fdata[0], fdata[1], fdata[2], fdata[3], location);
1043 break;
1044 default:
1045 for (GLint k = 0; k < uniformTypeSize; ++k)
1046 {
1047 crDmpStrF(pRec->pDumper, "%s[%d] = %f; //location %d", pszName, k, fdata[k], location);
1048 }
1049 break;
1050 }
1051 }
1052 }
1053 }
1054
1055 crFree(pszName);
1056 }
1057}
1058
1059void crRecDumpProgramAttribs(CR_RECORDER *pRec, CRContext *ctx, GLint id, GLint hwid)
1060{
1061 CRGLSLProgram *pProg;
1062
1063 if (!id)
1064 {
1065 unsigned long tstKey = 0;
1066 Assert(hwid);
1067 pProg = (CRGLSLProgram*)crDmpHashtableSearchByHwid(ctx->glsl.programs, hwid, crDmpGetHwidProgramCB, &tstKey);
1068 Assert(pProg);
1069 if (!pProg)
1070 return;
1071 id = pProg->id;
1072 Assert(tstKey == id);
1073 }
1074 else
1075 {
1076 pProg = (CRGLSLProgram *) crHashtableSearch(ctx->glsl.programs, id);
1077 Assert(pProg);
1078 if (!pProg)
1079 return;
1080 }
1081
1082 if (!hwid)
1083 hwid = pProg->hwid;
1084
1085 Assert(pProg->hwid == hwid);
1086 Assert(pProg->id == id);
1087
1088 GLint maxAttribLen = 0, activeAttrib = 0, i, j, attribCount = 0;
1089 GLenum type;
1090 GLint size, location;
1091 GLchar *pszName = NULL;
1092 pRec->pDispatch->GetProgramiv(hwid, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxAttribLen);
1093 pRec->pDispatch->GetProgramiv(hwid, GL_ACTIVE_ATTRIBUTES, &activeAttrib);
1094
1095 if (!maxAttribLen)
1096 {
1097 if (activeAttrib)
1098 {
1099 crWarning("activeAttrib (%d), while maxAttribLen is zero", activeAttrib);
1100 activeAttrib = 0;
1101 }
1102 }
1103
1104 if (activeAttrib>0)
1105 {
1106 pszName = (GLchar *) crAlloc((maxAttribLen+8)*sizeof(GLchar));
1107
1108 if (!pszName)
1109 {
1110 crWarning("crRecDumpProgramAttrib: out of memory");
1111 return;
1112 }
1113 }
1114
1115 for (i=0; i<activeAttrib; ++i)
1116 {
1117 pRec->pDispatch->GetActiveAttrib(hwid, i, maxAttribLen, NULL, &size, &type, pszName);
1118 attribCount += size;
1119 }
1120 Assert(attribCount>=activeAttrib);
1121
1122 if (activeAttrib>0)
1123 {
1124 GLfloat fdata[16];
1125 GLint idata[16];
1126 char *pIndexStr=NULL;
1127
1128 for (i=0; i<activeAttrib; ++i)
1129 {
1130 bool fPrintBraketsWithName = false;
1131 pRec->pDispatch->GetActiveAttrib(hwid, i, maxAttribLen, NULL, &size, &type, pszName);
1132 GLint arrayBufferBind = 0, arrayEnabled = 0, arraySize = 0, arrayStride = 0, arrayType = 0, arrayNormalized = 0, arrayInteger = 0/*, arrayDivisor = 0*/;
1133
1134 pRec->pDispatch->GetVertexAttribivARB(i, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &arrayBufferBind);
1135 pRec->pDispatch->GetVertexAttribivARB(i, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &arrayEnabled);
1136 pRec->pDispatch->GetVertexAttribivARB(i, GL_VERTEX_ATTRIB_ARRAY_SIZE, &arraySize);
1137 pRec->pDispatch->GetVertexAttribivARB(i, GL_VERTEX_ATTRIB_ARRAY_STRIDE, &arrayStride);
1138 pRec->pDispatch->GetVertexAttribivARB(i, GL_VERTEX_ATTRIB_ARRAY_TYPE, &arrayType);
1139 pRec->pDispatch->GetVertexAttribivARB(i, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, &arrayNormalized);
1140 pRec->pDispatch->GetVertexAttribivARB(i, GL_VERTEX_ATTRIB_ARRAY_INTEGER, &arrayInteger);
1141// pRec->pDispatch->GetVertexAttribivARB(i, GL_VERTEX_ATTRIB_ARRAY_DIVISOR, &arrayDivisor);
1142
1143 if (size>1)
1144 {
1145 pIndexStr = crStrchr(pszName, '[');
1146 if (!pIndexStr)
1147 {
1148 pIndexStr = pszName+crStrlen(pszName);
1149 fPrintBraketsWithName = true;
1150 }
1151 }
1152
1153 if (fPrintBraketsWithName)
1154 {
1155 crDmpStrF(pRec->pDumper, "%s %s[%d];", crRecDumpVarTypeString(type, pRec->pDumper), pszName, size);
1156 Assert(size > 1);
1157 }
1158 else
1159 crDmpStrF(pRec->pDumper, "%s %s;", crRecDumpVarTypeString(type, pRec->pDumper), pszName);
1160
1161 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);
1162
1163 GLint attribTypeSize = crStateGetUniformSize(type);
1164 Assert(attribTypeSize >= 1);
1165
1166 for (j=0; j<size; ++j)
1167 {
1168 if (size>1)
1169 {
1170 sprintf(pIndexStr, "[%i]", j);
1171 }
1172 location = pRec->pDispatch->GetAttribLocation(hwid, pszName);
1173
1174 if (crStateIsIntUniform(type))
1175 {
1176 pRec->pDispatch->GetVertexAttribivARB(location, GL_CURRENT_VERTEX_ATTRIB, &idata[0]);
1177 switch (attribTypeSize)
1178 {
1179 case 1:
1180 crDmpStrF(pRec->pDumper, "%s = %d; //location %d", pszName, idata[0], location);
1181 break;
1182 case 2:
1183 crDmpStrF(pRec->pDumper, "%s = {%d, %d}; //location %d", pszName, idata[0], idata[1], location);
1184 break;
1185 case 3:
1186 crDmpStrF(pRec->pDumper, "%s = {%d, %d, %d}; //location %d", pszName, idata[0], idata[1], idata[2], location);
1187 break;
1188 case 4:
1189 crDmpStrF(pRec->pDumper, "%s = {%d, %d, %d, %d}; //location %d", pszName, idata[0], idata[1], idata[2], idata[3], location);
1190 break;
1191 default:
1192 for (GLint k = 0; k < attribTypeSize; ++k)
1193 {
1194 crDmpStrF(pRec->pDumper, "%s[%d] = %d; //location %d", pszName, k, idata[k], location);
1195 }
1196 break;
1197 }
1198 }
1199 else
1200 {
1201 pRec->pDispatch->GetVertexAttribfvARB(location, GL_CURRENT_VERTEX_ATTRIB, &fdata[0]);
1202 switch (attribTypeSize)
1203 {
1204 case 1:
1205 crDmpStrF(pRec->pDumper, "%s = %f; //location %d", pszName, fdata[0], location);
1206 break;
1207 case 2:
1208 crDmpStrF(pRec->pDumper, "%s = {%f, %f}; //location %d", pszName, fdata[0], fdata[1], location);
1209 break;
1210 case 3:
1211 crDmpStrF(pRec->pDumper, "%s = {%f, %f, %f}; //location %d", pszName, fdata[0], fdata[1], fdata[2], location);
1212 break;
1213 case 4:
1214 crDmpStrF(pRec->pDumper, "%s = {%f, %f, %f, %f}; //location %d", pszName, fdata[0], fdata[1], fdata[2], fdata[3], location);
1215 break;
1216 default:
1217 for (GLint k = 0; k < attribTypeSize; ++k)
1218 {
1219 crDmpStrF(pRec->pDumper, "%s[%d] = %f; //location %d", pszName, k, fdata[k], location);
1220 }
1221 break;
1222 }
1223 }
1224 }
1225 }
1226
1227 crFree(pszName);
1228 }
1229}
1230
1231VBOXDUMPDECL(void) crRecDumpCurrentProgramUniforms(CR_RECORDER *pRec, CRContext *ctx)
1232{
1233 GLint curProgram = 0;
1234 pRec->pDispatch->GetIntegerv(GL_CURRENT_PROGRAM, &curProgram);
1235 if (curProgram)
1236 {
1237 Assert(ctx->glsl.activeProgram);
1238 if (!ctx->glsl.activeProgram)
1239 crWarning("no active program state with active hw program");
1240 else
1241 Assert(ctx->glsl.activeProgram->hwid == curProgram);
1242 crRecDumpProgramUniforms(pRec, ctx, 0, curProgram);
1243 }
1244 else
1245 {
1246 Assert(!ctx->glsl.activeProgram);
1247 crDmpStrF(pRec->pDumper, "--no active program");
1248 }
1249}
1250
1251VBOXDUMPDECL(void) crRecDumpCurrentProgramAttribs(CR_RECORDER *pRec, CRContext *ctx)
1252{
1253 GLint curProgram = 0;
1254 pRec->pDispatch->GetIntegerv(GL_CURRENT_PROGRAM, &curProgram);
1255 if (curProgram)
1256 {
1257 Assert(ctx->glsl.activeProgram);
1258 if (!ctx->glsl.activeProgram)
1259 crWarning("no active program state with active hw program");
1260 else
1261 Assert(ctx->glsl.activeProgram->hwid == curProgram);
1262 crRecDumpProgramAttribs(pRec, ctx, 0, curProgram);
1263 }
1264 else
1265 {
1266 Assert(!ctx->glsl.activeProgram);
1267 crDmpStrF(pRec->pDumper, "--no active program");
1268 }
1269}
1270
1271VBOXDUMPDECL(void) crRecRecompileCurrentProgram(CR_RECORDER *pRec, CRContext *ctx)
1272{
1273 GLint curProgram = 0;
1274 pRec->pDispatch->GetIntegerv(GL_CURRENT_PROGRAM, &curProgram);
1275 if (curProgram)
1276 {
1277 Assert(ctx->glsl.activeProgram);
1278 if (!ctx->glsl.activeProgram)
1279 crWarning("no active program state with active hw program");
1280 else
1281 Assert(ctx->glsl.activeProgram->hwid == curProgram);
1282 crRecRecompileProgram(pRec, ctx, 0, curProgram);
1283 }
1284 else
1285 {
1286 Assert(!ctx->glsl.activeProgram);
1287 crDmpStrF(pRec->pDumper, "--no active program");
1288 }
1289}
1290
1291int crRecAlphaImgCreate(const CR_BLITTER_IMG *pImg, CR_BLITTER_IMG *pAlphaImg)
1292{
1293 if (pImg->enmFormat != GL_RGBA
1294 && pImg->enmFormat != GL_BGRA)
1295 {
1296 crWarning("unsupported format 0x%x", pImg->enmFormat);
1297 return VERR_NOT_IMPLEMENTED;
1298 }
1299
1300 pAlphaImg->bpp = 32;
1301 pAlphaImg->pitch = pImg->width * 4;
1302 pAlphaImg->cbData = pAlphaImg->pitch * pImg->height;
1303 pAlphaImg->enmFormat = GL_BGRA;
1304 pAlphaImg->width = pImg->width;
1305 pAlphaImg->height = pImg->height;
1306
1307 pAlphaImg->pvData = RTMemAlloc(pAlphaImg->cbData);
1308 if (!pAlphaImg->pvData)
1309 {
1310 crWarning("RTMemAlloc failed");
1311 return VERR_NO_MEMORY;
1312 }
1313
1314 uint8_t *pu8SrcBuf = (uint8_t*)pImg->pvData;
1315 uint8_t *pu8DstBuf = (uint8_t*)pAlphaImg->pvData;
1316 for (uint32_t ih = 0; ih < pAlphaImg->height; ++ih)
1317 {
1318 uint32_t *pu32SrcBuf = (uint32_t*)pu8SrcBuf;
1319 uint32_t *pu32DstBuf = (uint32_t*)pu8DstBuf;
1320 for (uint32_t iw = 0; iw < pAlphaImg->width; ++iw)
1321 {
1322 uint8_t alpha = (((*pu32SrcBuf) >> 24) & 0xff);
1323 *pu32DstBuf = (0xff << 24) || (alpha << 16) || (alpha << 8) || alpha;
1324 ++pu32SrcBuf;
1325 ++pu32DstBuf;
1326 }
1327 pu8SrcBuf += pImg->pitch;
1328 pu8DstBuf += pAlphaImg->pitch;
1329 }
1330
1331 return VINF_SUCCESS;
1332}
1333
1334void crRecAlphaImgDestroy(CR_BLITTER_IMG *pImg)
1335{
1336 RTMemFree(pImg->pvData);
1337 pImg->pvData = NULL;
1338}
1339
1340void crRecDumpTextureV(CR_RECORDER *pRec, const VBOXVR_TEXTURE *pTex, const char *pszStr, va_list pArgList)
1341{
1342 CR_BLITTER_IMG Img = {0};
1343 int rc = CrBltEnter(pRec->pBlitter);
1344 if (RT_SUCCESS(rc))
1345 {
1346 rc = CrBltImgGetTex(pRec->pBlitter, pTex, GL_BGRA, &Img);
1347 if (RT_SUCCESS(rc))
1348 {
1349 crDmpImgV(pRec->pDumper, &Img, pszStr, pArgList);
1350 if (g_CrDbgDumpAlphaData)
1351 {
1352 CR_BLITTER_IMG AlphaImg = {0};
1353 rc = crRecAlphaImgCreate(&Img, &AlphaImg);
1354 if (RT_SUCCESS(rc))
1355 {
1356 crDmpImgF(pRec->pDumper, &AlphaImg, "Texture ALPHA Data");
1357 crRecAlphaImgDestroy(&AlphaImg);
1358 }
1359 else
1360 {
1361 crWarning("crRecAlphaImgCreate failed rc %d", rc);
1362 }
1363 }
1364 CrBltImgFree(pRec->pBlitter, &Img);
1365 }
1366 else
1367 {
1368 crWarning("CrBltImgGetTex failed, rc %d", rc);
1369 }
1370 CrBltLeave(pRec->pBlitter);
1371 }
1372 else
1373 {
1374 crWarning("CrBltEnter failed, rc %d", rc);
1375 }
1376}
1377
1378void crRecDumpTextureF(CR_RECORDER *pRec, const VBOXVR_TEXTURE *pTex, const char *pszStr, ...)
1379{
1380 va_list pArgList;
1381 va_start(pArgList, pszStr);
1382 crRecDumpTextureV(pRec, pTex, pszStr, pArgList);
1383 va_end(pArgList);
1384}
1385
1386void crRecDumpTextureByIdV(CR_RECORDER *pRec, CRContext *ctx, GLint id, const char *pszStr, va_list pArgList)
1387{
1388 CRTextureObj *pTobj = (CRTextureObj *)crHashtableSearch(ctx->shared->textureTable, id);
1389 if (!pTobj)
1390 {
1391 crWarning("no texture of id %d", id);
1392 return;
1393 }
1394
1395 CRTextureLevel *pTl = &pTobj->level[0][0 /* level */];
1396 VBOXVR_TEXTURE Tex;
1397 Tex.width = pTl->width;
1398 Tex.height = pTl->height;
1399 Tex.target = pTobj->target;
1400 Assert(Tex.target == GL_TEXTURE_2D);
1401 Tex.hwid = pTobj->hwid;
1402 if (!Tex.hwid)
1403 {
1404 crWarning("no texture hwid of id %d", id);
1405 return;
1406 }
1407
1408 crRecDumpTextureV(pRec, &Tex, pszStr, pArgList);
1409}
1410
1411void crRecDumpTextureByIdF(CR_RECORDER *pRec, CRContext *ctx, GLint id, const char *pszStr, ...)
1412{
1413 va_list pArgList;
1414 va_start(pArgList, pszStr);
1415 crRecDumpTextureByIdV(pRec, ctx, id, pszStr, pArgList);
1416 va_end(pArgList);
1417}
1418
1419void crRecDumpTextures(CR_RECORDER *pRec, CRContext *ctx)
1420{
1421 GLint maxUnits = 0;
1422 GLint curTexUnit = 0;
1423 GLint restoreTexUnit = 0;
1424 GLint curProgram = 0;
1425 int i;
1426
1427 pRec->pDispatch->GetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxUnits);
1428 maxUnits = RT_MIN(CR_MAX_TEXTURE_UNITS, maxUnits);
1429
1430 pRec->pDispatch->GetIntegerv(GL_CURRENT_PROGRAM, &curProgram);
1431 Assert(curProgram);
1432 Assert(ctx->glsl.activeProgram && ctx->glsl.activeProgram->hwid == curProgram);
1433
1434 Assert(maxUnits);
1435 pRec->pDispatch->GetIntegerv(GL_ACTIVE_TEXTURE, &curTexUnit);
1436 restoreTexUnit = curTexUnit;
1437 Assert(curTexUnit >= GL_TEXTURE0);
1438 Assert(curTexUnit < GL_TEXTURE0 + maxUnits);
1439
1440 Assert(ctx->texture.curTextureUnit == restoreTexUnit - GL_TEXTURE0);
1441
1442 for (i = 0; i < maxUnits; ++i)
1443 {
1444 GLboolean enabled1D;
1445 GLboolean enabled2D;
1446 GLboolean enabled3D;
1447 GLboolean enabledCubeMap;
1448 GLboolean enabledRect;
1449 CRTextureUnit *tu = &ctx->texture.unit[i];
1450
1451 if (i > 1)
1452 break;
1453
1454 if (curTexUnit != i + GL_TEXTURE0)
1455 {
1456 pRec->pDispatch->ActiveTextureARB(i + GL_TEXTURE0);
1457 curTexUnit = i + GL_TEXTURE0;
1458 }
1459
1460 enabled1D = pRec->pDispatch->IsEnabled(GL_TEXTURE_1D);
1461 enabled2D = pRec->pDispatch->IsEnabled(GL_TEXTURE_2D);
1462 enabled3D = pRec->pDispatch->IsEnabled(GL_TEXTURE_3D);
1463 enabledCubeMap = pRec->pDispatch->IsEnabled(GL_TEXTURE_CUBE_MAP_ARB);
1464 enabledRect = pRec->pDispatch->IsEnabled(GL_TEXTURE_RECTANGLE_NV);
1465
1466 Assert(enabled1D == tu->enabled1D);
1467 Assert(enabled2D == tu->enabled2D);
1468 Assert(enabled3D == tu->enabled3D);
1469 Assert(enabledCubeMap == tu->enabledCubeMap);
1470 Assert(enabledRect == tu->enabledRect);
1471
1472 if (enabled1D)
1473 {
1474 crWarning("GL_TEXTURE_1D: unsupported");
1475 }
1476
1477// if (enabled2D)
1478 {
1479 GLint hwTex = 0;
1480 VBOXVR_TEXTURE Tex;
1481
1482 GLint width = 0, height = 0, depth = 0;
1483 CRTextureObj *pTobj = tu->currentTexture2D;
1484
1485 pRec->pDispatch->GetIntegerv(GL_TEXTURE_BINDING_2D, &hwTex);
1486 if (hwTex)
1487 {
1488 CRTextureLevel *pTl = &pTobj->level[0][0 /* level */];
1489 Assert(pTobj
1490 && pTobj->hwid == hwTex);
1491
1492 pRec->pDispatch->GetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width);
1493 pRec->pDispatch->GetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &height);
1494 pRec->pDispatch->GetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_DEPTH, &depth);
1495
1496 Assert(width == pTl->width);
1497 Assert(height == pTl->height);
1498 Assert(depth == pTl->depth);
1499
1500 Tex.width = width;
1501 Tex.height = height;
1502 Tex.target = GL_TEXTURE_2D;
1503 Tex.hwid = hwTex;
1504
1505 if (g_CrDbgDumpRecTexInfo)
1506 {
1507 crRecDumpTexParam(pRec, ctx, GL_TEXTURE_2D);
1508 crRecDumpTexEnv(pRec, ctx);
1509 crRecDumpTexGen(pRec, ctx);
1510 }
1511
1512 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);
1513 }
1514// else
1515// {
1516// Assert(!pTobj || pTobj->hwid == 0);
1517// crWarning("no TEXTURE_2D bound!");
1518// }
1519 }
1520#if 0
1521 if (enabled3D)
1522 {
1523 crWarning("GL_TEXTURE_3D: unsupported");
1524 }
1525
1526 if (enabledCubeMap)
1527 {
1528 crWarning("GL_TEXTURE_CUBE_MAP_ARB: unsupported");
1529 }
1530
1531// if (enabledRect)
1532 {
1533 GLint hwTex = 0;
1534 CR_BLITTER_IMG Img = {0};
1535 VBOXVR_TEXTURE Tex;
1536
1537 GLint width = 0, height = 0, depth = 0;
1538 CRTextureObj *pTobj = tu->currentTextureRect;
1539
1540 pRec->pDispatch->GetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_NV, &hwTex);
1541 if (hwTex)
1542 {
1543 CRTextureLevel *pTl = &pTobj->level[0][0 /* level */];
1544 Assert(pTobj
1545 && pTobj->hwid == hwTex);
1546
1547 pRec->pDispatch->GetTexLevelParameteriv(GL_TEXTURE_RECTANGLE_NV, 0, GL_TEXTURE_WIDTH, &width);
1548 pRec->pDispatch->GetTexLevelParameteriv(GL_TEXTURE_RECTANGLE_NV, 0, GL_TEXTURE_HEIGHT, &height);
1549 pRec->pDispatch->GetTexLevelParameteriv(GL_TEXTURE_RECTANGLE_NV, 0, GL_TEXTURE_DEPTH, &depth);
1550
1551 Assert(width == pTl->width);
1552 Assert(height == pTl->height);
1553 Assert(depth == pTl->depth);
1554
1555 Tex.width = width;
1556 Tex.height = height;
1557 Tex.target = GL_TEXTURE_RECTANGLE_NV;
1558 Tex.hwid = hwTex;
1559
1560 rc = CrBltEnter(pRec->pBlitter);
1561 if (RT_SUCCESS(rc))
1562 {
1563 rc = CrBltImgGetTex(pRec->pBlitter, &Tex, GL_BGRA, &Img);
1564 if (RT_SUCCESS(rc))
1565 {
1566 crDmpImgF(pRec->pDumper, &Img, "Unit %d: TEXTURE_RECTANGLE data", i);
1567 CrBltImgFree(pRec->pBlitter, &Img);
1568 }
1569 else
1570 {
1571 crWarning("CrBltImgGetTex failed, rc %d", rc);
1572 }
1573 CrBltLeave(pRec->pBlitter);
1574 }
1575 else
1576 {
1577 crWarning("CrBltEnter failed, rc %d", rc);
1578 }
1579 }
1580// else
1581// {
1582// Assert(!pTobj || pTobj->hwid == 0);
1583// crWarning("no TEXTURE_RECTANGLE bound!");
1584// }
1585 }
1586#endif
1587 }
1588
1589 if (curTexUnit != restoreTexUnit)
1590 {
1591 pRec->pDispatch->ActiveTextureARB(restoreTexUnit);
1592 curTexUnit = restoreTexUnit;
1593 }
1594}
1595
1596#ifdef RT_OS_WINDOWS
1597static void crDmpPrint(const char* szString, ...)
1598{
1599 char szBuffer[4096] = {0};
1600 va_list pArgList;
1601 va_start(pArgList, szString);
1602 RTStrPrintfV(szBuffer, sizeof (szBuffer), szString, pArgList);
1603 va_end(pArgList);
1604
1605 OutputDebugStringA(szBuffer);
1606}
1607
1608static void crDmpPrintDmlCmd(const char* pszDesc, const char* pszCmd)
1609{
1610 crDmpPrint("<?dml?><exec cmd=\"%s\">%s</exec>, ( %s )\n", pszCmd, pszDesc, pszCmd);
1611}
1612
1613void crDmpPrintDumpDmlCmd(const char* pszDesc, const void *pvData, uint32_t width, uint32_t height, uint32_t bpp, uint32_t pitch)
1614{
1615 char Cmd[1024];
1616 sprintf(Cmd, "!vbvdbg.ms 0x%p 0n%d 0n%d 0n%d 0n%d", pvData, width, height, bpp, pitch);
1617 crDmpPrintDmlCmd(pszDesc, Cmd);
1618}
1619
1620DECLCALLBACK(void) crDmpDumpImgDmlBreak(struct CR_DUMPER * pDumper, CR_BLITTER_IMG *pImg, const char*pszEntryDesc)
1621{
1622 crDmpPrintDumpDmlCmd(pszEntryDesc, pImg->pvData, pImg->width, pImg->height, pImg->bpp, pImg->pitch);
1623 RT_BREAKPOINT();
1624}
1625
1626DECLCALLBACK(void) crDmpDumpStrDbgPrint(struct CR_DUMPER * pDumper, const char*pszStr)
1627{
1628 crDmpPrint("%s\n", pszStr);
1629}
1630#endif
1631
1632static void crDmpHtmlDumpStrExact(struct CR_HTML_DUMPER * pDumper, const char *pszStr)
1633{
1634 fprintf(pDumper->pFile, "%s", pszStr);
1635 fflush(pDumper->pFile);
1636}
1637
1638static DECLCALLBACK(void) crDmpHtmlDumpStr(struct CR_DUMPER * pDumper, const char*pszStr)
1639{
1640 CR_HTML_DUMPER * pHtmlDumper = (CR_HTML_DUMPER*)pDumper;
1641 fprintf(pHtmlDumper->pFile, "<pre>%s</pre>\n", pszStr);
1642 fflush(pHtmlDumper->pFile);
1643}
1644
1645static DECLCALLBACK(void) crDmpHtmlDumpImg(struct CR_DUMPER * pDumper, CR_BLITTER_IMG *pImg, const char*pszEntryDesc)
1646{
1647 CR_HTML_DUMPER * pHtmlDumper = (CR_HTML_DUMPER*)pDumper;
1648 char szBuffer[4096] = {0};
1649 size_t cbWritten = RTStrPrintf(szBuffer, sizeof(szBuffer), "%s/", pHtmlDumper->pszDir);
1650 char *pszFileName = szBuffer + cbWritten;
1651 RTStrPrintf(pszFileName, sizeof(szBuffer) - cbWritten, "img%d.bmp", ++pHtmlDumper->cImg);
1652 crDmpImgBmp(pImg, szBuffer);
1653 fprintf(pHtmlDumper->pFile, "<a href=\"%s\"><pre>%s</pre><img src=\"%s\" alt=\"%s\" width=\"150\" height=\"100\" /></a><br>\n",
1654 pszFileName, pszEntryDesc, pszFileName, pszEntryDesc);
1655 fflush(pHtmlDumper->pFile);
1656}
1657
1658static void crDmpHtmlPrintHeader(struct CR_HTML_DUMPER * pDumper)
1659{
1660 fprintf(pDumper->pFile, "<html><body>\n");
1661 fflush(pDumper->pFile);
1662}
1663
1664static void crDmpHtmlPrintFooter(struct CR_HTML_DUMPER * pDumper)
1665{
1666 fprintf(pDumper->pFile, "</body></html>\n");
1667 fflush(pDumper->pFile);
1668}
1669
1670DECLEXPORT(bool) crDmpHtmlIsInited(struct CR_HTML_DUMPER * pDumper)
1671{
1672 return !!pDumper->pFile;
1673}
1674
1675DECLEXPORT(void) crDmpHtmlTerm(struct CR_HTML_DUMPER * pDumper)
1676{
1677 crDmpHtmlPrintFooter(pDumper);
1678 fclose (pDumper->pFile);
1679 pDumper->pFile = NULL;
1680}
1681
1682DECLEXPORT(int) crDmpHtmlInit(struct CR_HTML_DUMPER * pDumper, const char *pszDir, const char *pszFile)
1683{
1684 int rc = VERR_NO_MEMORY;
1685 pDumper->Base.pfnDumpImg = crDmpHtmlDumpImg;
1686 pDumper->Base.pfnDumpStr = crDmpHtmlDumpStr;
1687 pDumper->cImg = 0;
1688 pDumper->pszDir = crStrdup(pszDir);
1689 if (pDumper->pszDir)
1690 {
1691 pDumper->pszFile = crStrdup(pszFile);
1692 if (pDumper->pszFile)
1693 {
1694 char szBuffer[4096] = {0};
1695 RTStrPrintf(szBuffer, sizeof(szBuffer), "%s/%s", pszDir, pszFile);
1696
1697 pDumper->pszFile = crStrdup(pszFile);
1698 pDumper->pFile = fopen(szBuffer, "w");
1699 if (pDumper->pFile)
1700 {
1701 crDmpHtmlPrintHeader(pDumper);
1702 return VINF_SUCCESS;
1703 }
1704 else
1705 {
1706 crWarning("open failed");
1707 rc = VERR_OPEN_FAILED;
1708 }
1709 crFree((void*)pDumper->pszFile);
1710 }
1711 else
1712 {
1713 crWarning("open failed");
1714 }
1715 crFree((void*)pDumper->pszDir);
1716 }
1717 else
1718 {
1719 crWarning("open failed");
1720 }
1721 return rc;
1722}
1723
1724DECLEXPORT(int) crDmpHtmlInitV(struct CR_HTML_DUMPER * pDumper, const char *pszDir, const char *pszFile, va_list pArgList)
1725{
1726 char szBuffer[4096] = {0};
1727 vsprintf_s(szBuffer, sizeof (szBuffer), pszFile, pArgList);
1728 return crDmpHtmlInit(pDumper, pszDir, szBuffer);
1729}
1730
1731DECLEXPORT(int) crDmpHtmlInitF(struct CR_HTML_DUMPER * pDumper, const char *pszDir, const char *pszFile, ...)
1732{
1733 int rc;
1734 va_list pArgList;
1735 va_start(pArgList, pszFile);
1736 rc = crDmpHtmlInitV(pDumper, pszDir, pszFile, pArgList);
1737 va_end(pArgList);
1738 return rc;
1739}
1740
1741#endif
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette