VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/Graphics/Video/disp/xpdm/VBoxDispDrawCmd.cpp@ 102295

Last change on this file since 102295 was 99828, checked in by vboxsync, 23 months ago

*: A bunch of adjustments that allows using /permissive- with Visual C++ (qt 6.x necessity).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 17.8 KB
Line 
1/* $Id: VBoxDispDrawCmd.cpp 99828 2023-05-17 13:48:57Z vboxsync $ */
2/** @file
3 * VBox XPDM Display driver drawing interface functions
4 */
5
6/*
7 * Copyright (C) 2011-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28/* The driver operates in 3 modes:
29 * 1) BASE : Driver does not report to host about any operations.
30 * All Drv* are immediately routed to Eng*.
31 * 2) VBVA : Driver reports dirty rectangles to host.
32 * 3) VBVA + VRDP : Driver also creates orders pipeline from which VRDP
33 * can reconstruct all drawing operations, including
34 * bitmap updates.
35 *
36 * These modes affect only VBoxDispDrv* functions in this file.
37 *
38 * VBVA mode is enabled by a registry key for the miniport driver
39 * (as it is implemented now).
40 *
41 * VRDP mode is enabled when a VRDP client connects and VBVA is enabled.
42 * The host sets a bit flag in VBVAMemory when VRDP client is connected.
43 *
44 * The VRDP mode pipeline consists of 3 types of commands:
45 *
46 * 1) RDP orders: BitBlt, RectFill, Text.
47 * These are the simplest ones.
48 *
49 * 2) Caching: Bitmap, glyph, brush.
50 * The driver maintains a bitmap (or other objects) cache.
51 * All source bitmaps are cached. The driver verifies
52 * iUniq and also computes CRC for these bitmaps
53 * for searching. The driver will use SURFOBJ::dhsurf
54 * field to save a pointer to in driver structure, even
55 * for Engine managed bitmaps (hope that will work).
56 *
57 *
58 * 3) Bitmap updates, when given draw operation can not be done
59 * using orders.
60 *
61 */
62
63#include "VBoxDisp.h"
64#include "VBoxDispDrawCmd.h"
65
66typedef struct _VBOXDISPCALLSTATS
67{
68 ULONG VBoxDispDrvLineTo;
69 ULONG VBoxDispDrvStrokePath;
70 ULONG VBoxDispDrvFillPath;
71 ULONG VBoxDispDrvTextOut;
72 ULONG VBoxDispDrvPaint;
73 ULONG VBoxDispDrvSaveScreenBits;
74 ULONG VBoxDispDrvBitBlt;
75 ULONG VBoxDispDrvStretchBlt;
76 ULONG VBoxDispDrvCopyBits;
77} VBOXDISPCALLSTATS;
78
79static VBOXDISPCALLSTATS gDispCallStats = {0,0,0,0,0,0,0,0,0};
80
81#ifdef STAT_sunlover
82# define STATDRVENTRY(a, b) do {if (VBoxDispIsScreenSurface(b)) gDispCallStats.VBoxDispDrv##a++; } while (0)
83# define STATPRINT do {VBoxDispPrintStats();} while (0)
84# define DUMPSURF(_s, _name) VBoxDispDumpPSO(_s, _name);
85#else
86# define STATDRVENTRY(a, b)
87# define STATPRINT
88# define DUMPSURF(_s, _name)
89#endif
90
91#define VBVA_OPERATION(__psoDest, __fn, __a) do { \
92 if (VBoxDispIsScreenSurface(__psoDest)) \
93 { \
94 PVBOXDISPDEV pMacroDev = (PVBOXDISPDEV)__psoDest->dhpdev; \
95 \
96 if ( pMacroDev->hgsmi.bSupported \
97 && VBoxVBVABufferBeginUpdate(&pMacroDev->vbvaCtx, &pMacroDev->hgsmi.ctx)) \
98 { \
99 vbvaDrv##__fn __a; \
100 \
101 if (pMacroDev->vbvaCtx.pVBVA->hostFlags.u32HostEvents & VBOX_VIDEO_INFO_HOST_EVENTS_F_VRDP_RESET) \
102 { \
103 vrdpReset(pMacroDev); \
104 \
105 pMacroDev->vbvaCtx.pVBVA->hostFlags.u32HostEvents &= ~VBOX_VIDEO_INFO_HOST_EVENTS_F_VRDP_RESET; \
106 } \
107 \
108 if (pMacroDev->vbvaCtx.pVBVA->hostFlags.u32HostEvents & VBVA_F_MODE_VRDP) \
109 { \
110 vrdpDrv##__fn __a; \
111 } \
112 \
113 VBoxVBVABufferEndUpdate(&pMacroDev->vbvaCtx); \
114 } \
115 } \
116} while (0)
117
118BOOL VBoxDispIsScreenSurface(SURFOBJ *pso)
119{
120 if (pso)
121 {
122 PVBOXDISPDEV pDev = (PVBOXDISPDEV)pso->dhpdev;
123
124 /* The screen surface has the 'pso->dhpdev' field,
125 * and is either the screen device surface with handle = hsurfScreen,
126 * or a surface derived from DDRAW with address equal to the framebuffer.
127 */
128 if (pDev && (pso->hsurf == pDev->surface.hSurface || pso->pvBits == pDev->memInfo.FrameBufferBase))
129 {
130 return TRUE;
131 }
132 }
133
134 return FALSE;
135}
136
137static void VBoxDispPrintStats(void)
138{
139 LOG(("LineTo = %u\n",
140 "StrokePath = %u\n",
141 "FillPath = %u\n",
142 "TextOut = %u\n",
143 "DrvPaint = %u\n",
144 "SaveScreenBits = %u\n",
145 "BitBlt = %u\n",
146 "StretchBlt = %u\n",
147 "CopyBits = %u",
148 gDispCallStats.VBoxDispDrvLineTo,
149 gDispCallStats.VBoxDispDrvStrokePath,
150 gDispCallStats.VBoxDispDrvFillPath,
151 gDispCallStats.VBoxDispDrvTextOut,
152 gDispCallStats.VBoxDispDrvPaint,
153 gDispCallStats.VBoxDispDrvSaveScreenBits,
154 gDispCallStats.VBoxDispDrvBitBlt,
155 gDispCallStats.VBoxDispDrvStretchBlt,
156 gDispCallStats.VBoxDispDrvCopyBits
157 ));
158}
159
160void VBoxDispDumpPSO(SURFOBJ *pso, const char *s)
161{
162 RT_NOREF(pso, s);
163 if (pso)
164 {
165 LOG(("Surface %s: %p\n"
166 " DHSURF dhsurf = %p\n"
167 " HSURF hsurf = %p\n"
168 " DHPDEV dhpdev = %p\n"
169 " HDEV hdev = %p\n"
170 " SIZEL sizlBitmap = %dx%d\n"
171 " ULONG cjBits = %p\n"
172 " PVOID pvBits = %p\n"
173 " PVOID pvScan0 = %p\n"
174 " LONG lDelta = %p\n"
175 " ULONG iUniq = %p\n"
176 " ULONG iBitmapFormat = %p\n"
177 " USHORT iType = %p\n"
178 " USHORT fjBitmap = %p",
179 s, pso, pso->dhsurf, pso->hsurf, pso->dhpdev, pso->hdev,
180 pso->sizlBitmap.cx, pso->sizlBitmap.cy, pso->cjBits, pso->pvBits,
181 pso->pvScan0, pso->lDelta, pso->iUniq, pso->iBitmapFormat, pso->iType, pso->fjBitmap));
182 }
183 else
184 {
185 LOG(("Surface %s: %p", s, pso));
186 }
187}
188
189static void ssbDiscardTopSlot(PVBOXDISPDEV pDev)
190{
191 SSB *pSSB = &pDev->aSSB[--pDev->cSSB];
192
193 if (pSSB->pBuffer)
194 {
195 EngFreeMem (pSSB->pBuffer);
196 pSSB->pBuffer = NULL;
197 }
198
199 pSSB->ident = 0;
200}
201
202static void ssbDiscardUpperSlots(PVBOXDISPDEV pDev, ULONG_PTR ident)
203{
204 while (pDev->cSSB > ident)
205 {
206 ssbDiscardTopSlot (pDev);
207 }
208}
209
210static BOOL ssbCopy(SSB *pSSB, SURFOBJ *pso, RECTL *prcl, BOOL bToScreen)
211{
212 BYTE *pSrc;
213 BYTE *pDst;
214
215 LONG lDeltaSrc;
216 LONG lDeltaDst;
217
218 ULONG cWidth;
219 ULONG cHeight;
220
221 int cbPixel = format2BytesPerPixel(pso);
222
223 LOGF(("pSSB = %p, pso = %p, prcl = %p, bToScreen = %d", pSSB, pso, prcl, bToScreen));
224
225 if (cbPixel == 0)
226 {
227 WARN(("unsupported pixel format!!!"));
228 return FALSE;
229 }
230
231 cWidth = prcl->right - prcl->left;
232 cHeight = prcl->bottom - prcl->top;
233
234 if (bToScreen)
235 {
236 if (pSSB->pBuffer == NULL)
237 {
238 WARN(("source buffer is NULL!!!"));
239 return FALSE;
240 }
241
242 pSrc = pSSB->pBuffer;
243 lDeltaSrc = cWidth * cbPixel;
244
245 pDst = (BYTE *)pso->pvScan0 +
246 pso->lDelta * prcl->top +
247 cbPixel * prcl->left;
248 lDeltaDst = pso->lDelta;
249 }
250 else
251 {
252 if (pSSB->pBuffer != NULL)
253 {
254 WARN(("source buffer is not NULL!!!"));
255 return FALSE;
256 }
257
258 pSSB->pBuffer = (BYTE *)EngAllocMem (0, cWidth * cHeight * cbPixel, MEM_ALLOC_TAG);
259
260 if (pSSB->pBuffer == NULL)
261 {
262 WARN(("Failed to allocate buffer!!!"));
263 return FALSE;
264 }
265
266 pDst = pSSB->pBuffer;
267 lDeltaDst = cWidth * cbPixel;
268
269 pSrc = (BYTE *)pso->pvScan0 +
270 pso->lDelta * prcl->top +
271 cbPixel * prcl->left;
272 lDeltaSrc = pso->lDelta;
273 }
274
275 LOG(("cHeight = %d, pDst = %p, pSrc = %p, lDeltaSrc = %d, lDeltaDst = %d",
276 cHeight, pDst, pSrc, lDeltaSrc, lDeltaDst));
277
278 while (cHeight--)
279 {
280 memcpy (pDst, pSrc, cWidth * cbPixel);
281
282 pDst += lDeltaDst;
283 pSrc += lDeltaSrc;
284 }
285
286 LOGF(("completed."));
287 return TRUE;
288}
289
290/*
291 * Display driver callbacks.
292 */
293
294BOOL APIENTRY
295VBoxDispDrvLineTo(SURFOBJ *pso, CLIPOBJ *pco, BRUSHOBJ *pbo, LONG x1, LONG y1, LONG x2, LONG y2,
296 RECTL *prclBounds, MIX mix)
297{
298 BOOL bRc;
299 LOGF_ENTER();
300 STATDRVENTRY(LineTo, pso);
301
302 bRc = EngLineTo(getSurfObj(pso), pco, pbo, x1, y1, x2, y2, prclBounds, mix);
303 VBVA_OPERATION(pso, LineTo, (pso, pco, pbo, x1, y1, x2, y2, prclBounds, mix));
304
305 LOGF_LEAVE();
306 return bRc;
307}
308
309BOOL APIENTRY
310VBoxDispDrvStrokePath(SURFOBJ *pso, PATHOBJ *ppo, CLIPOBJ *pco, XFORMOBJ *pxo,
311 BRUSHOBJ *pbo, POINTL *pptlBrushOrg, LINEATTRS *plineattrs, MIX mix)
312{
313 BOOL bRc;
314 LOGF_ENTER();
315 STATDRVENTRY(StrokePath, pso);
316
317 bRc = EngStrokePath(getSurfObj(pso), ppo, pco, pxo, pbo, pptlBrushOrg, plineattrs, mix);
318 VBVA_OPERATION(pso, StrokePath, (pso, ppo, pco, pxo, pbo, pptlBrushOrg, plineattrs, mix));
319
320 LOGF_LEAVE();
321 return bRc;
322}
323
324BOOL APIENTRY
325VBoxDispDrvFillPath(SURFOBJ *pso, PATHOBJ *ppo, CLIPOBJ *pco, BRUSHOBJ *pbo, POINTL *pptlBrushOrg,
326 MIX mix, FLONG flOptions)
327{
328 BOOL bRc;
329 LOGF_ENTER();
330 STATDRVENTRY(FillPath, pso);
331
332 bRc = EngFillPath(getSurfObj(pso), ppo, pco, pbo, pptlBrushOrg, mix, flOptions);
333 VBVA_OPERATION(pso, FillPath, (pso, ppo, pco, pbo, pptlBrushOrg, mix, flOptions));
334
335 LOGF_LEAVE();
336 return bRc;
337}
338
339BOOL APIENTRY VBoxDispDrvPaint(SURFOBJ *pso, CLIPOBJ *pco, BRUSHOBJ *pbo, POINTL *pptlBrushOrg, MIX mix)
340{
341 BOOL bRc;
342 LOGF_ENTER();
343 STATDRVENTRY(Paint, pso);
344
345 bRc = EngPaint (getSurfObj(pso), pco, pbo, pptlBrushOrg, mix);
346 VBVA_OPERATION(pso, Paint, (pso, pco, pbo, pptlBrushOrg, mix));
347
348 LOGF_LEAVE();
349 return bRc;
350}
351
352BOOL APIENTRY
353VBoxDispDrvTextOut(SURFOBJ *pso, STROBJ *pstro, FONTOBJ *pfo, CLIPOBJ *pco,
354 RECTL *prclExtra, RECTL *prclOpaque, BRUSHOBJ *pboFore,
355 BRUSHOBJ *pboOpaque, POINTL *pptlOrg, MIX mix)
356{
357 BOOL bRc;
358 LOGF_ENTER();
359 STATDRVENTRY(TextOut, pso);
360
361 bRc = EngTextOut(getSurfObj(pso), pstro, pfo, pco, prclExtra, prclOpaque, pboFore, pboOpaque, pptlOrg, mix);
362 VBVA_OPERATION(pso, TextOut, (pso, pstro, pfo, pco, prclExtra, prclOpaque, pboFore, pboOpaque, pptlOrg, mix));
363
364 LOGF_LEAVE();
365 return bRc;
366}
367
368ULONG_PTR APIENTRY VBoxDispDrvSaveScreenBits(SURFOBJ *pso, ULONG iMode, ULONG_PTR ident, RECTL *prcl)
369{
370 ULONG_PTR rc = 0; /* 0 means the function failure for every iMode. */
371 RECTL rcl;
372 SSB *pSSB;
373 SURFOBJ *psoOrg = pso;
374 BOOL bCallVBVA = FALSE;
375
376 PVBOXDISPDEV pDev = (PVBOXDISPDEV) pso->dhpdev;
377
378 LOGF(("%p, %d, %d, %d,%d %d,%d", pso, iMode, ident, prcl->left, prcl->top, prcl->right, prcl->bottom));
379
380 if (!pDev)
381 {
382 return rc;
383 }
384
385 pso = getSurfObj(pso);
386
387 /* Order the rectangle. */
388 if (prcl->left <= prcl->right)
389 {
390 rcl.left = prcl->left;
391 rcl.right = prcl->right;
392 }
393 else
394 {
395 rcl.left = prcl->right;
396 rcl.right = prcl->left;
397 }
398
399 if (prcl->top <= prcl->bottom)
400 {
401 rcl.top = prcl->top;
402 rcl.bottom = prcl->bottom;
403 }
404 else
405 {
406 rcl.top = prcl->bottom;
407 rcl.bottom = prcl->top;
408 }
409
410 /* Implementation of the save/restore is a bit complicated because RDP
411 * requires "the sequencing of saves and restores is such that they
412 * behave as a last-in, first-out stack.".
413 */
414 switch (iMode)
415 {
416 case SS_SAVE:
417 {
418 LOG(("SS_SAVE %d", pDev->cSSB));
419
420 if (pDev->cSSB >= RT_ELEMENTS(pDev->aSSB))
421 {
422 /* All slots are already in use. Fail. */
423 WARN(("no more slots %d!!!", pDev->cSSB));
424 break;
425 }
426
427 /* Get pointer to the slot where bits will be saved. */
428 pSSB = &pDev->aSSB[pDev->cSSB];
429
430 /* Allocate memory for screen bits and copy them to the buffer. */
431 if (ssbCopy(pSSB, pso, &rcl, FALSE /* bToScreen */))
432 {
433 /* Bits where successfully copied. Increase the active slot number
434 * and call VBVA levels, 'ident' is also assigned, the VBVA level
435 * will use it even for the SS_SAVE.
436 */
437 ident = rc = pSSB->ident = ++pDev->cSSB;
438 bCallVBVA = TRUE;
439 }
440 } break;
441
442 case SS_RESTORE:
443 {
444 LOG(("SS_RESTORE"));
445
446 if (pDev->cSSB == 0 || ident == 0 || ident > pDev->cSSB)
447 {
448 WARN(("no slot: pDev->cSSB = %d!!!", pDev->cSSB));
449 break;
450 }
451
452 if (ident < pDev->cSSB)
453 {
454 ssbDiscardUpperSlots(pDev, ident);
455 }
456
457 Assert(ident == pDev->cSSB);
458 Assert(ident != 0);
459
460 pSSB = &pDev->aSSB[ident - 1];
461
462 ssbCopy(pSSB, pso, &rcl, TRUE /* bToScreen */);
463
464 /* Bits must be discarded. */
465 ssbDiscardTopSlot (pDev);
466
467 rc = TRUE;
468 bCallVBVA = TRUE;
469 } break;
470
471 case SS_FREE:
472 {
473 LOG(("SS_FREE"));
474
475 if (pDev->cSSB == 0 || ident == 0 || ident > pDev->cSSB)
476 {
477 WARN(("no slot: pDev->cSSB = %d!!!", pDev->cSSB));
478 break;
479 }
480
481 if (ident < pDev->cSSB)
482 {
483 ssbDiscardUpperSlots(pDev, ident);
484 }
485
486 Assert(ident == pDev->cSSB);
487 Assert(ident != 0);
488
489 /* Bits must be discarded. */
490 ssbDiscardTopSlot(pDev);
491
492 rc = TRUE;
493 } break;
494 }
495
496 /* Now call the VBVA/VRDP levels. */
497 if (bCallVBVA)
498 {
499 LOG(("calling VBVA"));
500 VBVA_OPERATION(psoOrg, SaveScreenBits, (psoOrg, iMode, ident, &rcl));
501 }
502
503 LOGF(("return %d", rc));
504 return rc;
505}
506
507BOOL APIENTRY
508VBoxDispDrvBitBlt(SURFOBJ *psoTrg, SURFOBJ *psoSrc, SURFOBJ *psoMask, CLIPOBJ *pco, XLATEOBJ *pxlo,
509 RECTL *prclTrg, POINTL *pptlSrc, POINTL *pptlMask, BRUSHOBJ *pbo, POINTL *pptlBrush, ROP4 rop4)
510{
511 BOOL bRc;
512 LOGF_ENTER();
513 STATDRVENTRY(BitBlt, psoTrg);
514
515 LOG(("psoTrg = %p, psoSrc = %p, psoMask = %p, pco = %p, pxlo = %p, prclTrg = %p, pptlSrc = %p, "
516 "pptlMask = %p, pbo = %p, pptlBrush = %p, rop4 = %08X",
517 psoTrg, psoSrc, psoMask, pco, pxlo, prclTrg, pptlSrc, pptlMask, pbo, pptlBrush, rop4));
518
519 bRc = EngBitBlt(getSurfObj(psoTrg), getSurfObj(psoSrc), psoMask, pco, pxlo, prclTrg, pptlSrc, pptlMask, pbo, pptlBrush, rop4);
520 VBVA_OPERATION(psoTrg, BitBlt,
521 (psoTrg, psoSrc, psoMask, pco, pxlo, prclTrg, pptlSrc, pptlMask, pbo, pptlBrush, rop4));
522
523 LOGF_LEAVE();
524 return bRc;
525}
526
527BOOL APIENTRY
528VBoxDispDrvStretchBlt(SURFOBJ *psoDest, SURFOBJ *psoSrc, SURFOBJ *psoMask, CLIPOBJ *pco, XLATEOBJ *pxlo,
529 COLORADJUSTMENT *pca, POINTL *pptlHTOrg, RECTL *prclDest, RECTL *prclSrc,
530 POINTL *pptlMask, ULONG iMode)
531{
532 BOOL bRc;
533 LOGF_ENTER();
534 STATDRVENTRY(StretchBlt, psoDest);
535
536 bRc = EngStretchBlt(getSurfObj(psoDest), getSurfObj(psoSrc), psoMask, pco, pxlo, pca, pptlHTOrg,
537 prclDest, prclSrc, pptlMask, iMode);
538 VBVA_OPERATION(psoDest, StretchBlt,
539 (psoDest, psoSrc, psoMask, pco, pxlo, pca, pptlHTOrg, prclDest, prclSrc, pptlMask, iMode));
540
541 LOGF_LEAVE();
542 return bRc;
543}
544
545BOOL APIENTRY
546VBoxDispDrvCopyBits(SURFOBJ *psoDest, SURFOBJ *psoSrc, CLIPOBJ *pco, XLATEOBJ *pxlo,
547 RECTL *prclDest, POINTL *pptlSrc)
548{
549 RECTL rclDest = *prclDest;
550 POINTL ptlSrc = *pptlSrc;
551 LOGF_ENTER();
552 STATDRVENTRY(CopyBits, psoDest);
553
554 LOG(("psoDest = %p, psoSrc = %p, pco = %p, pxlo = %p, prclDest = %p, pptlSrc = %p",
555 psoDest, psoSrc, pco, pxlo, prclDest, pptlSrc));
556 DUMPSURF(psoSrc, "psoSrc");
557 DUMPSURF(psoDest, "psoDest");
558 STATPRINT;
559
560#ifdef VBOX_VBVA_ADJUST_RECT
561 /* Experimental fix for too large bitmap updates.
562 *
563 * Some application do a large bitmap update event if only
564 * a small part of the bitmap is actually changed.
565 *
566 * The driver will find the changed rectangle by comparing
567 * the current framebuffer content with the source bitmap.
568 *
569 * The optimization is only active when:
570 * - the VBVA extension is enabled;
571 * - the source bitmap is not cacheable;
572 * - the bitmap formats of both the source and the screen surfaces are equal.
573 *
574 */
575 BOOL fDo = TRUE;
576 if ( psoSrc
577 && !VBoxDispIsScreenSurface(psoSrc)
578 && VBoxDispIsScreenSurface(psoDest))
579 {
580 PVBOXDISPDEV pDev = ((PVBOXDISPDEV))psoDest->dhpdev;
581
582 LOG(("offscreen->screen"));
583
584 if ( pDev->vbvaCtx.pVBVA
585 && (pDev->vbvaCtx.pVBVA->hostFlags.u32HostEvents & VBVA_F_MODE_ENABLED))
586 {
587 if ( (psoSrc->fjBitmap & BMF_DONTCACHE) != 0
588 || psoSrc->iUniq == 0)
589 {
590 LOG(("non-cacheable %d->%d (pDev %p)", psoSrc->iBitmapFormat, psoDest->iBitmapFormat, pDev));
591
592 /* It is possible to apply the fix. */
593 fDo = vbvaFindChangedRect(getSurfObj(psoDest), getSurfObj(psoSrc), &rclDest, &ptlSrc);
594 }
595 }
596 }
597
598 if (!fDo)
599 {
600 /* The operation is a NOP. Just return success. */
601 LOGF_LEAVE();
602 return TRUE;
603 }
604#endif /* VBOX_VBVA_ADJUST_RECT */
605
606 BOOL fRc = EngCopyBits(getSurfObj(psoDest), getSurfObj(psoSrc), pco, pxlo, &rclDest, &ptlSrc);
607 VBVA_OPERATION(psoDest, CopyBits, (psoDest, psoSrc, pco, pxlo, &rclDest, &ptlSrc));
608
609 LOGF_LEAVE();
610 return fRc;
611}
Note: See TracBrowser for help on using the repository browser.

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