summaryrefslogtreecommitdiffstats
path: root/src/VBox/HostServices/SharedOpenGL/crserverlib/server.h
blob: 2b3c2318f71914aedaaaa7cb515b198f5d02b12e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
/* Copyright (c) 2001, Stanford University
 * All rights reserved.
 *
 * See the file LICENSE.txt for information on redistributing this software.
 */

#ifndef CR_SERVER_H
#define CR_SERVER_H

#include "cr_protocol.h"
#include "cr_glstate.h"
#include "spu_dispatch_table.h"

#include "state/cr_currentpointers.h"

#include "cr_server.h"
#include <cr_htable.h>
#include <cr_compositor.h>

#ifdef VBOX_WITH_CRHGSMI
# include <VBoxVideo.h>

#include <iprt/cdefs.h>

RT_C_DECLS_BEGIN

extern uint8_t* g_pvVRamBase;
extern uint32_t g_cbVRam;
extern PPDMLED g_pLed;
extern HCRHGSMICMDCOMPLETION g_hCrHgsmiCompletion;
extern PFNCRHGSMICMDCOMPLETION g_pfnCrHgsmiCompletion;

#define VBOXCRHGSMI_PTR(_off, _t) ((_t*)(g_pvVRamBase + (_off)))
#define VBOXCRHGSMI_PTR_SAFE(_off, _cb, _t) ((_t*)crServerCrHgsmiPtrGet(_off, _cb))

DECLINLINE(void*) crServerCrHgsmiPtrGet(VBOXVIDEOOFFSET offBuffer, uint32_t cbBuffer)
{
    return ((offBuffer) + (cbBuffer) <= g_cbVRam ? VBOXCRHGSMI_PTR(offBuffer, void) : NULL);
}

DECLINLINE(void) crServerCrHgsmiCmdComplete(struct VBOXVDMACMD_CHROMIUM_CMD *pCmd, int cmdProcessingRc)
{
    g_pfnCrHgsmiCompletion(g_hCrHgsmiCompletion, pCmd, cmdProcessingRc);
}

#define VBOXCRHGSMI_CMD_COMPLETE(_pData, _rc) do { \
        CRVBOXHGSMI_CMDDATA_ASSERT_ISSET(_pData); \
        CRVBOXHGSMI_CMDDATA_RC(_pData, _rc); \
        if (CRVBOXHGSMI_CMDDATA_IS_HGSMICMD(_pData)) { \
            Assert(CRVBOXHGSMI_CMDDATA_IS_HGSMICMD(_pData)); \
            crServerCrHgsmiCmdComplete((_pData)->pHgsmiCmd, VINF_SUCCESS); \
        } \
    } while (0)

#define VBOXCRHGSMI_CMD_CHECK_COMPLETE(_pData, _rc) do { \
        if (CRVBOXHGSMI_CMDDATA_IS_SET(_pData)) {\
            VBOXCRHGSMI_CMD_COMPLETE(_pData, _rc); \
        } \
    } while (0)

#endif

/*
 * This is the base number for window and context IDs
 */
#define MAGIC_OFFSET 5000

extern CRServer cr_server;

/* Semaphore wait queue node */
typedef struct _wqnode {
    RunQueue *q;
    struct _wqnode *next;
} wqnode;

typedef struct {
    GLuint count;
    GLuint num_waiting;
    RunQueue **waiting;
} CRServerBarrier;

typedef struct {
    GLuint count;
    wqnode *waiting, *tail;
} CRServerSemaphore;

typedef struct {
    GLuint id;
    GLint projParamStart;
    GLfloat projMat[16];  /* projection matrix, accumulated via calls to */
                        /* glProgramLocalParameterARB, glProgramParameterNV */
} CRServerProgram;

void crServerSetVBoxConfiguration();
void crServerSetVBoxConfigurationHGCM();
void crServerInitDispatch(void);
void crServerReturnValue( const void *payload, unsigned int payload_len );
void crServerWriteback(void);
int crServerRecv( CRConnection *conn, CRMessage *msg, unsigned int len );
void crServerSerializeRemoteStreams(void);
void crServerAddToRunQueue( CRClient *client );
void crServerDeleteClient( CRClient *client );


void crServerApplyBaseProjection( const CRmatrix *baseProj );
void crServerApplyViewMatrix( const CRmatrix *view );
void crServerSetOutputBounds( const CRMuralInfo *mural, int extNum );
void crServerComputeViewportBounds( const CRViewportState *v, CRMuralInfo *mural );

GLboolean crServerInitializeBucketing(CRMuralInfo *mural);

void crComputeOverlapGeom(double *quads, int nquad, CRPoly ***res);
void crComputeKnockoutGeom(double *quads, int nquad, int my_quad_idx, CRPoly **res);

int crServerGetCurrentEye(void);

GLboolean crServerClientInBeginEnd(const CRClient *client);

GLint crServerDispatchCreateContextEx(const char *dpyName, GLint visualBits, GLint shareCtx, GLint preloadCtxID, int32_t internalID);
GLint crServerDispatchWindowCreateEx(const char *dpyName, GLint visBits, GLint preloadWinID);
GLint crServerMuralInit(CRMuralInfo *mural, GLboolean fGuestWindow, GLint visBits, GLint preloadWinID);
void crServerMuralTerm(CRMuralInfo *mural);
GLboolean crServerMuralSize(CRMuralInfo *mural, GLint width, GLint height);
void crServerMuralPosition(CRMuralInfo *mural, GLint x, GLint y);
void crServerMuralVisibleRegion( CRMuralInfo *mural, GLint cRects, const GLint *pRects );
void crServerMuralShow( CRMuralInfo *mural, GLint state );

GLint crServerGenerateID(GLint *pCounter);

GLint crServerSPUWindowID(GLint serverWindow);

GLuint crServerTranslateProgramID(GLuint id);

CRMuralInfo * crServerGetDummyMural(GLint visualBits);

void crServerCheckMuralGeometry(CRMuralInfo *mural);
void crServerCheckAllMuralGeometry(CRMuralInfo *pMI);
GLboolean crServerSupportRedirMuralFBO(void);

void crVBoxServerMuralFbResizeBegin(HCR_FRAMEBUFFER hFb);
void crVBoxServerMuralFbResizeEnd(HCR_FRAMEBUFFER hFb);

void crVBoxServerNotifyEvent(int32_t idScreen, uint32_t uEvent, void* pvData, uint32_t cbData);

void crServerRedirMuralFbClear(CRMuralInfo *mural);

void crServerWindowReparent(CRMuralInfo *pMural);

void crServerRedirMuralFBO(CRMuralInfo *mural, bool fEnabled);
void crServerDeleteMuralFBO(CRMuralInfo *mural);
void crServerPresentFBO(CRMuralInfo *mural);
GLboolean crServerIsRedirectedToFBO();
GLint crServerMuralFBOIdxFromBufferName(CRMuralInfo *mural, GLenum buffer);
void crServerMuralFBOSwapBuffers(CRMuralInfo *mural);

HCR_FRAMEBUFFER CrPMgrFbGetFirstEnabled();
HCR_FRAMEBUFFER CrPMgrFbGetNextEnabled(HCR_FRAMEBUFFER hFb);
HCR_FRAMEBUFFER CrPMgrFbGetFirstInitialized();
HCR_FRAMEBUFFER CrPMgrFbGetNextInitialized(HCR_FRAMEBUFFER hFb);

int CrFbRegionsClear(HCR_FRAMEBUFFER hFb);


#define CR_SERVER_FBO_BB_IDX(_mural) ((_mural)->iBbBuffer)
#define CR_SERVER_FBO_FB_IDX(_mural) (((_mural)->iBbBuffer + 1) % ((_mural)->cBuffers))
/* returns a valid index to be used for negative _idx, i.e. for GL_NONE cases */
//#define CR_SERVER_FBO_ADJUST_IDX(_mural, _idx) ((_idx) >= 0 ? (_idx) : CR_SERVER_FBO_BB_IDX(_mural))
/* just a helper that uses CR_SERVER_FBO_ADJUST_IDX for getting mural's FBO id for buffer index*/
//#define CR_SERVER_FBO_FOR_IDX(_mural, _idx) ((_mural)->aidFBOs[CR_SERVER_FBO_ADJUST_IDX((_mural), (_idx))])
//#define CR_SERVER_FBO_TEX_FOR_IDX(_mural, _idx) ((_mural)->aidColorTexs[CR_SERVER_FBO_ADJUST_IDX((_mural), (_idx))])
#define CR_SERVER_FBO_FOR_IDX(_mural, _idx) ((_idx) >= 0 ? (_mural)->aidFBOs[(_idx)] : 0)
#define CR_SERVER_FBO_TEX_FOR_IDX(_mural, _idx) ((_idx) >= 0 ? (_mural)->aidColorTexs[(_idx)] : 0)

int32_t crVBoxServerInternalClientRead(CRClient *pClient, uint8_t *pBuffer, uint32_t *pcbBuffer);

void crServerPerformMakeCurrent( CRMuralInfo *mural, CRContextInfo *ctxInfo );

PCR_BLITTER crServerVBoxBlitterGet();
PCR_BLITTER crServerVBoxBlitterGetInitialized();

DECLINLINE(void) crServerVBoxBlitterWinInit(CR_BLITTER_WINDOW *win, CRMuralInfo *mural)
{
    win->Base.id = mural->spuWindow;
    win->Base.visualBits = mural->CreateInfo.realVisualBits;
    win->width = mural->width;
    win->height = mural->height;
}

DECLINLINE(void) crServerVBoxBlitterCtxInit(CR_BLITTER_CONTEXT *ctx, CRContextInfo *ctxInfo)
{
    ctx->Base.id = ctxInfo->SpuContext;
    if (ctx->Base.id < 0)
        ctx->Base.id = cr_server.MainContextInfo.SpuContext;
    ctx->Base.visualBits = cr_server.curClient->currentCtxInfo->CreateInfo.realVisualBits;
}

/* display worker thread.
 * see comments for CR_SERVER_RPW struct definition in cr_server.h */
DECLINLINE(void) crServerXchgI8(int8_t *pu8Val1, int8_t *pu8Val2)
{
    int8_t tmp;
    tmp = *pu8Val1;
    *pu8Val1 = *pu8Val2;
    *pu8Val2 = tmp;
}

#ifdef DEBUG
# define CR_GLERR_CHECK(_op) do { \
        GLenum status; \
        while ((status = cr_server.head_spu->dispatch_table.GetError()) != GL_NO_ERROR) {/*Assert(0);*/} \
        _op \
        while ((status = cr_server.head_spu->dispatch_table.GetError()) != GL_NO_ERROR) {Assert(0);} \
    } while (0)
#else
# define CR_GLERR_CHECK(_op) do { \
        _op \
    } while (0)
#endif

#ifdef DEBUG_misha
# define CR_SERVER_RPW_DEBUG
#endif
/* *
 * _name : Draw, Submitted, Worker, Gpu
 */

#ifdef CR_SERVER_RPW_DEBUG
# define crServerRpwEntryDbgVerify(_pE) crServerRpwEntryDbgDoVerify(_pE)
#else
# define crServerRpwEntryDbgVerify(_pE) do {} while (0)
#endif


#define CR_SERVER_RPW_ENTRY_TEX_IS_VALID(_pEntry, _name) ((_pEntry)->iTex##_name > 0)

#define CR_SERVER_RPW_ENTRY_TEX_INVALIDATE(_pEntry, _name) do { \
        crServerRpwEntryDbgVerify(_pEntry); \
        Assert(CR_SERVER_RPW_ENTRY_TEX_IS_VALID(_pEntry, _name)); \
        (_pEntry)->iTex##_name = -(_pEntry)->iTex##_name; \
        crServerRpwEntryDbgVerify(_pEntry); \
    } while (0)

#define CR_SERVER_RPW_ENTRY_TEX_PROMOTE(_pEntry, _fromName, _toName) do { \
        crServerRpwEntryDbgVerify(_pEntry); \
        Assert(CR_SERVER_RPW_ENTRY_TEX_IS_VALID(_pEntry, _fromName)); \
        Assert(!CR_SERVER_RPW_ENTRY_TEX_IS_VALID(_pEntry, _toName)); \
        crServerXchgI8(&(_pEntry)->iTex##_fromName, &(_pEntry)->iTex##_toName); \
        crServerRpwEntryDbgVerify(_pEntry); \
    } while (0)

#define CR_SERVER_RPW_ENTRY_TEX_XCHG_VALID(_pEntry, _fromName, _toName) do { \
        crServerRpwEntryDbgVerify(_pEntry); \
        Assert(CR_SERVER_RPW_ENTRY_TEX_IS_VALID(_pEntry, _fromName)); \
        Assert(CR_SERVER_RPW_ENTRY_TEX_IS_VALID(_pEntry, _toName)); \
        crServerXchgI8(&(_pEntry)->iTex##_fromName, &(_pEntry)->iTex##_toName); \
        Assert(CR_SERVER_RPW_ENTRY_TEX_IS_VALID(_pEntry, _fromName)); \
        Assert(CR_SERVER_RPW_ENTRY_TEX_IS_VALID(_pEntry, _toName)); \
        crServerRpwEntryDbgVerify(_pEntry); \
    } while (0)


#define CR_SERVER_RPW_ENTRY_TEX_PROMOTE_KEEPVALID(_pEntry, _fromName, _toName) do { \
        crServerRpwEntryDbgVerify(_pEntry); \
        Assert(CR_SERVER_RPW_ENTRY_TEX_IS_VALID(_pEntry, _fromName)); \
        Assert(!CR_SERVER_RPW_ENTRY_TEX_IS_VALID(_pEntry, _toName)); \
        crServerXchgI8(&(_pEntry)->iTex##_fromName, &(_pEntry)->iTex##_toName); \
        (_pEntry)->iTex##_fromName = -(_pEntry)->iTex##_fromName; \
        Assert(CR_SERVER_RPW_ENTRY_TEX_IS_VALID(_pEntry, _fromName)); \
        Assert(CR_SERVER_RPW_ENTRY_TEX_IS_VALID(_pEntry, _toName)); \
        crServerRpwEntryDbgVerify(_pEntry); \
    } while (0)

#define CR_SERVER_RPW_ENTRY_TEX(_pEntry, _name) ((_pEntry)->aidWorkerTexs[(_pEntry)->iTex##_name - 1])

#define CR_SERVER_RPW_ENTRY_PBO_NEXT_ID(_i) (((_i) + 1) % 2)
#define CR_SERVER_RPW_ENTRY_PBO_IS_ACTIVE(_pEntry) ((_pEntry)->iCurPBO >= 0)
#define CR_SERVER_RPW_ENTRY_PBO_CUR(_pEntry) ((_pEntry)->aidPBOs[(_pEntry)->iCurPBO])
#define CR_SERVER_RPW_ENTRY_PBO_COMPLETED(_pEntry) ((_pEntry)->aidPBOs[CR_SERVER_RPW_ENTRY_PBO_NEXT_ID((_pEntry)->iCurPBO)])
#define CR_SERVER_RPW_ENTRY_PBO_FLIP(_pEntry) do { \
        (_pEntry)->iCurPBO = CR_SERVER_RPW_ENTRY_PBO_NEXT_ID((_pEntry)->iCurPBO); \
    } while (0)

#ifdef CR_SERVER_RPW_DEBUG
DECLINLINE(void) crServerRpwEntryDbgDoVerify(CR_SERVER_RPW_ENTRY *pEntry)
{
    int tstMask = 0;
    int8_t iVal;
    Assert(CR_SERVER_RPW_ENTRY_TEX_IS_VALID(pEntry, Draw));

#define CR_VERVER_RPW_ENTRY_DBG_CHECKVAL(_v) do { \
        iVal = RT_ABS(_v); \
        Assert(iVal > 0); \
        Assert(iVal < 5); \
        Assert(!(tstMask & (1 << iVal))); \
        tstMask |= (1 << iVal); \
    } while (0)

    CR_VERVER_RPW_ENTRY_DBG_CHECKVAL(pEntry->iTexDraw);
    CR_VERVER_RPW_ENTRY_DBG_CHECKVAL(pEntry->iTexSubmitted);
    CR_VERVER_RPW_ENTRY_DBG_CHECKVAL(pEntry->iTexWorker);
    CR_VERVER_RPW_ENTRY_DBG_CHECKVAL(pEntry->iTexGpu);
    Assert(tstMask == 0x1E);
}
#endif

DECLINLINE(bool) crServerRpwIsInitialized(const CR_SERVER_RPW *pWorker)
{
    return !!pWorker->ctxId;
}
int crServerRpwInit(CR_SERVER_RPW *pWorker);
int crServerRpwTerm(CR_SERVER_RPW *pWorker);
DECLINLINE(bool) crServerRpwEntryIsInitialized(const CR_SERVER_RPW_ENTRY *pEntry)
{
    return !!pEntry->pfnData;
}
int crServerRpwEntryInit(CR_SERVER_RPW *pWorker, CR_SERVER_RPW_ENTRY *pEntry, uint32_t width, uint32_t height, PFNCR_SERVER_RPW_DATA pfnData);
int crServerRpwEntryCleanup(CR_SERVER_RPW *pWorker, CR_SERVER_RPW_ENTRY *pEntry);
int crServerRpwEntryResize(CR_SERVER_RPW *pWorker, CR_SERVER_RPW_ENTRY *pEntry, uint32_t width, uint32_t height);
int crServerRpwEntrySubmit(CR_SERVER_RPW *pWorker, CR_SERVER_RPW_ENTRY *pEntry);
int crServerRpwEntryWaitComplete(CR_SERVER_RPW *pWorker, CR_SERVER_RPW_ENTRY *pEntry);
int crServerRpwEntryCancel(CR_SERVER_RPW *pWorker, CR_SERVER_RPW_ENTRY *pEntry);
DECLINLINE(void) crServerRpwEntryDrawSettingsToTex(const CR_SERVER_RPW_ENTRY *pEntry, VBOXVR_TEXTURE *pTex)
{
    pTex->width = pEntry->Size.cx;
    pTex->height = pEntry->Size.cy;
    pTex->target = GL_TEXTURE_2D;
    Assert(CR_SERVER_RPW_ENTRY_TEX_IS_VALID(pEntry, Draw));
    pTex->hwid = CR_SERVER_RPW_ENTRY_TEX(pEntry, Draw);
}
/**/

typedef struct CR_SERVER_CTX_SWITCH
{
    GLuint idDrawFBO, idReadFBO;
    CRContext *pNewCtx;
    CRContext *pOldCtx;
} CR_SERVER_CTX_SWITCH;

DECLINLINE(void) crServerCtxSwitchPrepare(CR_SERVER_CTX_SWITCH *pData, CRContext *pNewCtx)
{
    CRMuralInfo *pCurrentMural = cr_server.currentMural;
    CRContextInfo *pCurCtxInfo = cr_server.currentCtxInfo;
    GLuint idDrawFBO, idReadFBO;
    CRContext *pCurCtx = pCurCtxInfo ? pCurCtxInfo->pContext : NULL;

    CRASSERT(pCurCtx == crStateGetCurrent());

    if (pCurrentMural)
    {
        idDrawFBO = CR_SERVER_FBO_FOR_IDX(pCurrentMural, pCurrentMural->iCurDrawBuffer);
        idReadFBO = CR_SERVER_FBO_FOR_IDX(pCurrentMural, pCurrentMural->iCurReadBuffer);
    }
    else
    {
        idDrawFBO = 0;
        idReadFBO = 0;
    }

    crStateSwitchPrepare(pNewCtx, pCurCtx, idDrawFBO, idReadFBO);

    pData->idDrawFBO = idDrawFBO;
    pData->idReadFBO = idReadFBO;
    pData->pNewCtx = pNewCtx;
    pData->pOldCtx = pCurCtx;
}

DECLINLINE(void) crServerCtxSwitchPostprocess(CR_SERVER_CTX_SWITCH *pData)
{
    crStateSwitchPostprocess(pData->pOldCtx, pData->pNewCtx, pData->idDrawFBO, pData->idReadFBO);
}

void crServerInitTmpCtxDispatch();

typedef struct CR_FBMAP
{
    uint8_t Map[(CR_MAX_GUEST_MONITORS+7)/8];
} CR_FBMAP;

DECLINLINE(void) CrFBmInit(CR_FBMAP *pMap)
{
    memset(pMap, 0, sizeof (*pMap));
}

DECLINLINE(bool) CrFBmIsSet(CR_FBMAP *pMap, uint32_t i)
{
    return ASMBitTest(&pMap->Map, i);
}

DECLINLINE(void) CrFBmSet(CR_FBMAP *pMap, uint32_t i)
{
    ASMBitSet(&pMap->Map, i);
}

DECLINLINE(void) CrFBmSetAtomic(CR_FBMAP *pMap, uint32_t i)
{
    ASMAtomicBitSet(&pMap->Map, i);
}

DECLINLINE(void) CrFBmClear(CR_FBMAP *pMap, uint32_t i)
{
    ASMBitClear(&pMap->Map, i);
}

/*helper function that calls CrFbUpdateBegin for all enabled framebuffers */
int CrPMgrHlpGlblUpdateBegin(CR_FBMAP *pMap);
/*helper function that calls CrFbUpdateEnd for all framebuffers being updated */
void CrPMgrHlpGlblUpdateEnd(CR_FBMAP *pMap);
HCR_FRAMEBUFFER CrPMgrFbGetFirstEnabled();
HCR_FRAMEBUFFER CrPMgrFbGetNextEnabled(HCR_FRAMEBUFFER hFb);
HCR_FRAMEBUFFER CrPMgrFbGetEnabled(uint32_t idFb);
HCR_FRAMEBUFFER CrPMgrFbGetEnabledForScreen(uint32_t idScreen);
int CrPMgrModeVrdp(bool fEnable);
int CrPMgrModeRootVr(bool fEnable);
int CrPMgrModeWinVisible(bool fEnable);
int CrPMgrRootVrUpdate();
int CrPMgrViewportUpdate(uint32_t idScreen);
int CrPMgrScreenChanged(uint32_t idScreen);
int CrPMgrResize(const struct VBVAINFOSCREEN *pScreen, void *pvVRAM, const uint32_t *pTargetMap);
int CrPMgrSaveState(PSSMHANDLE pSSM);
int CrPMgrLoadState(PSSMHANDLE pSSM, uint32_t version);
HCR_FRAMEBUFFER CrPMgrFbGet(uint32_t idScreen);
int CrPMgrClearRegionsGlobal();
/*cleanup stuff*/


int CrPMgrInit();
void CrPMgrTerm();
int CrPMgrDisable();
int CrPMgrEnable();

typedef DECLCALLBACKPTR(bool, PFNCR_FRAMEBUFFER_ENTRIES_VISITOR_CB)(HCR_FRAMEBUFFER hFb, HCR_FRAMEBUFFER_ENTRY hEntry, void *pvContext);

bool CrFbHas3DData(HCR_FRAMEBUFFER hFb);
void CrFbVisitCreatedEntries(HCR_FRAMEBUFFER hFb, PFNCR_FRAMEBUFFER_ENTRIES_VISITOR_CB pfnVisitorCb, void *pvContext);
int CrFbResize(HCR_FRAMEBUFFER hFb, const struct VBVAINFOSCREEN * pScreen, void *pvVRAM);
int CrFbBltGetContentsEx(HCR_FRAMEBUFFER hFb, const RTRECTSIZE *pSrcRectSize, const RTRECT *pDstRect, uint32_t cRects, const RTRECT *pRects, CR_BLITTER_IMG *pImg);
bool CrFbIsEnabled(HCR_FRAMEBUFFER hFb);
int CrFbEntryCreateForTexId(HCR_FRAMEBUFFER hFb, GLuint idTex, uint32_t fFlags, HCR_FRAMEBUFFER_ENTRY *phEntry);
int CrFbEntryCreateForTexData(HCR_FRAMEBUFFER hFb, struct CR_TEXDATA *pTex, uint32_t fFlags, HCR_FRAMEBUFFER_ENTRY *phEntry);
void CrFbEntryAddRef(HCR_FRAMEBUFFER hFb, HCR_FRAMEBUFFER_ENTRY hEntry);
void CrFbEntryRelease(HCR_FRAMEBUFFER hFb, HCR_FRAMEBUFFER_ENTRY hEntry);
const struct VBVAINFOSCREEN* CrFbGetScreenInfo(HCR_FRAMEBUFFER hFb);
void* CrFbGetVRAM(HCR_FRAMEBUFFER hFb);
const struct VBOXVR_SCR_COMPOSITOR* CrFbGetCompositor(HCR_FRAMEBUFFER hFb);
const struct VBOXVR_SCR_COMPOSITOR_ENTRY* CrFbEntryGetCompositorEntry(HCR_FRAMEBUFFER_ENTRY hEntry);

/* start doing modifications to the framebuffer */
int CrFbUpdateBegin(HCR_FRAMEBUFFER hFb);
/*below commands can only be used in Framebuffer update mode, i.e. after the CrFbUpdateBegin succeeded */
int CrFbEntryRegions(HCR_FRAMEBUFFER hFb, HCR_FRAMEBUFFER_ENTRY hEntry);

/* complete doing modifications to the framebuffer */
void CrFbUpdateEnd(HCR_FRAMEBUFFER hFb);

int CrFbEntryRegionsAdd(HCR_FRAMEBUFFER hFb, HCR_FRAMEBUFFER_ENTRY pEntry, const RTPOINT *pPos, uint32_t cRegions, const RTRECT *paRegions, bool fPosRelated);
int CrFbEntryRegionsSet(HCR_FRAMEBUFFER hFb, HCR_FRAMEBUFFER_ENTRY pEntry, const RTPOINT *pPos, uint32_t cRegions, const RTRECT *paRegions, bool fPosRelated);

int CrFbEntryTexDataUpdate(HCR_FRAMEBUFFER hFb, HCR_FRAMEBUFFER_ENTRY pEntry, struct CR_TEXDATA *pTex);

CRHTABLE_HANDLE CrFbDDataAllocSlot(HCR_FRAMEBUFFER hFb);

typedef DECLCALLBACKPTR(void, PFNCR_FRAMEBUFFER_SLOT_RELEASE_CB)(HCR_FRAMEBUFFER hFb, HCR_FRAMEBUFFER_ENTRY hEntry, void *pvContext);

void CrFbDDataReleaseSlot(HCR_FRAMEBUFFER hFb, CRHTABLE_HANDLE hSlot, PFNCR_FRAMEBUFFER_SLOT_RELEASE_CB pfnReleaseCb, void *pvContext);
int CrFbDDataEntryPut(HCR_FRAMEBUFFER_ENTRY hEntry, CRHTABLE_HANDLE hSlot, void *pvData);
void* CrFbDDataEntryClear(HCR_FRAMEBUFFER_ENTRY hEntry, CRHTABLE_HANDLE hSlot);
void* CrFbDDataEntryGet(HCR_FRAMEBUFFER_ENTRY hEntry, CRHTABLE_HANDLE hSlot);

CR_TEXDATA* CrFbTexDataCreate(const VBOXVR_TEXTURE *pTex);
void CrFbTexDataInit(CR_TEXDATA* pFbTex, const VBOXVR_TEXTURE *pTex, PFNCRTEXDATA_RELEASED pfnTextureReleased);

int8_t crVBoxServerCrCmdBltProcess(VBOXCMDVBVA_BLT_HDR const RT_UNTRUSTED_VOLATILE_GUEST *pCmd, uint32_t cbCmd);
int8_t crVBoxServerCrCmdClrFillProcess(VBOXCMDVBVA_CLRFILL_HDR const RT_UNTRUSTED_VOLATILE_GUEST *pCmd, uint32_t cbCmd);
int8_t crVBoxServerCrCmdFlipProcess(VBOXCMDVBVA_FLIP const RT_UNTRUSTED_VOLATILE_GUEST *pFlip, uint32_t cbCmd);


int32_t crVBoxServerClientGet(uint32_t u32ClientID, CRClient **ppClient);

int crServerPendSaveState(PSSMHANDLE pSSM);
int crServerPendLoadState(PSSMHANDLE pSSM, uint32_t u32Version);

//#define VBOX_WITH_CRSERVER_DUMPER
#ifdef VBOX_WITH_CRSERVER_DUMPER
void crServerDumpCheckTerm();
int crServerDumpCheckInit();
void crServerDumpBuffer(int idx);
void crServerDumpTextures();
void crServerDumpTexture(const VBOXVR_TEXTURE *pTex);
void crServerDumpShader(GLint id);
void crServerDumpProgram(GLint id);
void crServerDumpCurrentProgram();
void crServerDumpRecompileDumpCurrentProgram();
void crServerRecompileCurrentProgram();
void crServerDumpCurrentProgramUniforms();
void crServerDumpCurrentProgramAttribs();
void crServerDumpFramesCheck();
void crServerDumpState();
void crServerDumpDrawel(const char*pszFormat, ...);
void crServerDumpDrawelv(GLuint idx, const char*pszElFormat, uint32_t cbEl, const void *pvVal, uint32_t cVal);

extern int64_t g_CrDbgDumpPid;
extern unsigned long g_CrDbgDumpEnabled;
extern unsigned long g_CrDbgDumpDraw;
extern unsigned long g_CrDbgDumpDrawFramesSettings;
extern unsigned long g_CrDbgDumpDrawFramesAppliedSettings;
extern unsigned long g_CrDbgDumpDrawFramesCount;

extern uint32_t g_CrDbgDumpVertattrFixupOn;

bool crServerDumpFilterDmp(unsigned long event, CR_DUMPER *pDumper);
bool crServerDumpFilterOpEnter(unsigned long event, CR_DUMPER *pDumper);
void crServerDumpFilterOpLeave(unsigned long event, CR_DUMPER *pDumper);

//#define CR_SERVER_DUMP_MASK_OP                  0x0000fffc
//#define CR_SERVER_DUMP_OFF_OP                   2
//
//#define CR_SERVER_DUMP_MASK_DIR                 0x00000003
//#define CR_SERVER_DUMP_OFF_DIR                  0
//
//#define CR_SERVER_DUMP_MASK_DMP                 0xffff0000
//#define CR_SERVER_DUMP_OFF_DMP                  16
//
//#define CR_SERVER_DUMP_MAKE_OP(_v)              (1 << ((_v) + CR_SERVER_DUMP_OFF_OP))
//#define CR_SERVER_DUMP_MAKE_DIR(_v)             (1 << ((_v) + CR_SERVER_DUMP_OFF_DIR))
//#define CR_SERVER_DUMP_MAKE_DMP(_v)             (1 << ((_v) + CR_SERVER_DUMP_OFF_DMP))
//
//#define CR_SERVER_DUMP_GET_OP(_v)               ((_v) & CR_SERVER_DUMP_MASK_OP)
//#define CR_SERVER_DUMP_GET_DMP(_v)              ((_v) & CR_SERVER_DUMP_MASK_DMP)
//#define CR_SERVER_DUMP_GET_DIR(_v)              ((_v) & CR_SERVER_DUMP_MASK_DIR)
//
//#define CR_SERVER_DUMP_ISANY_OP(_v1, _v2)       (!!(CR_SERVER_DUMP_GET_OP(_v1) & CR_SERVER_DUMP_GET_OP(_v2)))
//#define CR_SERVER_DUMP_ISANY_DIR(_v1, _v2)      (!!(CR_SERVER_DUMP_GET_DIR(_v1) & CR_SERVER_DUMP_GET_DIR(_v2)))
//#define CR_SERVER_DUMP_ISANY_DMP(_v1, _v2)      (!!(CR_SERVER_DUMP_GET_DMP(_v1) & CR_SERVER_DUMP_GET_DMP(_v2)))
//
//#define CR_SERVER_DUMP_ISANY_OP(_v1, _v2)       ((CR_SERVER_DUMP_GET_OP(_v1) & CR_SERVER_DUMP_GET_OP(_v2)) == CR_SERVER_DUMP_GET_OP(_v2))
//#define CR_SERVER_DUMP_ISANY_DIR(_v1, _v2)      ((CR_SERVER_DUMP_GET_DIR(_v1) & CR_SERVER_DUMP_GET_DIR(_v2)) == CR_SERVER_DUMP_GET_DIR(_v2))
//#define CR_SERVER_DUMP_ISANY_DMP(_v1, _v2)      ((CR_SERVER_DUMP_GET_DMP(_v1) & CR_SERVER_DUMP_GET_DMP(_v2)) == CR_SERVER_DUMP_GET_DMP(_v2))
//
//#define CR_SERVER_DUMP_F_DIR_ENTER              CR_SERVER_DUMP_MAKE_DIR(0)
//#define CR_SERVER_DUMP_F_DIR_LEAVE              CR_SERVER_DUMP_MAKE_DIR(1)
//
//#define CR_SERVER_DUMP_F_OP_DRAW                CR_SERVER_DUMP_MAKE_OP(0)
//#define CR_SERVER_DUMP_F_OP_SWAPBUFFERS         CR_SERVER_DUMP_MAKE_OP(1)
//#define CR_SERVER_DUMP_F_OP_LINK_PROGRAM        CR_SERVER_DUMP_MAKE_OP(2)
//#define CR_SERVER_DUMP_F_OP_COMPILE_PROGRAM     CR_SERVER_DUMP_MAKE_OP(3)
//
//#define CR_SERVER_DUMP_F_DMP_BUFF               CR_SERVER_DUMP_MAKE_DMP(0)
//#define CR_SERVER_DUMP_F_DMP_TEX                CR_SERVER_DUMP_MAKE_DMP(0)
//#define CR_SERVER_DUMP_F_DMP_PROGRAM            CR_SERVER_DUMP_MAKE_DMP(0)
//#define CR_SERVER_DUMP_F_DMP_PROGRAM_UNIFORMS   CR_SERVER_DUMP_MAKE_DMP(0)
//#define CR_SERVER_DUMP_F_DMP_STATE              CR_SERVER_DUMP_MAKE_DMP(0)
//
//#define CR_SERVER_DUMP_GET_OP(_v)               ((_v) & CR_SERVER_DUMP_MASK_OP)
//#define CR_SERVER_DUMP_GET_DMP(_v)               ((_v) & CR_SERVER_DUMP_MASK_DMP)
//#define CR_SERVER_DUMP_GET_DIR(_v)               ((_v) & CR_SERVER_DUMP_MASK_DIR)

#define CR_SERVER_DUMP_F_DRAW_BUFF_ENTER        0x00000001
#define CR_SERVER_DUMP_F_DRAW_BUFF_LEAVE        0x00000002
#define CR_SERVER_DUMP_F_DRAW_STATE_ENTER       0x00000004
#define CR_SERVER_DUMP_F_DRAW_STATE_LEAVE       0x00000008
#define CR_SERVER_DUMP_F_DRAW_TEX_ENTER         0x00000010
#define CR_SERVER_DUMP_F_DRAW_TEX_LEAVE         0x00000020
#define CR_SERVER_DUMP_F_DRAW_PROGRAM_ENTER     0x00000040
#define CR_SERVER_DUMP_F_DRAW_PROGRAM_LEAVE     0x00000080
#define CR_SERVER_DUMP_F_DRAW_PROGRAM_UNIFORMS_ENTER     0x00000100
#define CR_SERVER_DUMP_F_DRAW_PROGRAM_UNIFORMS_LEAVE     0x00000200
#define CR_SERVER_DUMP_F_DRAW_PROGRAM_ATTRIBS_ENTER      0x00000400
#define CR_SERVER_DUMP_F_DRAW_PROGRAM_ATTRIBS_LEAVE      0x00000800

#define CR_SERVER_DUMP_F_DRAW_ENTER_ALL (CR_SERVER_DUMP_F_DRAW_BUFF_ENTER \
        | CR_SERVER_DUMP_F_DRAW_TEX_ENTER \
        | CR_SERVER_DUMP_F_DRAW_PROGRAM_ENTER \
        | CR_SERVER_DUMP_F_DRAW_PROGRAM_UNIFORMS_ENTER \
        | CR_SERVER_DUMP_F_DRAW_STATE_ENTER \
        | CR_SERVER_DUMP_F_DRAW_PROGRAM_ATTRIBS_ENTER)

#define CR_SERVER_DUMP_F_DRAW_LEAVE_ALL (CR_SERVER_DUMP_F_DRAW_BUFF_LEAVE \
        | CR_SERVER_DUMP_F_DRAW_TEX_LEAVE \
        | CR_SERVER_DUMP_F_DRAW_PROGRAM_LEAVE \
        | CR_SERVER_DUMP_F_DRAW_PROGRAM_UNIFORMS_LEAVE \
        | CR_SERVER_DUMP_F_DRAW_STATE_LEAVE \
        | CR_SERVER_DUMP_F_DRAW_PROGRAM_ATTRIBS_LEAVE)

#define CR_SERVER_DUMP_F_DRAW_ALL (CR_SERVER_DUMP_F_DRAW_ENTER_ALL | CR_SERVER_DUMP_F_DRAW_LEAVE_ALL)

#define CR_SERVER_DUMP_F_SWAPBUFFERS_ENTER      0x00010000
#define CR_SERVER_DUMP_F_SWAPBUFFERS_LEAVE      0x00020000
#define CR_SERVER_DUMP_F_TEXPRESENT             0x00040000
#define CR_SERVER_DUMP_F_DRAWEL                 0x00100000
#define CR_SERVER_DUMP_F_COMPILE_SHADER         0x01000000
#define CR_SERVER_DUMP_F_SHADER_SOURCE          0x02000000
#define CR_SERVER_DUMP_F_LINK_PROGRAM           0x04000000


#define CR_SERVER_DUMP_DEFAULT_FILTER_OP(_ev) ((((_ev) & g_CrDbgDumpDraw) != 0) \
        || ((_ev) == CR_SERVER_DUMP_F_SWAPBUFFERS_ENTER && g_CrDbgDumpDrawFramesCount))

#define CR_SERVER_DUMP_DEFAULT_FILTER_DMP(_ev) (((_ev) & g_CrDbgDumpDraw) != 0)

#define CR_SERVER_DUMP_FILTER_OP(_ev, _pDumper) (g_CrDbgDumpEnabled \
                && (!g_CrDbgDumpPid \
                        || (g_CrDbgDumpPid > 0 && ((uint64_t)g_CrDbgDumpPid) == cr_server.curClient->pid) \
                        || (g_CrDbgDumpPid < 0 && ((uint64_t)(-g_CrDbgDumpPid)) != cr_server.curClient->pid)) \
                && crServerDumpFilterOpEnter((_ev), (_pDumper)))
#define CR_SERVER_DUMP_FILTER_DMP(_ev, _pDumper) (crServerDumpFilterDmp((_ev), (_pDumper)))

#define CR_SERVER_DUMP_DRAW_ENTER() do { \
            if (!CR_SERVER_DUMP_FILTER_OP(CR_SERVER_DUMP_F_DRAW_ENTER_ALL, cr_server.Recorder.pDumper)) break; \
            crServerDumpCheckInit(); \
            crDmpStrF(cr_server.Recorder.pDumper, "==ENTER[%d] %s==", (uint32_t)cr_server.curClient->pid, __FUNCTION__); \
            if (CR_SERVER_DUMP_FILTER_DMP(CR_SERVER_DUMP_F_DRAW_STATE_ENTER, cr_server.Recorder.pDumper)) { crServerDumpState(); } \
            if (CR_SERVER_DUMP_FILTER_DMP(CR_SERVER_DUMP_F_DRAW_PROGRAM_ENTER, cr_server.Recorder.pDumper)) { crServerDumpCurrentProgram(); } \
            if (CR_SERVER_DUMP_FILTER_DMP(CR_SERVER_DUMP_F_DRAW_PROGRAM_UNIFORMS_ENTER, cr_server.Recorder.pDumper)) { crServerDumpCurrentProgramUniforms(); } \
            if (CR_SERVER_DUMP_FILTER_DMP(CR_SERVER_DUMP_F_DRAW_PROGRAM_ATTRIBS_ENTER, cr_server.Recorder.pDumper)) { crServerDumpCurrentProgramAttribs(); } \
            if (CR_SERVER_DUMP_FILTER_DMP(CR_SERVER_DUMP_F_DRAW_TEX_ENTER, cr_server.Recorder.pDumper)) { crServerDumpTextures(); } \
            if (CR_SERVER_DUMP_FILTER_DMP(CR_SERVER_DUMP_F_DRAW_BUFF_ENTER, cr_server.Recorder.pDumper)) { crServerDumpBuffer(-1); } \
            crDmpStrF(cr_server.Recorder.pDumper, "==Done ENTER[%d] %s==", (uint32_t)cr_server.curClient->pid, __FUNCTION__); \
            crServerDumpFilterOpLeave(CR_SERVER_DUMP_F_DRAW_ENTER_ALL, cr_server.Recorder.pDumper); \
        } while (0)

#define CR_SERVER_DUMP_DRAW_LEAVE() do { \
            if (!CR_SERVER_DUMP_FILTER_OP(CR_SERVER_DUMP_F_DRAW_LEAVE_ALL, cr_server.Recorder.pDumper)) break; \
            crServerDumpCheckInit(); \
            crDmpStrF(cr_server.Recorder.pDumper, "==LEAVE[%d] %s==", (uint32_t)cr_server.curClient->pid, __FUNCTION__); \
            if (CR_SERVER_DUMP_FILTER_DMP(CR_SERVER_DUMP_F_DRAW_TEX_LEAVE, cr_server.Recorder.pDumper)) { crServerDumpTextures(); } \
            if (CR_SERVER_DUMP_FILTER_DMP(CR_SERVER_DUMP_F_DRAW_BUFF_LEAVE, cr_server.Recorder.pDumper)) { crServerDumpBuffer(-1); } \
            if (CR_SERVER_DUMP_FILTER_DMP(CR_SERVER_DUMP_F_DRAW_PROGRAM_UNIFORMS_LEAVE, cr_server.Recorder.pDumper)) { crServerDumpCurrentProgramUniforms(); } \
            if (CR_SERVER_DUMP_FILTER_DMP(CR_SERVER_DUMP_F_DRAW_PROGRAM_ATTRIBS_LEAVE, cr_server.Recorder.pDumper)) { crServerDumpCurrentProgramAttribs(); } \
            if (CR_SERVER_DUMP_FILTER_DMP(CR_SERVER_DUMP_F_DRAW_PROGRAM_LEAVE, cr_server.Recorder.pDumper)) { crServerDumpCurrentProgram(); } \
            if (CR_SERVER_DUMP_FILTER_DMP(CR_SERVER_DUMP_F_DRAW_STATE_LEAVE, cr_server.Recorder.pDumper)) { crServerDumpState(); } \
            crDmpStrF(cr_server.Recorder.pDumper, "==Done LEAVE[%d] %s==", (uint32_t)cr_server.curClient->pid, __FUNCTION__); \
            crServerDumpFilterOpLeave(CR_SERVER_DUMP_F_DRAW_LEAVE_ALL, cr_server.Recorder.pDumper); \
        } while (0)

#define CR_SERVER_DUMP_COMPILE_SHADER(_id) do { \
            if (!CR_SERVER_DUMP_FILTER_OP(CR_SERVER_DUMP_F_COMPILE_SHADER, cr_server.Recorder.pDumper)) break; \
            crServerDumpCheckInit(); \
            crDmpStrF(cr_server.Recorder.pDumper, "==[%d] %s", (uint32_t)cr_server.curClient->pid, __FUNCTION__); \
            crServerDumpShader((_id)); \
            crDmpStrF(cr_server.Recorder.pDumper, "==Done[%d] %s==", (uint32_t)cr_server.curClient->pid, __FUNCTION__); \
            crServerDumpFilterOpLeave(CR_SERVER_DUMP_F_COMPILE_SHADER, cr_server.Recorder.pDumper); \
        } while (0)

#define CR_SERVER_DUMP_SHADER_SOURCE(_id) do { \
            if (!CR_SERVER_DUMP_FILTER_OP(CR_SERVER_DUMP_F_SHADER_SOURCE, cr_server.Recorder.pDumper)) break; \
            crServerDumpCheckInit(); \
            crDmpStrF(cr_server.Recorder.pDumper, "==[%d] %s==", (uint32_t)cr_server.curClient->pid, __FUNCTION__); \
            crServerDumpShader((_id)); \
            crDmpStrF(cr_server.Recorder.pDumper, "==Done[%d] %s==", (uint32_t)cr_server.curClient->pid, __FUNCTION__); \
            crServerDumpFilterOpLeave(CR_SERVER_DUMP_F_SHADER_SOURCE, cr_server.Recorder.pDumper); \
        } while (0)

#define CR_SERVER_DUMP_LINK_PROGRAM(_id) do { \
            if (!CR_SERVER_DUMP_FILTER_OP(CR_SERVER_DUMP_F_LINK_PROGRAM, cr_server.Recorder.pDumper)) break; \
            crServerDumpCheckInit(); \
            crDmpStrF(cr_server.Recorder.pDumper, "==[%d] %s==", (uint32_t)cr_server.curClient->pid, __FUNCTION__); \
            crServerDumpProgram((_id)); \
            crDmpStrF(cr_server.Recorder.pDumper, "==Done[%d] %s==", (uint32_t)cr_server.curClient->pid, __FUNCTION__); \
            crServerDumpFilterOpLeave(CR_SERVER_DUMP_F_LINK_PROGRAM, cr_server.Recorder.pDumper); \
        } while (0)

#define CR_SERVER_DUMP_SWAPBUFFERS_ENTER() do { \
            if (!CR_SERVER_DUMP_FILTER_OP(CR_SERVER_DUMP_F_SWAPBUFFERS_ENTER, cr_server.Recorder.pDumper)) break; \
            crServerDumpCheckInit(); \
            crDmpStrF(cr_server.Recorder.pDumper, "==ENTER[%d] %s==", (uint32_t)cr_server.curClient->pid, __FUNCTION__); \
            if (CR_SERVER_DUMP_FILTER_DMP(CR_SERVER_DUMP_F_SWAPBUFFERS_ENTER, cr_server.Recorder.pDumper)) { crServerDumpBuffer(CR_SERVER_FBO_BB_IDX(cr_server.currentMural)); } \
            if (g_CrDbgDumpDrawFramesCount) { crServerDumpFramesCheck(); } \
            crDmpStrF(cr_server.Recorder.pDumper, "==Done ENTER[%d] %s==", (uint32_t)cr_server.curClient->pid, __FUNCTION__); \
            crServerDumpFilterOpLeave(CR_SERVER_DUMP_F_SWAPBUFFERS_ENTER, cr_server.Recorder.pDumper); \
        } while (0)

#define CR_SERVER_DUMP_TEXPRESENT(_pTex) do { \
            if (!CR_SERVER_DUMP_FILTER_OP(CR_SERVER_DUMP_F_TEXPRESENT, cr_server.Recorder.pDumper)) break; \
            crServerDumpCheckInit(); \
            crDmpStrF(cr_server.Recorder.pDumper, "==[%d] %s==", (uint32_t)cr_server.curClient->pid, __FUNCTION__); \
            crServerDumpTexture((_pTex)); \
            crServerDumpFilterOpLeave(CR_SERVER_DUMP_F_TEXPRESENT, cr_server.Recorder.pDumper); \
        } while (0)

#define CR_SERVER_DUMP_SWAPBUFFERS_LEAVE() do { \
            if (!CR_SERVER_DUMP_FILTER_OP(CR_SERVER_DUMP_F_SWAPBUFFERS_LEAVE, cr_server.Recorder.pDumper)) break; \
            crDmpStrF(cr_server.Recorder.pDumper, "==LEAVE[%d] %s==", (uint32_t)cr_server.curClient->pid, __FUNCTION__); \
            crServerDumpCheckInit(); \
            crDmpStrF(cr_server.Recorder.pDumper, "==Done LEAVE[%d] %s==", (uint32_t)cr_server.curClient->pid, __FUNCTION__); \
            crServerDumpFilterOpLeave(CR_SERVER_DUMP_F_SWAPBUFFERS_LEAVE, cr_server.Recorder.pDumper); \
        } while (0)

#define CR_SERVER_DUMP_DRAWEL_F(_msg) do { \
        if (!CR_SERVER_DUMP_FILTER_OP(CR_SERVER_DUMP_F_DRAWEL, cr_server.Recorder.pDumper)) break; \
        crServerDumpCheckInit(); \
        crDmpStrF(cr_server.Recorder.pDumper, "==[%d] %s==", (uint32_t)cr_server.curClient->pid, __FUNCTION__); \
        crServerDumpDrawel _msg; \
        crServerDumpFilterOpLeave(CR_SERVER_DUMP_F_DRAWEL, cr_server.Recorder.pDumper); \
    } while (0)

#define CR_SERVER_DUMP_DRAWEL_V(_index, _pszElFormat, _cbEl, _pvVal, _cVal) do { \
        if (!CR_SERVER_DUMP_FILTER_OP(CR_SERVER_DUMP_F_DRAWEL, cr_server.Recorder.pDumper)) break; \
        crServerDumpCheckInit(); \
        crDmpStrF(cr_server.Recorder.pDumper, "==[%d] %s==", (uint32_t)cr_server.curClient->pid, __FUNCTION__); \
        crServerDumpDrawelv((_index), (_pszElFormat), (_cbEl), (_pvVal), (_cVal)); \
        crServerDumpFilterOpLeave(CR_SERVER_DUMP_F_DRAWEL, cr_server.Recorder.pDumper); \
    } while (0)
#else /* if !defined VBOX_WITH_CRSERVER_DUMPER */
#define CR_SERVER_DUMP_DRAW_ENTER() do {} while (0)
#define CR_SERVER_DUMP_DRAW_LEAVE() do {} while (0)
#define CR_SERVER_DUMP_COMPILE_SHADER(_id) do {} while (0)
#define CR_SERVER_DUMP_LINK_PROGRAM(_id) do {} while (0)
#define CR_SERVER_DUMP_TEXPRESENT(_pTex) do {} while (0)
#define CR_SERVER_DUMP_SWAPBUFFERS_ENTER() do {} while (0)
#define CR_SERVER_DUMP_SWAPBUFFERS_LEAVE() do {} while (0)
#define CR_SERVER_DUMP_SHADER_SOURCE(_id) do {} while (0)
#define CR_SERVER_DUMP_DRAWEL_F(_msg) do {} while (0)
#define CR_SERVER_DUMP_DRAWEL_V(_index, _pszElFormat, _cbEl, _pvVal, _cVal) do {} while (0)
#endif /* !VBOX_WITH_CRSERVER_DUMPER */

RT_C_DECLS_END

#endif /* CR_SERVER_H */