VirtualBox

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

Last change on this file since 100010 was 98103, checked in by vboxsync, 2 years ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 50.4 KB
Line 
1/* $Id: VBoxDispVRDP.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * VBox XPDM Display driver
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#include "VBoxDisp.h"
29#include <VBox/RemoteDesktop/VRDEOrders.h>
30
31#define VRDP_MAKE_OP(__c) (__c)
32
33/* vrdpGetIntersectingClipRects result */
34#define VRDP_CLIP_OK 0
35#define VRDP_CLIP_NO_INTERSECTION 1
36#define VRDP_CLIP_TOO_MANY_RECTS 2
37
38typedef struct _VRDPBRUSH
39{
40 BOOL fPattern;
41
42 union {
43 struct {
44 uint32_t rgbFG;
45 uint32_t rgbBG;
46 uint8_t au8Pattern[8];
47 } pat;
48
49 struct {
50 uint16_t w;
51 uint16_t h;
52 uint32_t au32Bits[1];
53 /* Here bits continue. */
54 } bitmap;
55 } u;
56} VRDPBRUSH;
57
58#if 1
59#define dumpPCO(a, b) do {} while (0)
60#else
61static void dumpPCO(RECTL *prclTrg, CLIPOBJ *pco)
62{
63 LOG(("pco = %p Trg = %d-%d %d-%d", pco, prclTrg->left, prclTrg->right, prclTrg->top, prclTrg->bottom));
64
65 if (pco)
66 {
67 BOOL bMore;
68 CLIPRECTS cr;
69 RECTL* prclClip;
70 int cRects = 0;
71
72 LOG(("pco = %d %d-%d %d-%d dc %d fc %d mode %d opt %d",
73 pco->iUniq,
74 pco->rclBounds.left, pco->rclBounds.right, pco->rclBounds.top, pco->rclBounds.bottom,
75 pco->iDComplexity, pco->iFComplexity, pco->iMode, pco->fjOptions));
76
77 CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_ANY, 0);
78
79 do
80 {
81 bMore = CLIPOBJ_bEnum(pco, sizeof(cr), (ULONG*)&cr);
82
83 for (prclClip = &cr.arcl[0]; cr.c != 0; cr.c--, prclClip++)
84 {
85 LOG((" %d-%d %d-%d", prclClip->left, prclClip->right, prclClip->top, prclClip->bottom));
86 cRects++;
87 }
88 } while (bMore);
89
90 LOG(("Total %d rects", cRects));
91 }
92}
93#endif
94
95static uint32_t vrdpColor2RGB (SURFOBJ *pso, uint32_t color)
96{
97 uint32_t rgb = 0;
98
99 switch (pso->iBitmapFormat)
100 {
101 case BMF_16BPP:
102 {
103 uint8_t *d = (uint8_t *)&rgb;
104
105 *d++ = (BYTE)( color << 3); /* B */
106 *d++ = (BYTE)((color >> 5) << 2); /* G */
107 *d++ = (BYTE)((color >> 11) << 3); /* R */
108 } break;
109 case BMF_24BPP:
110 case BMF_32BPP:
111 {
112 rgb = color & 0xFFFFFF;
113 } break;
114 default:
115 WARN(("Unsupported bitmap format %d", pso->iBitmapFormat));
116 }
117
118 return rgb;
119}
120
121static void vrdpPointFX2Point(const POINTFIX *pptfx, VRDEORDERPOINT *ppt)
122{
123 ppt->x = (int16_t)FXTOLROUND(pptfx->x);
124 ppt->y = (int16_t)FXTOLROUND(pptfx->y);
125}
126
127static void vrdpPolyPointsAdd(VRDEORDERPOLYPOINTS *pPoints, const VRDEORDERPOINT *ppt)
128{
129 Assert(pPoints->c < RT_ELEMENTS(pPoints->a));
130
131 pPoints->a[pPoints->c] = *ppt;
132
133 pPoints->c++;
134}
135
136static void vrdpExtendOrderBounds(VRDEORDERBOUNDS *pBounds, const VRDEORDERPOINT *ppt)
137{
138 /* Bounds have inclusive pt1 and exclusive pt2. */
139
140 if (pBounds->pt1.x > ppt->x) /* Left. */
141 {
142 pBounds->pt1.x = ppt->x;
143 }
144 if (pBounds->pt1.y > ppt->y) /* Top. */
145 {
146 pBounds->pt1.y = ppt->y;
147 }
148 if (pBounds->pt2.x <= ppt->x) /* Right. */
149 {
150 pBounds->pt2.x = ppt->x + 1;
151 }
152 if (pBounds->pt2.y <= ppt->y) /* Bottom. */
153 {
154 pBounds->pt2.y = ppt->y + 1;
155 }
156}
157
158static void vrdpOrderRect(RECTL *prcl)
159{
160 int tmp;
161
162 if (prcl->left > prcl->right)
163 {
164 WARN(("Inverse X coordinates"));
165
166 tmp = prcl->left;
167 prcl->left = prcl->right;
168 prcl->right = tmp;
169 }
170
171 if (prcl->top > prcl->bottom)
172 {
173 WARN(("Inverse Y coordinates"));
174
175 tmp = prcl->top;
176 prcl->top = prcl->bottom;
177 prcl->bottom = tmp;
178 }
179}
180
181static BOOL vrdpIsRectEmpty (const RECTL *prcl)
182{
183 return (prcl->left == prcl->right) || (prcl->top == prcl->bottom);
184}
185
186static void vrdpIntersectRects(RECTL *prectResult, const RECTL *prect1, const RECTL *prect2)
187{
188 /* Calculations are easier with left, right, top, bottom. */
189 int xLeft1 = prect1->left;
190 int xRight1 = prect1->right;
191
192 int xLeft2 = prect2->left;
193 int xRight2 = prect2->right;
194
195 int yTop1 = prect1->top;
196 int yBottom1 = prect1->bottom;
197
198 int yTop2 = prect2->top;
199 int yBottom2 = prect2->bottom;
200
201 int xLeftResult = max (xLeft1, xLeft2);
202 int xRightResult = min (xRight1, xRight2);
203
204 /* Initialize result to empty record. */
205 memset (prectResult, 0, sizeof (RECTL));
206
207 if (xLeftResult < xRightResult)
208 {
209 /* There is intersection by X. */
210
211 int yTopResult = max (yTop1, yTop2);
212 int yBottomResult = min (yBottom1, yBottom2);
213
214 if (yTopResult < yBottomResult)
215 {
216 /* There is intersection by Y. */
217
218 prectResult->left = xLeftResult;
219 prectResult->top = yTopResult;
220 prectResult->right = xRightResult;
221 prectResult->bottom = yBottomResult;
222 }
223 }
224
225 return;
226}
227
228void vrdpAdjustRect(SURFOBJ *pso, RECTL *prcl)
229{
230 int x;
231 int y;
232 int w;
233 int h;
234
235 LOGF(("%d-%d %d-%d on %dx%d\n", prcl->left, prcl->right, prcl->top, prcl->bottom, pso->sizlBitmap.cx, pso->sizlBitmap.cy));
236
237 if (prcl->left <= prcl->right)
238 {
239 x = prcl->left;
240 w = prcl->right - prcl->left;
241 }
242 else
243 {
244 WARN(("Inverse X coordinates"));
245 x = prcl->right;
246 w = prcl->left - prcl->right;
247 }
248
249 if (prcl->top <= prcl->bottom)
250 {
251 y = prcl->top;
252 h = prcl->bottom - prcl->top;
253 }
254 else
255 {
256 WARN(("Inverse Y coordinates"));
257 y = prcl->bottom;
258 h = prcl->top - prcl->bottom;
259 }
260
261 Assert(w >= 0 && h >= 0);
262
263 /* Correct negative x and y coordinates. */
264 if (x < 0)
265 {
266 x += w; /* Compute xRight which is also the new width. */
267
268 w = (x < 0)? 0: x;
269
270 x = 0;
271 }
272
273 if (y < 0)
274 {
275 y += h; /* Compute xBottom, which is also the new height. */
276
277 h = (y < 0)? 0: y;
278
279 y = 0;
280 }
281
282 /* Also check if coords are greater than the display resolution. */
283 if (x + w > pso->sizlBitmap.cx)
284 {
285 w = pso->sizlBitmap.cx > x? pso->sizlBitmap.cx - x: 0;
286 }
287
288 if (y + h > pso->sizlBitmap.cy)
289 {
290 h = pso->sizlBitmap.cy > y? pso->sizlBitmap.cy - y: 0;
291 }
292
293 prcl->left = x;
294 prcl->top = y;
295 prcl->right = x + w;
296 prcl->bottom = y + h;
297
298 LOGF(("result %d-%d %d-%d", prcl->left, prcl->right, prcl->top, prcl->bottom));
299}
300
301static int vrdpGetIntersectingClipRects(VRDPCLIPRECTS *pClipRects, SURFOBJ *pso, RECTL *prcl, CLIPOBJ *pco, POINTL *pptlSrc)
302{
303 BOOL bTooManyRects = FALSE;
304
305 LOGF(("pso = %p, pptlSrc = %p", pso, pptlSrc));
306
307 pso = getSurfObj(pso);
308
309 pClipRects->rclDstOrig = *prcl;
310 pClipRects->rclDst = *prcl;
311 pClipRects->rects.c = 0;
312
313 vrdpAdjustRect(pso, &pClipRects->rclDst);
314
315 if (pco && (pco->iDComplexity != DC_TRIVIAL))
316 {
317 ULONG iDirection = CD_ANY;
318
319 if (pptlSrc)
320 {
321 /* Operation is performed on the same (screen) surface and enumeration direction
322 * must take into account the position of source and target rectangles.
323 */
324 if (pptlSrc->x <= prcl->left)
325 {
326 if (pptlSrc->y <= prcl->top)
327 {
328 iDirection = CD_LEFTUP;
329 }
330 else
331 {
332 iDirection = CD_LEFTDOWN;
333 }
334 }
335 else
336 {
337 if (pptlSrc->y <= prcl->top)
338 {
339 iDirection = CD_RIGHTUP;
340 }
341 else
342 {
343 iDirection = CD_RIGHTDOWN;
344 }
345 }
346 }
347
348 /* Clip the target rect by entire clipping region. Obtain the effective target. */
349 vrdpIntersectRects(&pClipRects->rclDst, &pClipRects->rclDst, &pco->rclBounds);
350
351 /* Enumerate rectangles. Try to get all rectangles at once and if there is not
352 * enough space (too many rectangles) fail with the bTooManyRects condition.
353 */
354 CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, iDirection, 0);
355
356 bTooManyRects = CLIPOBJ_bEnum(pco, sizeof(pClipRects->rects), &pClipRects->rects.c);
357
358 if (!bTooManyRects)
359 {
360 RECTL *prclClipSrc = &pClipRects->rects.arcl[0];
361 RECTL *prclClipDst = prclClipSrc;
362
363 ULONG cRects = pClipRects->rects.c;
364
365 LOGF(("%d rects", cRects));
366
367 if (cRects > 0)
368 {
369 for (; cRects != 0; cRects--, prclClipSrc++)
370 {
371 vrdpIntersectRects(prclClipDst, prclClipSrc, &pClipRects->rclDst);
372
373 if (vrdpIsRectEmpty(prclClipDst))
374 {
375 pClipRects->rects.c--;
376 }
377 else
378 {
379 prclClipDst++;
380 }
381 }
382 }
383
384 if (pClipRects->rects.c == 0)
385 {
386 pClipRects->rclDst.left = pClipRects->rclDst.right = 0;
387 }
388 LOGF(("%d rects remains", pClipRects->rects.c));
389 }
390 }
391
392 if (vrdpIsRectEmpty(&pClipRects->rclDst))
393 {
394 return VRDP_CLIP_NO_INTERSECTION;
395 }
396
397 if (bTooManyRects)
398 {
399 pClipRects->rects.c = 0;
400
401 return VRDP_CLIP_TOO_MANY_RECTS;
402 }
403
404 return VRDP_CLIP_OK;
405}
406
407static void vrdpReportDirtyPathBounds(PVBOXDISPDEV pDev, CLIPOBJ *pco, PATHOBJ *ppo)
408{
409 RECTFX rcfxBounds;
410 RECTL rclBounds;
411
412 PATHOBJ_vGetBounds(ppo, &rcfxBounds);
413
414 rclBounds.left = FXTOLFLOOR(rcfxBounds.xLeft);
415 rclBounds.right = FXTOLCEILING(rcfxBounds.xRight);
416 rclBounds.top = FXTOLFLOOR(rcfxBounds.yTop);
417 rclBounds.bottom = FXTOLCEILING(rcfxBounds.yBottom);
418
419 vrdpIntersectRects(&rclBounds, &rclBounds, &pco->rclBounds);
420
421 vrdpReportDirtyRect(pDev, &rclBounds);
422}
423
424static void vrdpReportDirtyPath(PVBOXDISPDEV pDev, CLIPOBJ *pco, PATHOBJ *ppo)
425{
426 vrdpReportDirtyPathBounds(pDev, pco, ppo);
427}
428
429static void vrdpReportDirtyClip(PVBOXDISPDEV pDev, CLIPOBJ *pco, RECTL *prcl)
430{
431 if (prcl)
432 {
433 vrdpReportDirtyRect(pDev, prcl);
434 }
435 else if (pco)
436 {
437 vrdpReportDirtyRect(pDev, &pco->rclBounds);
438 }
439}
440
441static void vrdpReportDirtyRects(PVBOXDISPDEV pDev, VRDPCLIPRECTS *pClipRects)
442{
443 /* Ignore rects, report entire area. */
444 vrdpReportDirtyRect (pDev, &pClipRects->rclDst);
445}
446
447__inline BOOL vrdpWriteHdr (PVBOXDISPDEV pDev, uint32_t u32Op)
448{
449 return VBoxVBVAWrite(&pDev->vbvaCtx, &pDev->hgsmi.ctx, &u32Op, sizeof (u32Op));
450}
451
452static BOOL vrdpWriteBits (PVBOXDISPDEV pDev, uint8_t *pu8Bits, int lDelta, int32_t x, int32_t y, uint32_t cWidth, uint32_t cHeight, int bytesPerPixel)
453{
454 BOOL bRc = FALSE;
455
456 VRDEDATABITS bits;
457
458 bits.cb = cHeight * cWidth * bytesPerPixel;
459 bits.x = (int16_t)x;
460 bits.y = (int16_t)y;
461 bits.cWidth = (uint16_t)cWidth;
462 bits.cHeight = (uint16_t)cHeight;
463 bits.cbPixel = (uint8_t)bytesPerPixel;
464
465 bRc = VBoxVBVAWrite(&pDev->vbvaCtx, &pDev->hgsmi.ctx, &bits, sizeof (bits));
466
467 if (bRc)
468 {
469 while (cHeight--)
470 {
471 bRc = VBoxVBVAWrite(&pDev->vbvaCtx, &pDev->hgsmi.ctx, pu8Bits, cWidth * bytesPerPixel);
472
473 if (!bRc)
474 {
475 break;
476 }
477
478 pu8Bits += lDelta;
479 }
480 }
481
482 return bRc;
483}
484
485/*
486 * RDP orders reporting.
487 */
488static BOOL vrdpReportOrder(PVBOXDISPDEV pDev, const void *pOrder, unsigned cbOrder, unsigned code)
489{
490 BOOL bRc = vrdpWriteHdr(pDev, VRDP_MAKE_OP(code));
491
492 if (bRc)
493 {
494 VBoxVBVAWrite(&pDev->vbvaCtx, &pDev->hgsmi.ctx, pOrder, cbOrder);
495 }
496
497 return bRc;
498}
499
500static BOOL vrdpReportBounds(PVBOXDISPDEV pDev, const RECTL *prcl)
501{
502 VRDEORDERBOUNDS bounds;
503
504 bounds.pt1.x = (int16_t)(prcl->left);
505 bounds.pt1.y = (int16_t)(prcl->top);
506 bounds.pt2.x = (int16_t)(prcl->right);
507 bounds.pt2.y = (int16_t)(prcl->bottom);
508
509 return vrdpReportOrder(pDev, &bounds, sizeof (bounds), VRDE_ORDER_BOUNDS);
510}
511
512static BOOL vrdpReportRepeat(PVBOXDISPDEV pDev, const CLIPRECTS *pRects)
513{
514 BOOL bRc = TRUE;
515
516 if (pRects)
517 {
518 /* Start from index 1, because the first rect was already reported. */
519 unsigned i = 1;
520 const RECTL *prcl = &pRects->arcl[1];
521
522 for (; i < pRects->c; i++, prcl++)
523 {
524 VRDEORDERREPEAT repeat;
525
526 repeat.bounds.pt1.x = (int16_t)(prcl->left);
527 repeat.bounds.pt1.y = (int16_t)(prcl->top);
528 repeat.bounds.pt2.x = (int16_t)(prcl->right);
529 repeat.bounds.pt2.y = (int16_t)(prcl->bottom);
530
531 bRc = vrdpReportOrder(pDev, &repeat, sizeof (repeat), VRDE_ORDER_REPEAT);
532
533 if (!bRc)
534 {
535 return bRc;
536 }
537 }
538 }
539
540 return bRc;
541}
542
543void vrdpReportDirtyRect(PVBOXDISPDEV pDev, RECTL *prcl)
544{
545 SURFOBJ *pso = pDev->surface.psoBitmap;
546
547 /* This is a Bitmap Update Fallback operation. It takes bits from VRAM
548 * and inserts them in the pipeline. These bits are not cached.
549 */
550
551 uint8_t *pu8Bits;
552 int32_t lDelta;
553 uint32_t cWidth;
554 uint32_t cHeight;
555
556 BOOL bRc = FALSE;
557
558 int bytesPerPixel = format2BytesPerPixel(pso);
559
560 RECTL rclCopy = *prcl;
561
562 vrdpAdjustRect (pso, &rclCopy);
563
564 pu8Bits = (uint8_t *)pso->pvScan0 +
565 pso->lDelta * rclCopy.top +
566 bytesPerPixel * rclCopy.left;
567 lDelta = pso->lDelta;
568 cWidth = rclCopy.right - rclCopy.left;
569 cHeight = rclCopy.bottom - rclCopy.top;
570
571 if (cWidth == 0 || cHeight == 0)
572 {
573 return;
574 }
575
576 if (bytesPerPixel > 0)
577 {
578 bRc = vrdpWriteHdr(pDev, VRDP_MAKE_OP(VRDE_ORDER_DIRTY_RECT));
579
580 if (bRc)
581 {
582 bRc = vrdpWriteBits(pDev, pu8Bits, lDelta, rclCopy.left, rclCopy.top, cWidth, cHeight, bytesPerPixel);
583 }
584 }
585
586 if (!bRc)
587 {
588 WARN(("failed!!! %d,%d %dx%d, bpp = %d\n",
589 rclCopy.left, rclCopy.top, cWidth, cHeight, bytesPerPixel));
590 }
591}
592
593static BOOL vrdpIntersectRectWithBounds (RECTL *prclIntersect,
594 const RECTL *prcl,
595 const VRDEORDERBOUNDS *pBounds)
596{
597 if ( prcl->left < pBounds->pt2.x /* left < bounds_right */
598 && prcl->right > pBounds->pt1.x /* right < bounds_left */
599 && prcl->top < pBounds->pt2.y /* top < bounds_bottom */
600 && prcl->bottom > pBounds->pt1.y /* bottom < bounds_top */
601 )
602 {
603 /* There is intersection. */
604 prclIntersect->left = max(prcl->left, pBounds->pt1.x);
605 prclIntersect->right = min(prcl->right, pBounds->pt2.x);
606 prclIntersect->top = max(prcl->top, pBounds->pt1.y);
607 prclIntersect->bottom = min(prcl->bottom, pBounds->pt2.y);
608
609 Assert(prclIntersect->left < prclIntersect->right);
610 Assert(prclIntersect->top < prclIntersect->bottom);
611
612 return TRUE;
613 }
614
615 /* No intersection. */
616 return FALSE;
617}
618
619static BOOL vrdpGetIntersectingRects (CLIPRECTS *pRects,
620 const VRDPCLIPRECTS *pClipRects,
621 const VRDEORDERBOUNDS *pBounds)
622{
623 BOOL fReportOrder = TRUE;
624
625 pRects->c = 0; /* Number of clipping rects. */
626
627 if (pClipRects->rects.c == 0)
628 {
629 /* There were no clipping for the order. Therefore do nothing
630 * here and just return that order must be reported without
631 * clipping (rc = TRUE, pRects->c = 0).
632 */
633 /* Do nothing. */
634 }
635 else
636 {
637 /* Find which clipping rects intersect with the bounds. */
638 unsigned c = 0;
639 RECTL *prclIntersect = &pRects->arcl[0];
640
641 unsigned i = 0;
642 const RECTL *prcl = &pClipRects->rects.arcl[0];
643
644 for (; i < pClipRects->rects.c; i++, prcl++)
645 {
646 if (vrdpIntersectRectWithBounds (prclIntersect, prcl, pBounds))
647 {
648 c++;
649 prclIntersect++;
650 }
651 }
652
653 if (c == 0)
654 {
655 /* No of clip rects intersect with the bounds. */
656 fReportOrder = FALSE;
657 }
658 else
659 {
660 pRects->c = c;
661 }
662 }
663
664 return fReportOrder;
665}
666
667BOOL vrdpReportOrderGeneric (PVBOXDISPDEV pDev,
668 const VRDPCLIPRECTS *pClipRects,
669 const void *pvOrder,
670 unsigned cbOrder,
671 unsigned code)
672{
673 BOOL bRc;
674
675 if (pClipRects && pClipRects->rects.c > 0)
676 {
677 bRc = vrdpReportBounds (pDev, &pClipRects->rects.arcl[0]);
678
679 if (!bRc)
680 {
681 return bRc;
682 }
683 }
684
685 bRc = vrdpReportOrder (pDev, pvOrder, cbOrder, code);
686
687 if (!bRc)
688 {
689 return bRc;
690 }
691
692 if (pClipRects && pClipRects->rects.c > 1)
693 {
694 bRc = vrdpReportRepeat (pDev, &pClipRects->rects);
695 }
696
697 return bRc;
698}
699
700static void vrdpReportOrderGenericBounds (PVBOXDISPDEV pDev,
701 const VRDPCLIPRECTS *pClipRects,
702 const VRDEORDERBOUNDS *pBounds,
703 const void *pvOrder,
704 unsigned cbOrder,
705 unsigned code)
706{
707 CLIPRECTS rects;
708
709 if (vrdpGetIntersectingRects (&rects, pClipRects, pBounds))
710 {
711 vrdpReportOrderGeneric (pDev, pClipRects, pvOrder, cbOrder, code);
712 }
713}
714
715static void vrdpReportSolidRect (PVBOXDISPDEV pDev,
716 const RECTL *prclTrg,
717 VRDPCLIPRECTS *pClipRects,
718 ULONG rgb)
719{
720 VRDEORDERSOLIDRECT order;
721
722 order.x = (int16_t)prclTrg->left;
723 order.y = (int16_t)prclTrg->top;
724 order.w = (uint16_t)(prclTrg->right - prclTrg->left);
725 order.h = (uint16_t)(prclTrg->bottom - prclTrg->top);
726 order.rgb = rgb;
727
728 vrdpReportOrderGeneric (pDev, pClipRects, &order, sizeof (order), VRDE_ORDER_SOLIDRECT);
729}
730
731static void vrdpReportSolidBlt (PVBOXDISPDEV pDev,
732 const RECTL *prclTrg,
733 VRDPCLIPRECTS *pClipRects,
734 ULONG rgb,
735 uint8_t rop3)
736{
737 VRDEORDERSOLIDBLT order;
738
739 order.x = (int16_t)prclTrg->left;
740 order.y = (int16_t)prclTrg->top;
741 order.w = (uint16_t)(prclTrg->right - prclTrg->left);
742 order.h = (uint16_t)(prclTrg->bottom - prclTrg->top);
743 order.rgb = rgb;
744 order.rop = rop3;
745
746 vrdpReportOrderGeneric (pDev, pClipRects, &order, sizeof (order), VRDE_ORDER_SOLIDBLT);
747}
748
749static void vrdpReportPatBlt (PVBOXDISPDEV pDev,
750 const RECTL *prclTrg,
751 VRDPCLIPRECTS *pClipRects,
752 VRDPBRUSH *pBrush,
753 POINTL *pptlBrush,
754 uint8_t rop3)
755{
756 VRDEORDERPATBLTBRUSH order;
757
758 int8_t xSrc = 0;
759 int8_t ySrc = 0;
760
761 if (pptlBrush)
762 {
763 LOG(("Dst %d,%d Brush origin %d,%d", prclTrg->left, prclTrg->top, pptlBrush->x, pptlBrush->y));
764
765 /* Make sure that the coords fit in a 8 bit value.
766 * Only 8x8 pixel brushes are supported, so last 3 bits
767 * is a [0..7] coordinate of the brush, because the brush
768 * repeats after each 8 pixels.
769 */
770 xSrc = (int8_t)(pptlBrush->x & 7);
771 ySrc = (int8_t)(pptlBrush->y & 7);
772 }
773
774 order.x = (int16_t)prclTrg->left;
775 order.y = (int16_t)prclTrg->top;
776 order.w = (uint16_t)(prclTrg->right - prclTrg->left);
777 order.h = (uint16_t)(prclTrg->bottom - prclTrg->top);
778 order.xSrc = xSrc;
779 order.ySrc = ySrc;
780 order.rgbFG = pBrush->u.pat.rgbFG;
781 order.rgbBG = pBrush->u.pat.rgbBG;
782 order.rop = rop3;
783
784 memcpy (order.pattern, pBrush->u.pat.au8Pattern, sizeof (order.pattern));
785
786 vrdpReportOrderGeneric (pDev, pClipRects, &order, sizeof (order), VRDE_ORDER_PATBLTBRUSH);
787}
788
789static void vrdpReportDstBlt (PVBOXDISPDEV pDev,
790 const RECTL *prclTrg,
791 VRDPCLIPRECTS *pClipRects,
792 uint8_t rop3)
793{
794 VRDEORDERDSTBLT order;
795
796 order.x = (int16_t)prclTrg->left;
797 order.y = (int16_t)prclTrg->top;
798 order.w = (uint16_t)(prclTrg->right - prclTrg->left);
799 order.h = (uint16_t)(prclTrg->bottom - prclTrg->top);
800 order.rop = rop3;
801
802 vrdpReportOrderGeneric (pDev, pClipRects, &order, sizeof (order), VRDE_ORDER_DSTBLT);
803}
804
805static void vrdpReportScreenBlt (PVBOXDISPDEV pDev,
806 const RECTL *prclTrg,
807 VRDPCLIPRECTS *pClipRects,
808 POINTL *pptlSrc,
809 uint8_t rop3)
810{
811 VRDEORDERSCREENBLT order;
812
813 order.x = (int16_t)prclTrg->left;
814 order.y = (int16_t)prclTrg->top;
815 order.w = (uint16_t)(prclTrg->right - prclTrg->left);
816 order.h = (uint16_t)(prclTrg->bottom - prclTrg->top);
817 order.xSrc = (int16_t)pptlSrc->x;
818 order.ySrc = (int16_t)pptlSrc->y;
819 order.rop = rop3;
820
821 vrdpReportOrderGeneric (pDev, pClipRects, &order, sizeof (order), VRDE_ORDER_SCREENBLT);
822}
823
824static void vrdpReportMemBltRect (PVBOXDISPDEV pDev,
825 RECTL *prcl,
826 int xSrc,
827 int ySrc,
828 uint8_t rop3,
829 const VRDPBCHASH *phash)
830{
831 VRDEORDERMEMBLT order;
832
833 order.x = (int16_t)prcl->left;
834 order.y = (int16_t)prcl->top;
835 order.w = (uint16_t)(prcl->right - prcl->left);
836 order.h = (uint16_t)(prcl->bottom - prcl->top);
837 order.xSrc = (int16_t)xSrc;
838 order.ySrc = (int16_t)ySrc;
839 order.rop = rop3;
840
841 Assert(sizeof (*phash) == sizeof (order.hash));
842 memcpy (order.hash, phash, sizeof (*phash));
843
844 vrdpReportOrder (pDev, &order, sizeof (order), VRDE_ORDER_MEMBLT);
845}
846
847static void vrdpReportMemBlt (PVBOXDISPDEV pDev,
848 VRDPCLIPRECTS *pClipRects,
849 POINTL *pptlSrc,
850 const uint8_t rop3,
851 const VRDPBCHASH *phash)
852{
853 if (pClipRects->rects.c == 0)
854 {
855 int xShift = pClipRects->rclDst.left - pClipRects->rclDstOrig.left;
856 int yShift = pClipRects->rclDst.top - pClipRects->rclDstOrig.top;
857
858 Assert(xShift >= 0 && yShift >= 0);
859
860 vrdpReportMemBltRect (pDev, &pClipRects->rclDst, pptlSrc->x + xShift, pptlSrc->y + yShift, rop3, phash);
861 }
862 else
863 {
864 ULONG i;
865 for (i = 0; i < pClipRects->rects.c; i++)
866 {
867 int xShift = pClipRects->rects.arcl[i].left - pClipRects->rclDstOrig.left;
868 int yShift = pClipRects->rects.arcl[i].top - pClipRects->rclDstOrig.top;
869
870 Assert(xShift >= 0 && yShift >= 0);
871
872 vrdpReportMemBltRect (pDev, &pClipRects->rects.arcl[i], pptlSrc->x + xShift, pptlSrc->y + yShift, rop3, phash);
873 }
874 }
875}
876
877static void vrdpReportCachedBitmap (PVBOXDISPDEV pDev,
878 SURFOBJ *psoSrc,
879 const VRDPBCHASH *phash)
880{
881 BOOL bRc;
882
883 VRDEORDERCACHEDBITMAP order;
884
885 Assert(sizeof (*phash) == sizeof (order.hash));
886 memcpy (order.hash, phash, sizeof (*phash));
887
888 bRc = vrdpReportOrder (pDev, &order, sizeof (order), VRDE_ORDER_CACHED_BITMAP);
889
890 if (bRc)
891 {
892 int bytesPerPixel = format2BytesPerPixel(psoSrc);
893
894 uint8_t *pu8Bits = (uint8_t *)psoSrc->pvScan0;
895 int32_t lDelta = psoSrc->lDelta;
896 uint32_t cWidth = psoSrc->sizlBitmap.cx;
897 uint32_t cHeight = psoSrc->sizlBitmap.cy;
898
899 Assert(cWidth != 0 && cHeight != 0 && bytesPerPixel != 0);
900
901 vrdpWriteBits (pDev, pu8Bits, lDelta, 0, 0, cWidth, cHeight, bytesPerPixel);
902 }
903}
904
905static void vrdpReportDeletedBitmap (PVBOXDISPDEV pDev,
906 const VRDPBCHASH *phash)
907{
908 VRDEORDERDELETEDBITMAP order;
909
910 Assert(sizeof (*phash) == sizeof (order.hash));
911 memcpy (order.hash, phash, sizeof (*phash));
912
913 vrdpReportOrder (pDev, &order, sizeof (order), VRDE_ORDER_DELETED_BITMAP);
914}
915
916
917void vrdpReset(PVBOXDISPDEV pDev)
918{
919 LOGF(("%p", pDev));
920
921 vrdpbmpReset(&pDev->vrdpCache);
922
923 return;
924}
925
926/*
927 * VRDP driver functions.
928 */
929
930void vrdpDrvLineTo(SURFOBJ *pso, CLIPOBJ *pco, BRUSHOBJ *pbo,
931 LONG x1, LONG y1, LONG x2, LONG y2, RECTL *prclBounds, MIX mix)
932{
933 PVBOXDISPDEV pDev = (PVBOXDISPDEV)pso->dhpdev;
934
935 /*
936 * LineTo operation is supported by RDP_ORDER_LINE.
937 */
938 VRDPCLIPRECTS clipRects;
939 int clipResult;
940 RECTL rclBoundsOrdered = *prclBounds;
941
942 vrdpOrderRect(&rclBoundsOrdered);
943
944 clipResult = vrdpGetIntersectingClipRects(&clipRects, pso, &rclBoundsOrdered, pco, NULL);
945
946 if (clipResult == VRDP_CLIP_NO_INTERSECTION)
947 {
948 /* Do nothing. The Blt does not affect anything. */
949 LOG(("VRDP_CLIP_NO_INTERSECTION!!!"));
950 dumpPCO(&rclBoundsOrdered, pco);
951 }
952 else if (clipResult == VRDP_CLIP_TOO_MANY_RECTS)
953 {
954 /* A very complex clip. Better to emulate it. */
955 LOG(("VRDP_CLIP_TOO_MANY_RECTS!!!"));
956 dumpPCO(&rclBoundsOrdered, pco);
957
958 vrdpReportDirtyRects(pDev, &clipRects);
959 }
960 else if (pbo->iSolidColor == 0xFFFFFFFF)
961 {
962 /* Not solid brushes are not supported. */
963 vrdpReportDirtyRects(pDev, &clipRects);
964 }
965 else
966 {
967 VRDEORDERLINE order;
968
969 order.x1 = (int16_t)x1;
970 order.y1 = (int16_t)y1;
971 order.x2 = (int16_t)x2;
972 order.y2 = (int16_t)y2;
973
974 order.xBounds1 = ~0;
975 order.yBounds1 = ~0;
976 order.xBounds2 = ~0;
977 order.yBounds2 = ~0;
978
979 order.mix = (uint8_t)(mix & 0x1F);
980 order.rgb = vrdpColor2RGB (pso, pbo->iSolidColor);
981
982 LOG(("LINE %d,%d to %d,%d mix %02X rgb %08X bounds %d-%d %d-%d cliprects %d.",
983 x1, y1, x2, y2, order.mix, order.rgb,
984 prclBounds->left, prclBounds->right, prclBounds->top, prclBounds->bottom, clipRects.rects.c));
985
986 vrdpReportOrderGeneric(pDev, &clipRects, &order, sizeof (order), VRDE_ORDER_LINE);
987 }
988}
989
990void vrdpDrvStrokePath(SURFOBJ *pso, PATHOBJ *ppo, CLIPOBJ *pco, XFORMOBJ *pxo,
991 BRUSHOBJ *pbo, POINTL *pptlBrushOrg, LINEATTRS *plineattrs, MIX mix)
992{
993 RT_NOREF(pxo, pptlBrushOrg);
994 PVBOXDISPDEV pDev = (PVBOXDISPDEV)pso->dhpdev;
995
996 /*
997 * StrokePath operation is supported by RDP_ORDER_POLYGON/POLYLINE/ELLIPSE.
998 */
999 VRDPCLIPRECTS clipRects;
1000 int clipResult;
1001 RECTFX rcfxBounds;
1002 RECTL rclBoundsOrdered;
1003
1004 LOGF(("pso = %p, ppo = %p, pco = %p, pxo = %p, pbo = %p, pptlBrushOrg = %p, plineattrs = %p, mix = 0x%08X",
1005 pso, ppo, pco, pxo, pbo, pptlBrushOrg, plineattrs, mix));
1006 LOGF(("ppo: fl = 0x%08X, cCurves = %d", ppo->fl, ppo->cCurves));
1007
1008 PATHOBJ_vGetBounds(ppo, &rcfxBounds);
1009
1010 rclBoundsOrdered.left = FXTOLFLOOR(rcfxBounds.xLeft);
1011 rclBoundsOrdered.right = FXTOLCEILING(rcfxBounds.xRight);
1012 rclBoundsOrdered.top = FXTOLFLOOR(rcfxBounds.yTop);
1013 rclBoundsOrdered.bottom = FXTOLCEILING(rcfxBounds.yBottom);
1014
1015 vrdpOrderRect(&rclBoundsOrdered);
1016
1017 LOG(("ppo: bounds %x-%x, %x-%x, %d-%d %d-%d",
1018 rcfxBounds.xLeft, rcfxBounds.xRight, rcfxBounds.yTop, rcfxBounds.yBottom,
1019 rclBoundsOrdered.left, rclBoundsOrdered.right, rclBoundsOrdered.top, rclBoundsOrdered.bottom));
1020
1021 clipResult = vrdpGetIntersectingClipRects(&clipRects, pso, &rclBoundsOrdered, pco, NULL);
1022
1023 if (clipResult == VRDP_CLIP_NO_INTERSECTION)
1024 {
1025 /* Do nothing. The operation does not affect anything. */
1026 LOG(("VRDP_CLIP_NO_INTERSECTION!!!"));
1027 dumpPCO (&rclBoundsOrdered, pco);
1028 }
1029 else if (clipResult == VRDP_CLIP_TOO_MANY_RECTS)
1030 {
1031 /* A very complex clip. Better to emulate it. */
1032 LOG(("VRDP_CLIP_TOO_MANY_RECTS!!!"));
1033 dumpPCO (&rclBoundsOrdered, pco);
1034
1035 vrdpReportDirtyRects(pDev, &clipRects);
1036 }
1037 else if (pbo->iSolidColor == 0xFFFFFFFF)
1038 {
1039 /* Not solid brushes are not supported. */
1040 vrdpReportDirtyRects(pDev, &clipRects);
1041 }
1042 else if (ppo->fl & PO_ELLIPSE)
1043 {
1044 if (VBoxVBVAOrderSupported(&pDev->vbvaCtx, VRDE_ORDER_ELLIPSE))
1045 {
1046 VRDEORDERELLIPSE order;
1047
1048 order.pt1.x = (int16_t)FXTOLROUND(rcfxBounds.xLeft + 4);
1049 order.pt1.y = (int16_t)FXTOLROUND(rcfxBounds.yTop + 4);
1050 order.pt2.x = (int16_t)FXTOLROUND(rcfxBounds.xRight - 4);
1051 order.pt2.y = (int16_t)FXTOLROUND(rcfxBounds.yBottom - 4);
1052
1053 order.mix = (uint8_t)(mix & 0x1F);
1054 order.fillMode = 0;
1055 order.rgb = vrdpColor2RGB(pso, pbo->iSolidColor);
1056
1057 vrdpReportOrderGeneric(pDev, &clipRects, &order, sizeof (order), VRDE_ORDER_ELLIPSE);
1058 }
1059 else
1060 {
1061 WARN(("ELLIPSE not supported"));
1062 vrdpReportDirtyRects (pDev, &clipRects);
1063 }
1064 }
1065 else if ( (ppo->fl & PO_BEZIERS) == 0
1066 && (plineattrs->fl & LA_GEOMETRIC) == 0
1067 && plineattrs->pstyle == NULL)
1068 {
1069 unsigned i;
1070 PATHDATA pd;
1071 BOOL bMore;
1072 VRDEORDERPOLYLINE order;
1073 /** @todo it is not immediately obvious how we're sure ptStart isn't used uninitialized. */
1074 VRDEORDERPOINT ptStart = { 0, 0 }; /* Shut up MSC */
1075 VRDEORDERBOUNDS bounds;
1076
1077 order.rgb = vrdpColor2RGB(pso, pbo->iSolidColor);
1078 order.mix = (uint8_t)(mix & 0x1F);
1079
1080 PATHOBJ_vEnumStart(ppo);
1081
1082 order.points.c = 0;
1083
1084 do {
1085 POINTFIX *pptfx;
1086 /** @todo it is not immediately obvious how we're sure pt isn't used uninitialized. */
1087 VRDEORDERPOINT pt = {0, 0}; /* Shut up MSC */
1088
1089 bMore = PATHOBJ_bEnum (ppo, &pd);
1090
1091 LOG(("pd: flags = 0x%08X, count = %d", pd.flags, pd.count));
1092
1093 pptfx = &pd.pptfx[0];
1094
1095 if (pd.flags & PD_BEGINSUBPATH)
1096 {
1097 /* Setup first point. Start a new order. */
1098 LOG(("BEGINSUBPATH"));
1099
1100 Assert(order.points.c == 0);
1101
1102 vrdpPointFX2Point(pptfx, &ptStart);
1103 order.ptStart = ptStart;
1104 pt = ptStart;
1105
1106 bounds.pt1 = bounds.pt2 = ptStart;
1107
1108 pptfx++;
1109 i = 1;
1110 }
1111 else
1112 {
1113 LOG(("Continue order"));
1114
1115 i = 0;
1116 }
1117
1118 for (; i < pd.count; i++, pptfx++)
1119 {
1120 LOG(("pd: %2d: %x,%x %d,%d",
1121 i, pptfx->x, pptfx->y, FXTOLROUND(pptfx->x), FXTOLROUND(pptfx->y)));
1122
1123 vrdpPointFX2Point (pptfx, &pt);
1124 vrdpPolyPointsAdd (&order.points, &pt);
1125 vrdpExtendOrderBounds (&bounds, &pt);
1126
1127 if (order.points.c == RT_ELEMENTS(order.points.a))
1128 {
1129 /* Flush the order and start a new order. */
1130 LOG(("Report order, points overflow."));
1131
1132 vrdpReportOrderGenericBounds(pDev, &clipRects, &bounds, &order, sizeof (order), VRDE_ORDER_POLYLINE);
1133
1134 order.points.c = 0;
1135 order.ptStart = pt;
1136 bounds.pt1 = bounds.pt2 = pt;
1137 }
1138 }
1139
1140 if (pd.flags & PD_CLOSEFIGURE)
1141 {
1142 /* Encode the start point as the end point. */
1143 LOG(("Report order, CLOSEFIGURE"));
1144
1145 if ( ptStart.x != pt.x
1146 || ptStart.y != pt.y)
1147 {
1148 Assert(order.points.c < RT_ELEMENTS(order.points.a));
1149
1150 vrdpPolyPointsAdd (&order.points, &ptStart);
1151 vrdpExtendOrderBounds (&bounds, &ptStart);
1152 }
1153 }
1154
1155 if (pd.flags & PD_ENDSUBPATH)
1156 {
1157 /* Finish the order. */
1158 LOG(("Report order, ENDSUBPATH"));
1159
1160 if (order.points.c > 0)
1161 {
1162 vrdpReportOrderGenericBounds(pDev, &clipRects, &bounds, &order, sizeof (order), VRDE_ORDER_POLYLINE);
1163 }
1164
1165 order.points.c = 0;
1166 }
1167 } while (bMore);
1168 }
1169 else
1170 {
1171 /* Not supported. */
1172 WARN(("not supported: ppo->fl = %08X, plineattrs->fl = %08X, plineattrs->pstyle = %08X",
1173 ppo->fl, plineattrs->fl, plineattrs->pstyle));
1174
1175 vrdpReportDirtyRects(pDev, &clipRects);
1176 }
1177
1178 return;
1179}
1180
1181void vrdpDrvFillPath(SURFOBJ *pso, PATHOBJ *ppo, CLIPOBJ *pco, BRUSHOBJ *pbo, POINTL *pptlBrushOrg, MIX mix, FLONG flOptions)
1182{
1183 RT_NOREF(pbo, pptlBrushOrg, mix, flOptions);
1184 PVBOXDISPDEV pDev = (PVBOXDISPDEV)pso->dhpdev;
1185 vrdpReportDirtyPath(pDev, pco, ppo);
1186}
1187
1188void vrdpDrvPaint(SURFOBJ *pso, CLIPOBJ *pco, BRUSHOBJ *pbo, POINTL *pptlBrushOrg, MIX mix)
1189{
1190 RT_NOREF(pbo, pptlBrushOrg, mix);
1191 PVBOXDISPDEV pDev = (PVBOXDISPDEV)pso->dhpdev;
1192 vrdpReportDirtyClip(pDev, pco, NULL);
1193}
1194
1195void vrdpDrvTextOut(SURFOBJ *pso, STROBJ *pstro, FONTOBJ *pfo, CLIPOBJ *pco, RECTL *prclExtra, RECTL *prclOpaque,
1196 BRUSHOBJ *pboFore, BRUSHOBJ *pboOpaque, POINTL *pptlOrg, MIX mix)
1197{
1198 RT_NOREF(pptlOrg, mix);
1199 PVBOXDISPDEV pDev = (PVBOXDISPDEV)pso->dhpdev;
1200
1201 /*
1202 * TextOut operation is supported by RDP_ORDER_TEXT2/FONTCACHE.
1203 */
1204 VRDPCLIPRECTS clipRects;
1205 int clipResult;
1206
1207 RECTL rclArea = prclOpaque? *prclOpaque: pstro->rclBkGround;
1208
1209 clipResult = vrdpGetIntersectingClipRects(&clipRects, pso, &rclArea, pco, NULL);
1210
1211 if (clipResult == VRDP_CLIP_NO_INTERSECTION)
1212 {
1213 /* Do nothing. The operation does not affect anything. */
1214 LOG(("VRDP_CLIP_NO_INTERSECTION!!!"));
1215 dumpPCO (&rclArea, pco);
1216 }
1217 else if (clipResult == VRDP_CLIP_TOO_MANY_RECTS)
1218 {
1219 /* A very complex clip. Better to emulate it. */
1220 LOG(("VRDP_CLIP_TOO_MANY_RECTS!!!"));
1221 dumpPCO (&rclArea, pco);
1222
1223 vrdpReportDirtyRects (pDev, &clipRects);
1224 }
1225 else if ( pstro->pwszOrg == NULL
1226 || prclExtra != NULL
1227 || (pfo->flFontType & FO_TYPE_RASTER) == 0
1228 || pstro->cGlyphs > VRDP_TEXT_MAX_GLYPHS
1229 || (pboOpaque && pboOpaque->iSolidColor == 0xFFFFFFFF)
1230 || pfo->iUniq == 0
1231 )
1232 {
1233 /* Unknown/unsupported parameters. */
1234 WARN(("unsupported: pstro->pwszOrg=%p, prclExtra=%p, pfo->flFontType & FO_TYPE_RASTER = 0x%08X, "
1235 "pstro->cGlyphs = %d, pboOpaque->iSolidColor %p, pfo->iUniq = %p",
1236 pstro->pwszOrg, prclExtra, pfo->flFontType & FO_TYPE_RASTER, pstro->cGlyphs,
1237 pboOpaque? pboOpaque->iSolidColor: 0, pfo->iUniq));
1238 vrdpReportDirtyRects(pDev, &clipRects);
1239 }
1240 else
1241 {
1242#if 0
1243 /* Testing: report a red rectangle for the text area. */
1244 vrdpReportSolidRect(pDev, &clipRects, 0x0000FF);
1245#else
1246 /* Try to report the text order. */
1247 ULONG ulForeRGB = pboFore? vrdpColor2RGB(pso, pboFore->iSolidColor): 0;
1248 ULONG ulBackRGB = pboOpaque? vrdpColor2RGB(pso, pboOpaque->iSolidColor): 0;
1249
1250 LOG(("calling vboxReportText fg %x bg %x", ulForeRGB, ulBackRGB));
1251
1252 if (!vrdpReportText(pDev, &clipRects, pstro, pfo, prclOpaque, ulForeRGB, ulBackRGB))
1253 {
1254 vrdpReportDirtyRects(pDev, &clipRects);
1255 }
1256#endif
1257 }
1258
1259 return;
1260}
1261
1262void vrdpDrvSaveScreenBits(SURFOBJ *pso, ULONG iMode, ULONG_PTR ident, RECTL *prcl)
1263{
1264 PVBOXDISPDEV pDev = (PVBOXDISPDEV)pso->dhpdev;
1265
1266 switch (iMode)
1267 {
1268 case SS_SAVE:
1269 {
1270 VRDEORDERSAVESCREEN order;
1271
1272 order.pt1.x = (int16_t)prcl->left;
1273 order.pt1.y = (int16_t)prcl->top;
1274 order.pt2.x = (int16_t)prcl->right;
1275 order.pt2.y = (int16_t)prcl->bottom;
1276
1277 order.ident = (uint8_t)ident;
1278 order.restore = 0;
1279
1280 vrdpReportOrderGeneric(pDev, NULL, &order, sizeof (order), VRDE_ORDER_SAVESCREEN);
1281 } break;
1282
1283 case SS_RESTORE:
1284 {
1285 VRDEORDERSAVESCREEN order;
1286
1287 order.pt1.x = (int16_t)prcl->left;
1288 order.pt1.y = (int16_t)prcl->top;
1289 order.pt2.x = (int16_t)prcl->right;
1290 order.pt2.y = (int16_t)prcl->bottom;
1291
1292 order.ident = (uint8_t)ident;
1293 order.restore = 1;
1294
1295 if (vrdpReportOrderGeneric(pDev, NULL, &order, sizeof (order), VRDE_ORDER_SAVESCREEN))
1296 {
1297 uint8_t *pu8Bits;
1298 int32_t lDelta;
1299 uint32_t w;
1300 uint32_t h;
1301
1302 int cbPixel;
1303
1304 pso = getSurfObj(pso);
1305
1306 cbPixel = format2BytesPerPixel(pso);
1307
1308 pu8Bits = (uint8_t *)pso->pvScan0 +
1309 pso->lDelta * prcl->top +
1310 cbPixel * prcl->left;
1311
1312 lDelta = pso->lDelta;
1313
1314 w = prcl->right - prcl->left;
1315 h = prcl->bottom - prcl->top;
1316
1317 vrdpWriteBits(pDev, pu8Bits, lDelta, prcl->left, prcl->top, w, h, cbPixel);
1318 }
1319 } break;
1320
1321 default:
1322 WARN(("Invalid mode %d!!!", iMode));
1323 }
1324}
1325
1326/* Whether the ROP4 operation requires MASK. */
1327#define ROP4_NEED_MASK(__rop4) ( (uint8_t)((__rop4) >> 8) != (uint8_t)(__rop4) )
1328
1329/* Whether the ROP3 (lower byte of rop4) operation requires BRUSH. */
1330#define ROP3_NEED_BRUSH(__rop3) (((((__rop3) >> 4) ^ (__rop3)) & 0x0F) != 0)
1331
1332/* Whether the ROP3 (lower byte of rop4) operation requires SOURCE. */
1333#define ROP3_NEED_SRC(__rop3) (((((__rop3) >> 2) ^ (__rop3)) & 0x33) != 0)
1334
1335/* Whether the ROP3 (lower byte of rop4) operation requires DESTINATION. */
1336#define ROP3_NEED_DST(__rop3) (((((__rop3) >> 1) ^ (__rop3)) & 0x55) != 0)
1337
1338void vrdpDrvBitBlt(SURFOBJ *psoTrg, SURFOBJ *psoSrc, SURFOBJ *psoMask, CLIPOBJ *pco, XLATEOBJ *pxlo,
1339 RECTL *prclTrg, POINTL *pptlSrc, POINTL *pptlMask, BRUSHOBJ *pbo, POINTL *pptlBrush, ROP4 rop4)
1340{
1341 RT_NOREF(psoMask, pxlo, pptlMask);
1342 PVBOXDISPDEV pDev = (PVBOXDISPDEV)psoTrg->dhpdev;
1343
1344 /*
1345 * BitBlt operation is supported by following RDP orders:
1346 * RDP_ORDER_DESTBLT ROP on the screen bits (BLACKNESS, WHITENESS, DSTINVERT).
1347 * RDP_ORDER_PATBLT ROP with screen bits and a brush.
1348 * RDP_ORDER_SCREENBLT Screen to screen with ROP.
1349 * RDP_ORDER_RECT Solid fill (SRCCOPY).
1350 * RDP_ORDER_MEMBLT ROP with screen and cached offscreen bitmap.
1351 * RDP_ORDER_TRIBLT ROP with screen, cached offscreen bitmap and a brush.
1352 *
1353 * Actual BitBlts must be mapped to these RDP operations.
1354 * Anything that can not be mapped must be emulated with dirty rect.
1355 *
1356 */
1357 VRDPCLIPRECTS clipRects;
1358
1359 int clipResult;
1360
1361 RECTL rclTrg = *prclTrg;
1362 vrdpOrderRect (&rclTrg);
1363
1364 LOGF_ENTER();
1365
1366 clipResult = vrdpGetIntersectingClipRects(&clipRects, psoTrg, &rclTrg, pco,
1367 VBoxDispIsScreenSurface(psoSrc)? pptlSrc: NULL);
1368
1369 if (clipResult == VRDP_CLIP_NO_INTERSECTION)
1370 {
1371 /* Do nothing. The Blt does not affect anything. */
1372 WARN(("VRDP_CLIP_NO_INTERSECTION!!!"));
1373 dumpPCO (&rclTrg, pco);
1374 }
1375 else if (clipResult == VRDP_CLIP_TOO_MANY_RECTS)
1376 {
1377 /* A very complex clip. Better to emulate it. */
1378 WARN(("VRDP_CLIP_TOO_MANY_RECTS!!!"));
1379 dumpPCO (&rclTrg, pco);
1380
1381 vrdpReportDirtyRects(pDev, &clipRects);
1382 }
1383 else if (ROP4_NEED_MASK (rop4))
1384 {
1385 /* Operation with mask is not supported. */
1386 WARN(("Operation with mask is not supported."));
1387 vrdpReportDirtyRects(pDev, &clipRects);
1388 }
1389 else if (ROP3_NEED_BRUSH(rop4))
1390 {
1391 LOG(("Operation requires brush."));
1392
1393 /* Operation requires brush. */
1394
1395 if (ROP3_NEED_SRC(rop4))
1396 {
1397 /** @todo Three way blt. RDP_ORDER_TRIBLT. */
1398 LOG(("TRIBLT pbo->iSolidColor = 0x%08X.", pbo->iSolidColor));
1399 vrdpReportDirtyRects(pDev, &clipRects);
1400 }
1401 else
1402 {
1403 /* Only brush and destination. Check if the brush is solid. */
1404 if (pbo->iSolidColor != 0xFFFFFFFF)
1405 {
1406 /* Solid brush. The iSolidColor is the target surface color. */
1407 uint32_t rgb = vrdpColor2RGB(psoTrg, pbo->iSolidColor);
1408
1409 /* Mix with solid brush. RDP_ORDER_PATBLT. Or RDP_ORDER_RECT for rop4 = 0xF0F0. */
1410 LOG(("Solid PATBLT color = %08X, rgb %08X.", pbo->iSolidColor, rgb));
1411
1412 if (rop4 == 0xF0F0)
1413 {
1414 vrdpReportSolidRect(pDev, &rclTrg, &clipRects, rgb);
1415 }
1416 else
1417 {
1418 vrdpReportSolidBlt(pDev, &rclTrg, &clipRects, rgb, (uint8_t)rop4);
1419 }
1420 }
1421 else
1422 {
1423 /* Non solid brush. RDP_ORDER_PATBLT. */
1424 LOG(("VRDP::vrdpBitBlt: PATBLT pbo->pvRbrush = %p.", pbo->pvRbrush));
1425
1426 /* Realize brush. */
1427 if (!pbo->pvRbrush)
1428 {
1429 BRUSHOBJ_pvGetRbrush (pbo);
1430 }
1431
1432 if (pbo->pvRbrush)
1433 {
1434 /* Brush has been realized. */
1435 VRDPBRUSH *pBrush = (VRDPBRUSH *)pbo->pvRbrush;
1436
1437 if (pBrush->fPattern)
1438 {
1439 vrdpReportPatBlt(pDev, &rclTrg, &clipRects, pBrush, pptlBrush, (uint8_t)rop4);
1440 }
1441 else
1442 {
1443 /** @todo BITMAPCACHE followed by MEMBLT? */
1444 vrdpReportDirtyRects(pDev, &clipRects);
1445 }
1446 }
1447 else
1448 {
1449 /* Unsupported brush format. Fallback to dirty rects. */
1450 vrdpReportDirtyRects(pDev, &clipRects);
1451 }
1452 }
1453 }
1454 }
1455 else
1456 {
1457 /* Operation does not require brush. */
1458 if (ROP3_NEED_SRC(rop4))
1459 {
1460 LOG(("MEMBLT or SCREENBLT."));
1461
1462 /* MEMBLT or SCREENBLT. */
1463 if (VBoxDispIsScreenSurface(psoSrc))
1464 {
1465 /* Screen to screen transfer. SCREENBLT. */
1466 LOG(("SCREENBLT."));
1467 vrdpReportScreenBlt(pDev, &rclTrg, &clipRects, pptlSrc, (uint8_t)rop4);
1468 }
1469 else
1470 {
1471 /* Offscreen bitmap to screen. MEMBLT. */
1472 VRDPBCHASH hash;
1473 VRDPBCHASH hashDeleted;
1474 int cacheResult;
1475
1476 LOG(("MEMBLT: bitmap %dx%d.", psoSrc->sizlBitmap.cx, psoSrc->sizlBitmap.cy));
1477 if ( pDev->bBitmapCacheDisabled
1478 || (psoSrc->fjBitmap & BMF_DONTCACHE) != 0
1479 || psoSrc->iUniq == 0
1480 /* Bitmaps with hdev == 0 seems to have different RGB layout for 16BPP modes.
1481 * Just do not cache these bitmaps and report the dirty display area instead.
1482 */
1483 || ( psoSrc->hdev == 0
1484 && !(psoSrc->iBitmapFormat == BMF_24BPP || psoSrc->iBitmapFormat == BMF_32BPP)
1485 )
1486 /* Do not try to cache large bitmaps. The cache should be mostly used for icons, etc.
1487 * Computing a bitmap hash increases CPU load. Up to 384K pixels (~620x620)
1488 */
1489 || psoSrc->sizlBitmap.cx * psoSrc->sizlBitmap.cy > 384 * _1K
1490 )
1491 {
1492 LOG(("MEMBLT: non cacheable bitmap."));
1493 cacheResult = VRDPBMP_RC_NOT_CACHED;
1494 }
1495 else
1496 {
1497 LOG(("MEMBLT: going to cache."));
1498 cacheResult = vrdpbmpCacheSurface(&pDev->vrdpCache, psoSrc, &hash, &hashDeleted, FALSE);
1499 }
1500
1501 LOG(("MEMBLT: cacheResult 0x%08X", cacheResult));
1502
1503 if (cacheResult & VRDPBMP_RC_F_DELETED)
1504 {
1505 LOG(("VRDPBMP_RC_F_DELETED"));
1506 vrdpReportDeletedBitmap(pDev, &hashDeleted);
1507 cacheResult &= ~VRDPBMP_RC_F_DELETED;
1508 }
1509
1510 switch (cacheResult)
1511 {
1512 case VRDPBMP_RC_CACHED:
1513 vrdpReportCachedBitmap(pDev, psoSrc, &hash);
1514 LOG(("MEMBLT: cached add %dx%d",
1515 psoSrc->sizlBitmap.cx, psoSrc->sizlBitmap.cy));
1516 /* Continue and report MEMBLT order. */
1517
1518 case VRDPBMP_RC_ALREADY_CACHED:
1519 vrdpReportMemBlt(pDev, &clipRects, pptlSrc, (uint8_t)rop4, &hash);
1520 LOG(("MEMBLT: cached use %dx%d from %d,%d %dx%d",
1521 psoSrc->sizlBitmap.cx, psoSrc->sizlBitmap.cy,
1522 pptlSrc->x, pptlSrc->y,
1523 rclTrg.right - rclTrg.left,
1524 rclTrg.bottom - rclTrg.top));
1525 LOG((" %08X %08X %08X %08X",
1526 *(uint32_t *)&((uint8_t *)&hash)[0],
1527 *(uint32_t *)&((uint8_t *)&hash)[4],
1528 *(uint32_t *)&((uint8_t *)&hash)[8],
1529 *(uint32_t *)&((uint8_t *)&hash)[12]
1530 ));
1531 break;
1532
1533 default:
1534 /* The surface was not cached. Fallback to dirty rects. */
1535 LOG(("MEMBLT: not cached %dx%d from %d,%d %dx%d",
1536 psoSrc->sizlBitmap.cx, psoSrc->sizlBitmap.cy,
1537 pptlSrc->x, pptlSrc->y,
1538 rclTrg.right - rclTrg.left,
1539 rclTrg.bottom - rclTrg.top));
1540 VBoxDispDumpPSO(psoSrc, "psoSrc");
1541 vrdpReportDirtyRects(pDev, &clipRects);
1542 }
1543 }
1544 }
1545 else
1546 {
1547 /* No source and no brush, only dest affected. DESTBLT. */
1548 LOG(("DSTBLT with rop 0x%08X", rop4));
1549 vrdpReportDstBlt(pDev, &rclTrg, &clipRects, (uint8_t)rop4);
1550 }
1551 }
1552}
1553
1554void vrdpDrvStretchBlt(SURFOBJ *psoDest, SURFOBJ *psoSrc, SURFOBJ *psoMask, CLIPOBJ *pco, XLATEOBJ *pxlo,
1555 COLORADJUSTMENT *pca, POINTL *pptlHTOrg, RECTL *prclDest, RECTL *prclSrc, POINTL *pptlMask, ULONG iMode)
1556{
1557 RT_NOREF(psoSrc, psoMask, pxlo, pca, pptlHTOrg, prclSrc, pptlMask, iMode);
1558 PVBOXDISPDEV pDev = (PVBOXDISPDEV)psoDest->dhpdev;
1559 vrdpReportDirtyClip(pDev, pco, prclDest);
1560}
1561
1562void vrdpDrvCopyBits(SURFOBJ *psoDest, SURFOBJ *psoSrc, CLIPOBJ *pco, XLATEOBJ *pxlo, RECTL *prclDest, POINTL *pptlSrc)
1563{
1564 /* The copy bits is the same as bit blt with particular set of parameters. */
1565 vrdpDrvBitBlt(psoDest, psoSrc, NULL, pco, pxlo, prclDest, pptlSrc, NULL, NULL, NULL, 0xCCCC);
1566}
1567
1568BOOL vrdpDrvRealizeBrush(BRUSHOBJ *pbo, SURFOBJ *psoTarget, SURFOBJ *psoPattern, SURFOBJ *psoMask, XLATEOBJ *pxlo, ULONG iHatch)
1569{
1570 RT_NOREF(psoMask, iHatch);
1571 BOOL bRc = FALSE;
1572
1573 LOGF(("psoMask = %p, iHatch = %d", psoMask, iHatch));
1574 VBoxDispDumpPSO(psoPattern, "psoPattern");
1575
1576 if (psoPattern
1577 && psoPattern->sizlBitmap.cx == 8
1578 && psoPattern->sizlBitmap.cy == 8
1579 && psoPattern->iBitmapFormat == 1
1580 )
1581 {
1582 uint32_t cbBrush = sizeof (VRDPBRUSH);
1583
1584 VRDPBRUSH *pBrush = (VRDPBRUSH *)BRUSHOBJ_pvAllocRbrush (pbo, cbBrush);
1585
1586 LOG(("pattern pBrush = %p, size = %d", pBrush, cbBrush));
1587
1588 if (pBrush)
1589 {
1590 int i;
1591 uint8_t *pu8Bits = (uint8_t *)psoPattern->pvScan0;
1592
1593 for (i = 0; i < 8; i++)
1594 {
1595 pBrush->u.pat.au8Pattern[i] = *pu8Bits;
1596
1597 pu8Bits += psoPattern->lDelta;
1598 }
1599
1600 /* Obtain RGB values for the brush fore and background colors:
1601 * "should translate color zero through the XLATEOBJ to get the foreground color for the brush."
1602 */
1603 pBrush->u.pat.rgbFG = vrdpColor2RGB (psoTarget, pxlo->pulXlate[0]);
1604 pBrush->u.pat.rgbBG = vrdpColor2RGB (psoTarget, pxlo->pulXlate[1]);
1605
1606 pBrush->fPattern = TRUE;
1607
1608 bRc = TRUE;
1609 }
1610 }
1611#if 0
1612 else if (psoPattern)
1613 {
1614 /* Color brushes and brushes >8x8 are cached and MEMBLT order generated. */
1615 uint32_t cbBrush = sizeof (VRDPBRUSH) +
1616 psoTarget->sizlBitmap.cx * sizeof (uint32_t) * psoTarget->sizlBitmap.cy;
1617 ??? target
1618
1619 VRDPBRUSH *pBrush = (VRDPBRUSH *)BRUSHOBJ_pvAllocRbrush (pbo, cbBrush);
1620
1621 LOG(("bitmap pBrush = %p, size = %d", pBrush, cbBrush));
1622
1623 if (pBrush)
1624 {
1625 /* Byte per pattern pixel. */
1626 uint32_t cbSrcBPP = format2BytesPerPixel(psoPattern);
1627
1628 /* Source bits scanline pointer. */
1629 uint8_t *pu8BitsSrcScanLine = (uint8_t *)psoPattern->pvScan0;
1630
1631 /* Target RGB pixel pointer. */
1632 uint32_t *pu32BitsDst = &pBrush->u.bitmap.au32Bits[0];
1633
1634 int y;
1635 for (y = 0; y < psoTarget->sizlBitmap.cy; y++, pu8BitsSrcScanLine += psoPattern->lDelta)
1636 {
1637 uint8_t *pu8BitsSrc = pu8BitsSrcScanLine;
1638
1639 int x;
1640
1641 for (x = 0; x < psoTarget->sizlBitmap.cx; x++, pu8BitsSrc += cbSrcBPP)
1642 {
1643 uint32_t color = 0;
1644
1645 memcpy (&color, pu8BitsSrc, cbSrcBPP);
1646
1647 if (pxlo)
1648 {
1649 color = XLATEOBJ_iXlate (pxlo, color);
1650 }
1651
1652 *pu32BitsDst++ = vrdpColor2RGB (psoTarget, color);
1653
1654 /* LOG(("%08X", pu32BitsDst[-1])); */
1655 }
1656 }
1657
1658 pBrush->u.bitmap.w = (uint16_t)psoTarget->sizlBitmap.cx;
1659 pBrush->u.bitmap.h = (uint16_t)psoTarget->sizlBitmap.cy;
1660
1661 pBrush->fPattern = FALSE;
1662
1663 bRc = TRUE;
1664 }
1665 }
1666#endif /* 0 */
1667
1668 return bRc;
1669}
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