VirtualBox

source: vbox/trunk/src/VBox/GuestHost/OpenGL/util/blitter.cpp@ 44766

Last change on this file since 44766 was 44766, checked in by vboxsync, 12 years ago

crOpenGL: host 3d window repaint impl for Win host; enable offscreen rendering for Win; 3D window repaint generics

  • Property svn:executable set to *
File size: 17.8 KB
Line 
1/* $Id$ */
2
3/** @file
4 * Blitter API implementation
5 */
6/*
7 * Copyright (C) 2013 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
26#include <iprt/cdefs.h>
27#include <iprt/types.h>
28#include <iprt/mem.h>
29
30
31int CrBltInit(PCR_BLITTER pBlitter, CR_BLITTER_CONTEXT *pCtxBase, bool fCreateNewCtx, SPUDispatchTable *pDispatch)
32{
33 memset(pBlitter, 0, sizeof (*pBlitter));
34
35 pBlitter->pDispatch = pDispatch;
36
37 if (pCtxBase->Base.id == 0 || pCtxBase->Base.id < -1)
38 {
39 crWarning("Default share context not initialized!");
40 return VERR_INVALID_PARAMETER;
41 }
42
43 pBlitter->CtxInfo = *pCtxBase;
44 if (fCreateNewCtx)
45 {
46 pBlitter->CtxInfo.Base.id = pDispatch->CreateContext("", pCtxBase->Base.visualBits, pCtxBase->Base.id);
47 if (!pBlitter->CtxInfo.Base.id)
48 {
49 crWarning("CreateContext failed!");
50 return VERR_GENERAL_FAILURE;
51 }
52 pBlitter->Flags.CtxCreated = 1;
53 }
54
55 return VINF_SUCCESS;
56}
57
58void CrBltTerm(PCR_BLITTER pBlitter)
59{
60 if (pBlitter->Flags.CtxCreated)
61 pBlitter->pDispatch->DestroyContext(pBlitter->CtxInfo.Base.id);
62}
63
64void CrBltMuralSetCurrent(PCR_BLITTER pBlitter, CR_BLITTER_WINDOW *pMural)
65{
66 if (pBlitter->pCurrentMural == pMural)
67 return;
68
69 pBlitter->pCurrentMural = pMural;
70 pBlitter->Flags.CurrentMuralChanged = 1;
71
72 if (!CrBltIsEntered(pBlitter))
73 return;
74
75 if (pMural)
76 pBlitter->pDispatch->MakeCurrent(pMural->Base.id, 0, pBlitter->CtxInfo.Base.id);
77 else
78 pBlitter->pDispatch->MakeCurrent(0, 0, 0);
79}
80
81#define CRBLT_FILTER_FROM_FLAGS(_f) (((_f) & CRBLT_F_LINEAR) ? GL_LINEAR : GL_NEAREST)
82
83static DECLCALLBACK(int) crBltBlitTexBufImplFbo(PCR_BLITTER pBlitter, VBOXVR_TEXTURE *pSrc, const RTRECT *paSrcRect, const PRTRECTSIZE pDstSize, const RTRECT *paDstRect, uint32_t cRects, uint32_t fFlags)
84{
85 GLenum filter = CRBLT_FILTER_FROM_FLAGS(fFlags);
86 pBlitter->pDispatch->BindFramebufferEXT(GL_READ_FRAMEBUFFER, pBlitter->idFBO);
87 pBlitter->pDispatch->FramebufferTexture2DEXT(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, pSrc->target, pSrc->hwid, 0);
88 pBlitter->pDispatch->ReadBuffer(GL_COLOR_ATTACHMENT0);
89
90 for (uint32_t i = 0; i < cRects; ++i)
91 {
92 const RTRECT * pSrcRect = &paSrcRect[i];
93 const RTRECT * pDstRect = &paDstRect[i];
94 pBlitter->pDispatch->BlitFramebufferEXT(
95 pSrcRect->xLeft, pSrcRect->yTop, pSrcRect->xRight, pSrcRect->yBottom,
96 pDstRect->xLeft, pDstRect->yTop, pDstRect->xRight, pDstRect->yBottom,
97 GL_COLOR_BUFFER_BIT, filter);
98 }
99
100 return VINF_SUCCESS;
101}
102
103/* GL_TRIANGLE_FAN */
104DECLINLINE(GLfloat*) crBltVtRectTFNormalized(const RTRECT *pRect, uint32_t normalX, uint32_t normalY, GLfloat* pBuff)
105{
106 /* xLeft yTop */
107 pBuff[0] = ((float)pRect->xLeft)/((float)normalX);
108 pBuff[1] = ((float)pRect->yTop)/((float)normalY);
109
110 /* xLeft yBottom */
111 pBuff[2] = pBuff[0];
112 pBuff[3] = ((float)pRect->yBottom)/((float)normalY);
113
114 /* xRight yBottom */
115 pBuff[4] = ((float)pRect->xRight)/((float)normalX);
116 pBuff[5] = pBuff[3];
117
118 /* xRight yTop */
119 pBuff[6] = pBuff[4];
120 pBuff[7] = pBuff[1];
121 return &pBuff[8];
122}
123
124DECLINLINE(GLint*) crBltVtRectTF(const RTRECT *pRect, uint32_t normalX, uint32_t normalY, GLint* pBuff)
125{
126 /* xLeft yTop */
127 pBuff[0] = pRect->xLeft;
128 pBuff[1] = pRect->yTop;
129
130 /* xLeft yBottom */
131 pBuff[2] = pBuff[0];
132 pBuff[3] = pRect->yBottom;
133
134 /* xRight yBottom */
135 pBuff[4] = pRect->xRight;
136 pBuff[5] = pBuff[3];
137
138 /* xRight yTop */
139 pBuff[6] = pBuff[4];
140 pBuff[7] = pBuff[1];
141 return &pBuff[8];
142}
143
144DECLINLINE(GLubyte*) crBltVtFillRectIndicies(GLubyte *pIndex, GLubyte *piBase)
145{
146 GLubyte iBase = *piBase;
147 /* triangle 1 */
148 pIndex[0] = iBase;
149 pIndex[1] = iBase + 1;
150 pIndex[2] = iBase + 2;
151
152 /* triangle 2 */
153 pIndex[3] = iBase;
154 pIndex[4] = iBase + 2;
155 pIndex[5] = iBase + 3;
156 *piBase = iBase + 6;
157 return pIndex + 6;
158}
159
160/* Indexed GL_TRIANGLES */
161DECLINLINE(GLfloat*) crBltVtRectITNormalized(const RTRECT *pRect, uint32_t normalX, uint32_t normalY, GLfloat* pBuff, GLubyte **ppIndex, GLubyte *piBase)
162{
163 GLfloat* ret = crBltVtRectTFNormalized(pRect, normalX, normalY, pBuff);
164
165 if (ppIndex)
166 *ppIndex = crBltVtFillRectIndicies(*ppIndex, piBase);
167
168 return ret;
169}
170
171DECLINLINE(GLint*) crBltVtRectIT(RTRECT *pRect, uint32_t normalX, uint32_t normalY, GLint* pBuff, GLubyte **ppIndex, GLubyte *piBase)
172{
173 GLint* ret = crBltVtRectTF(pRect, normalX, normalY, pBuff);
174
175 if (ppIndex)
176 *ppIndex = crBltVtFillRectIndicies(*ppIndex, piBase);
177
178 return ret;
179}
180
181DECLINLINE(GLuint) crBltVtGetNumVerticiesTF(GLuint cRects)
182{
183 return cRects * 4;
184}
185
186#define crBltVtGetNumVerticiesIT crBltVtGetNumVerticiesTF
187
188DECLINLINE(GLuint) crBltVtGetNumIndiciesIT(GLuint cRects)
189{
190 return 6 * cRects;
191}
192
193
194static GLfloat* crBltVtRectsITNormalized(const RTRECT *paRects, uint32_t cRects, uint32_t normalX, uint32_t normalY, GLfloat* pBuff, GLubyte **ppIndex, GLubyte *piBase)
195{
196 for (uint32_t i = 0; i < cRects; ++i)
197 {
198 pBuff = crBltVtRectITNormalized(&paRects[i], normalX, normalY, pBuff, ppIndex, piBase);
199 }
200 return pBuff;
201}
202
203static void* crBltBufGet(PCR_BLITTER_BUFFER pBuffer, GLuint cbBuffer)
204{
205 if (pBuffer->cbBuffer < cbBuffer)
206 {
207 if (pBuffer->pvBuffer)
208 {
209 RTMemFree(pBuffer->pvBuffer);
210 }
211
212 cbBuffer += 16;
213
214 pBuffer->pvBuffer = RTMemAlloc(cbBuffer);
215 if (pBuffer->pvBuffer)
216 pBuffer->cbBuffer = cbBuffer;
217 else
218 {
219 crWarning("failed to allocate buffer of size %d", cbBuffer);
220 pBuffer->cbBuffer = 0;
221 }
222 }
223 return pBuffer->pvBuffer;
224}
225
226static void crBltCheckSetupViewport(PCR_BLITTER pBlitter, const PRTRECTSIZE pDstSize, bool fFBODraw)
227{
228 if (!pBlitter->Flags.LastWasFBODraw != !fFBODraw
229 || pBlitter->Flags.CurrentMuralChanged
230 || pBlitter->CurrentSetSize.cx != pDstSize->cx
231 || pBlitter->CurrentSetSize.cy != pDstSize->cy)
232 {
233#if 0
234 const GLdouble aProjection[] =
235 {
236 2.0 / pDstSize->cx, 0.0, 0.0, 0.0,
237 0.0, 2.0 / pDstSize->cy, 0.0, 0.0,
238 0.0, 0.0, 2.0, 0.0,
239 -1.0, -1.0, -1.0, 1.0
240 };
241 pBlitter->pDispatch->MatrixMode(GL_PROJECTION);
242 pBlitter->pDispatch->LoadMatrixd(aProjection);
243 pBlitter->pDispatch->Viewport(0, 0, pDstSize->cx, pDstSize->cy);
244#else
245 pBlitter->pDispatch->MatrixMode(GL_PROJECTION);
246 pBlitter->pDispatch->LoadIdentity();
247 pBlitter->pDispatch->Viewport(0, 0, pDstSize->cx, pDstSize->cy);
248 pBlitter->pDispatch->Ortho(0, pDstSize->cx, 0, pDstSize->cy, -1, 1);
249 pBlitter->pDispatch->MatrixMode(GL_TEXTURE);
250 pBlitter->pDispatch->LoadIdentity();
251 pBlitter->pDispatch->MatrixMode(GL_MODELVIEW);
252 pBlitter->pDispatch->LoadIdentity();
253
254 /* Clear background to transparent */
255 pBlitter->pDispatch->ClearColor(0.0f, 0.0f, 0.0f, 0.0f);
256#endif
257 pBlitter->CurrentSetSize.cx = pDstSize->cx;
258 pBlitter->CurrentSetSize.cy = pDstSize->cy;
259 pBlitter->Flags.LastWasFBODraw = fFBODraw;
260 if (!fFBODraw)
261 pBlitter->Flags.CurrentMuralChanged = 0;
262 }
263}
264
265static DECLCALLBACK(int) crBltBlitTexBufImplDraw2D(PCR_BLITTER pBlitter, VBOXVR_TEXTURE *pSrc, const RTRECT *paSrcRect, const PRTRECTSIZE pDstSize, const RTRECT *paDstRect, uint32_t cRects, uint32_t fFlags)
266{
267 GLuint normalX, normalY;
268
269 switch (pSrc->target)
270 {
271 case GL_TEXTURE_2D:
272 {
273 normalX = pSrc->width;
274 normalY = pSrc->height;
275 break;
276 }
277
278 case GL_TEXTURE_RECTANGLE_ARB:
279 {
280 normalX = 1;
281 normalY = 1;
282 break;
283 }
284
285 default:
286 {
287 crWarning("Unsupported texture target 0x%x", pSrc->target);
288 return VERR_INVALID_PARAMETER;
289 }
290 }
291
292 Assert(pSrc->hwid);
293
294 pBlitter->pDispatch->BindTexture(pSrc->target, pSrc->hwid);
295
296 if (cRects == 1)
297 {
298 /* just optimizatino to draw a single rect with GL_TRIANGLE_FAN */
299 bool bUseSameVerticies = paSrcRect == paDstRect && normalX == 1 && normalY == 1;
300 GLfloat *pVerticies;
301 GLfloat *pTexCoords;
302 GLuint cElements = crBltVtGetNumVerticiesTF(1);
303 if (bUseSameVerticies)
304 {
305 pVerticies = (GLfloat*)crBltBufGet(&pBlitter->Verticies, cElements * 2 * sizeof (*pVerticies));
306 crBltVtRectTFNormalized(paDstRect, normalX, normalY, pVerticies);
307 pTexCoords = pVerticies;
308 }
309 else
310 {
311 pVerticies = (GLfloat*)crBltBufGet(&pBlitter->Verticies, cElements * 2 * 2 * sizeof (*pVerticies));
312 pTexCoords = crBltVtRectTFNormalized(paDstRect, normalX, normalY, pVerticies);
313 crBltVtRectTFNormalized(paSrcRect, normalX, normalY, pTexCoords);
314 }
315
316 pBlitter->pDispatch->EnableClientState(GL_VERTEX_ARRAY);
317 pBlitter->pDispatch->VertexPointer(2, GL_FLOAT, 0, pVerticies);
318
319 pBlitter->pDispatch->EnableClientState(GL_TEXTURE_COORD_ARRAY);
320 pBlitter->pDispatch->VertexPointer(2, GL_FLOAT, 0, pTexCoords);
321
322 pBlitter->pDispatch->Enable(pSrc->target);
323
324 pBlitter->pDispatch->DrawArrays(GL_TRIANGLE_FAN, 0, cElements);
325
326 pBlitter->pDispatch->Disable(pSrc->target);
327
328 pBlitter->pDispatch->DisableClientState(GL_TEXTURE_COORD_ARRAY);
329 pBlitter->pDispatch->DisableClientState(GL_VERTEX_ARRAY);
330 }
331 else
332 {
333 bool bUseSameVerticies = paSrcRect == paDstRect && normalX == 1 && normalY == 1;
334 GLfloat *pVerticies;
335 GLfloat *pTexCoords;
336 GLubyte *pIndicies;
337 GLuint cElements = crBltVtGetNumVerticiesIT(cRects);
338 GLuint cIndicies = crBltVtGetNumIndiciesIT(cRects);
339 GLubyte iIdxBase = 0;
340 if (bUseSameVerticies)
341 {
342 pVerticies = (GLfloat*)crBltBufGet(&pBlitter->Verticies, cElements * 2 * sizeof (*pVerticies));
343 crBltVtRectsITNormalized(paDstRect, cRects, normalX, normalY, pVerticies, &pIndicies, &iIdxBase);
344 pTexCoords = pVerticies;
345 }
346 else
347 {
348 pVerticies = (GLfloat*)crBltBufGet(&pBlitter->Verticies, cElements * 2 * 2 * sizeof (*pVerticies));
349 pTexCoords = crBltVtRectsITNormalized(paDstRect, cRects, normalX, normalY, pVerticies, &pIndicies, &iIdxBase);
350 crBltVtRectsITNormalized(paSrcRect, cRects, normalX, normalY, pTexCoords, NULL, NULL);
351 }
352
353 pBlitter->pDispatch->EnableClientState(GL_VERTEX_ARRAY);
354 pBlitter->pDispatch->VertexPointer(2, GL_FLOAT, 0, pVerticies);
355
356 pBlitter->pDispatch->EnableClientState(GL_TEXTURE_COORD_ARRAY);
357 pBlitter->pDispatch->VertexPointer(2, GL_FLOAT, 0, pTexCoords);
358
359 pBlitter->pDispatch->Enable(pSrc->target);
360
361 pBlitter->pDispatch->DrawElements(GL_TRIANGLES, cIndicies, GL_UNSIGNED_BYTE, pIndicies);
362
363 pBlitter->pDispatch->Disable(pSrc->target);
364
365 pBlitter->pDispatch->DisableClientState(GL_TEXTURE_COORD_ARRAY);
366 pBlitter->pDispatch->DisableClientState(GL_VERTEX_ARRAY);
367 }
368
369 return VINF_SUCCESS;
370}
371
372static int crBltInitOnMakeCurent(PCR_BLITTER pBlitter)
373{
374 const char * pszExtension = (const char*)pBlitter->pDispatch->GetString(GL_EXTENSIONS);
375 if (crStrstr(pszExtension, "GL_EXT_framebuffer_object"))
376 {
377 pBlitter->Flags.SupportsFBO = 1;
378 pBlitter->pDispatch->GenFramebuffersEXT(1, &pBlitter->idFBO);
379 Assert(pBlitter->idFBO);
380 }
381 else
382 crWarning("GL_EXT_framebuffer_object not supported, blitter can only blit to window");
383
384 if (crStrstr(pszExtension, "GL_EXT_framebuffer_blit"))
385 {
386 pBlitter->Flags.SupportsFBOBlit = 1;
387 pBlitter->pfnBlt = crBltBlitTexBufImplFbo;
388 }
389 else
390 {
391 crWarning("GL_EXT_framebuffer_blit not supported, will use Draw functions for blitting, which might be less efficient");
392 pBlitter->pfnBlt = crBltBlitTexBufImplDraw2D;
393 }
394
395 return VINF_SUCCESS;
396}
397
398void CrBltLeave(PCR_BLITTER pBlitter)
399{
400 Assert(CrBltIsEntered(pBlitter));
401
402 if (pBlitter->Flags.SupportsFBO)
403 {
404 pBlitter->pDispatch->BindFramebufferEXT(GL_FRAMEBUFFER, 0);
405 pBlitter->pDispatch->DrawBuffer(GL_BACK);
406 pBlitter->pDispatch->ReadBuffer(GL_BACK);
407 }
408
409 pBlitter->pDispatch->Flush();
410
411 if (pBlitter->pRestoreCtxInfo != &pBlitter->CtxInfo)
412 {
413// GLuint idDrawFBO, idReadFBO;
414// CR_BLITTER_WINDOW *pRestoreMural = pBlitter->pRestoreMural;
415// if (pRestoreMural->fUseFBO && crServerSupportRedirMuralFBO())
416// {
417// idDrawFBO = pRestoreMural->aidFBOs[pRestoreMural->iCurDrawBuffer];
418// idReadFBO = pRestoreMural->aidFBOs[pRestoreMural->iCurReadBuffer];
419// }
420// else
421// {
422// idDrawFBO = 0;
423// idReadFBO = 0;
424// }
425
426 pBlitter->pDispatch->MakeCurrent(pBlitter->pRestoreMural->Base.id, 0,
427 pBlitter->pRestoreCtxInfo->Base.id >= 0
428 ? pBlitter->pRestoreCtxInfo->Base.id : pBlitter->pRestoreCtxInfo->Base.id);
429// crStateSwitchPostprocess(pBlitter->pRestoreCtxInfo->pContext, NULL, idDrawFBO, idReadFBO);
430 }
431 else
432 {
433 pBlitter->pDispatch->MakeCurrent(0, 0, 0);
434 }
435
436 pBlitter->pRestoreCtxInfo = NULL;
437}
438
439int CrBltEnter(PCR_BLITTER pBlitter, CR_BLITTER_CONTEXT *pRestoreCtxInfo, CR_BLITTER_WINDOW *pRestoreMural)
440{
441 if (!pBlitter->pCurrentMural)
442 {
443 crWarning("current mural not initialized!");
444 return VERR_INVALID_STATE;
445 }
446
447 if (CrBltIsEntered(pBlitter))
448 {
449 crWarning("blitter is entered already!");
450 return VERR_INVALID_STATE;
451 }
452
453 if (pRestoreCtxInfo)
454 {
455 pBlitter->pRestoreCtxInfo = pRestoreCtxInfo;
456 pBlitter->pRestoreMural = pRestoreMural;
457
458// GLuint idDrawFBO, idReadFBO;
459//
460// if (pRestoreMural->fUseFBO && crServerSupportRedirMuralFBO())
461// {
462// idDrawFBO = pRestoreMural->aidFBOs[pRestoreMural->iCurDrawBuffer];
463// idReadFBO = pRestoreMural->aidFBOs[pRestoreMural->iCurReadBuffer];
464// }
465// else
466// {
467// idDrawFBO = 0;
468// idReadFBO = 0;
469// }
470// crStateSwitchPrepare(NULL, pRestoreCtxInfo->pContext, idDrawFBO, idReadFBO);
471
472 pBlitter->pDispatch->Flush();
473 }
474 else
475 {
476 pBlitter->pRestoreCtxInfo = &pBlitter->CtxInfo;
477 }
478
479 pBlitter->pDispatch->MakeCurrent(pBlitter->pCurrentMural->Base.id, 0, pBlitter->CtxInfo.Base.id);
480
481 if (pBlitter->Flags.Initialized)
482 return VINF_SUCCESS;
483
484 int rc = crBltInitOnMakeCurent(pBlitter);
485 if (RT_SUCCESS(rc))
486 {
487 pBlitter->Flags.Initialized = 1;
488 return VINF_SUCCESS;
489 }
490
491 crWarning("crBltInitOnMakeCurent failed, rc %d", rc);
492 CrBltLeave(pBlitter);
493 return rc;
494}
495
496static void crBltBlitTexBuf(PCR_BLITTER pBlitter, VBOXVR_TEXTURE *pSrc, const RTRECT *paSrcRects, GLenum enmDstBuff, const PRTRECTSIZE pDstSize, const RTRECT *paDstRects, uint32_t cRects, uint32_t fFlags)
497{
498 pBlitter->pDispatch->DrawBuffer(enmDstBuff);
499
500 crBltCheckSetupViewport(pBlitter, pDstSize, enmDstBuff == GL_DRAW_FRAMEBUFFER);
501
502 pBlitter->pfnBlt(pBlitter, pSrc, paSrcRects, pDstSize, paDstRects, cRects, fFlags);
503}
504
505void CrBltBlitTexMural(PCR_BLITTER pBlitter, VBOXVR_TEXTURE *pSrc, const RTRECT *paSrcRects, const RTRECT *paDstRects, uint32_t cRects, uint32_t fFlags)
506{
507 RTRECTSIZE DstSize = {pBlitter->pCurrentMural->width, pBlitter->pCurrentMural->height};
508
509 pBlitter->pDispatch->BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, 0);
510
511 crBltBlitTexBuf(pBlitter, pSrc, paSrcRects, GL_BACK, &DstSize, paDstRects, cRects, fFlags);
512}
513
514void CrBltBlitTexTex(PCR_BLITTER pBlitter, VBOXVR_TEXTURE *pSrc, const RTRECT *pSrcRect, VBOXVR_TEXTURE *pDst, const RTRECT *pDstRect, uint32_t cRects, uint32_t fFlags)
515{
516 RTRECTSIZE DstSize = {(uint32_t)pDst->width, (uint32_t)pDst->height};
517
518 pBlitter->pDispatch->BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, pBlitter->idFBO);
519
520 /* TODO: mag/min filters ? */
521
522 pBlitter->pDispatch->FramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, pDst->target, pDst->hwid, 0);
523
524// pBlitter->pDispatch->FramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
525// pBlitter->pDispatch->FramebufferTexture2DEXT(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
526
527 crBltBlitTexBuf(pBlitter, pSrc, pSrcRect, GL_DRAW_FRAMEBUFFER, &DstSize, pDstRect, cRects, fFlags);
528}
529
530void CrBltPresent(PCR_BLITTER pBlitter)
531{
532 if (pBlitter->CtxInfo.Base.visualBits & CR_DOUBLE_BIT)
533 pBlitter->pDispatch->SwapBuffers(pBlitter->pCurrentMural->Base.id, 0);
534 else
535 pBlitter->pDispatch->Flush();
536}
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