VirtualBox

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

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

*: scm --update-copyright-year

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