VirtualBox

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

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

Windows guest video driver: corrected detection of non-cacheable bitmaps.

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