VirtualBox

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

Last change on this file since 5952 was 5952, checked in by vboxsync, 17 years ago

Workaround for scrambled icons over VRDP with 16BPP guest video mode.

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