VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/Graphics/Display/vrdp.c@ 4454

Last change on this file since 4454 was 4181, checked in by vboxsync, 18 years ago

Windows guest display driver to report the screen rectangle that was actually changed.

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