VirtualBox

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

Last change on this file since 63061 was 63061, checked in by vboxsync, 8 years ago

GA/NT/Graphics: warnings

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