VirtualBox

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

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

Multimonitor support.

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