VirtualBox

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

Last change on this file since 34406 was 33595, checked in by vboxsync, 14 years ago

src/*: more spelling fixes (logging), thanks Timeless!

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 53.2 KB
Line 
1/** @file
2 *
3 * VirtualBox Windows NT/2000/XP guest video driver
4 *
5 * VRDP graphics orders pipeline.
6 */
7
8/*
9 * Copyright (C) 2006-2007 Oracle Corporation
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.virtualbox.org. This file is free software;
13 * you can redistribute it and/or modify it under the terms of the GNU
14 * General Public License (GPL) as published by the Free Software
15 * Foundation, in version 2 as it comes in the "COPYING" file of the
16 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18 */
19
20#include "driver.h"
21#include "vrdpbmp.h"
22#include <VBox/RemoteDesktop/VRDEOrders.h>
23
24#define VRDP_MAKE_OP(__c) (__c)
25
26typedef struct _VRDPBRUSH
27{
28 BOOL fPattern;
29
30 union {
31 struct {
32 uint32_t rgbFG;
33 uint32_t rgbBG;
34 uint8_t au8Pattern[8];
35 } pat;
36
37 struct {
38 uint16_t w;
39 uint16_t h;
40 uint32_t au32Bits[1];
41 /* Here bits continue. */
42 } bitmap;
43 } u;
44} VRDPBRUSH;
45
46#define VRDP_CLIP_OK 0
47#define VRDP_CLIP_NO_INTERSECTION 1
48#define VRDP_CLIP_TOO_MANY_RECTS 2
49
50#if 0
51#define dumpPCO(a, b) do {} while (0)
52#else
53void dumpPCO (RECTL *prclTrg, CLIPOBJ *pco)
54{
55 DISPDBG((1, " pco = %p Trg = %d-%d %d-%d\n", pco, prclTrg->left, prclTrg->right, prclTrg->top, prclTrg->bottom));
56
57 if (pco)
58 {
59 BOOL bMore;
60 CLIPRECTS cr;
61 RECTL* prclClip;
62 int cRects = 0;
63
64 DISPDBG((1, " pco = %d %d-%d %d-%d dc %d fc %d mode %d opt %d\n",
65 pco->iUniq,
66 pco->rclBounds.left, pco->rclBounds.right, pco->rclBounds.top, pco->rclBounds.bottom,
67 pco->iDComplexity, pco->iFComplexity, pco->iMode, pco->fjOptions));
68
69 CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_ANY, 0);
70
71 do
72 {
73 bMore = CLIPOBJ_bEnum(pco, sizeof(cr), (ULONG*)&cr);
74
75 for (prclClip = &cr.arcl[0]; cr.c != 0; cr.c--, prclClip++)
76 {
77 DISPDBG((1, " %d-%d %d-%d\n", prclClip->left, prclClip->right, prclClip->top, prclClip->bottom));
78 cRects++;
79 }
80 } while (bMore);
81
82 DISPDBG((1, " Total %d rects\n", cRects));
83 }
84}
85#endif
86
87static BOOL vrdpIsRectEmpty (const RECTL *prcl)
88{
89 return (prcl->left == prcl->right) || (prcl->top == prcl->bottom);
90}
91
92static void vrdpIntersectRects (RECTL *prectResult,
93 const RECTL *prect1,
94 const RECTL *prect2)
95{
96 /* Calculations are easier with left, right, top, bottom. */
97 int xLeft1 = prect1->left;
98 int xRight1 = prect1->right;
99
100 int xLeft2 = prect2->left;
101 int xRight2 = prect2->right;
102
103 int yTop1 = prect1->top;
104 int yBottom1 = prect1->bottom;
105
106 int yTop2 = prect2->top;
107 int yBottom2 = prect2->bottom;
108
109 int xLeftResult = max (xLeft1, xLeft2);
110 int xRightResult = min (xRight1, xRight2);
111
112 /* Initialize result to empty record. */
113 memset (prectResult, 0, sizeof (RECTL));
114
115 if (xLeftResult < xRightResult)
116 {
117 /* There is intersection by X. */
118
119 int yTopResult = max (yTop1, yTop2);
120 int yBottomResult = min (yBottom1, yBottom2);
121
122 if (yTopResult < yBottomResult)
123 {
124 /* There is intersection by Y. */
125
126 prectResult->left = xLeftResult;
127 prectResult->top = yTopResult;
128 prectResult->right = xRightResult;
129 prectResult->bottom = yBottomResult;
130 }
131 }
132
133 return;
134}
135
136static void vrdpOrderRect (RECTL *prcl)
137{
138 int tmp;
139
140 if (prcl->left > prcl->right)
141 {
142 DISPDBG((1, "vrdpOrderRect: Inverse X coordinates!!!\n"));
143
144 tmp = prcl->left;
145 prcl->left = prcl->right;
146 prcl->right = tmp;
147 }
148
149 if (prcl->top > prcl->bottom)
150 {
151 DISPDBG((1, "vrdpOrderRect: Inverse Y coordinates!!!\n"));
152
153 tmp = prcl->top;
154 prcl->top = prcl->bottom;
155 prcl->bottom = tmp;
156 }
157}
158
159
160void vrdpAdjustRect (SURFOBJ *pso, RECTL *prcl)
161{
162 int x;
163 int y;
164 int w;
165 int h;
166
167 DISPDBG((1, "vrdpAdjustRect: %d-%d %d-%d on %dx%d\n", prcl->left, prcl->right, prcl->top, prcl->bottom, pso->sizlBitmap.cx, pso->sizlBitmap.cy));
168
169 if (prcl->left <= prcl->right)
170 {
171 x = prcl->left;
172 w = prcl->right - prcl->left;
173 }
174 else
175 {
176 DISPDBG((1, "vrdpAdjustRect: Inverse X coordinates!!!\n"));
177 x = prcl->right;
178 w = prcl->left - prcl->right;
179 }
180
181 if (prcl->top <= prcl->bottom)
182 {
183 y = prcl->top;
184 h = prcl->bottom - prcl->top;
185 }
186 else
187 {
188 DISPDBG((1, "vrdpAdjustRect: Inverse Y coordinates!!!\n"));
189 y = prcl->bottom;
190 h = prcl->top - prcl->bottom;
191 }
192
193 VBVA_ASSERT(w >= 0 && h >= 0);
194
195 /* Correct negative x and y coordinates. */
196 if (x < 0)
197 {
198 x += w; /* Compute xRight which is also the new width. */
199
200 w = (x < 0)? 0: x;
201
202 x = 0;
203 }
204
205 if (y < 0)
206 {
207 y += h; /* Compute xBottom, which is also the new height. */
208
209 h = (y < 0)? 0: y;
210
211 y = 0;
212 }
213
214 /* Also check if coords are greater than the display resolution. */
215 if (x + w > pso->sizlBitmap.cx)
216 {
217 w = pso->sizlBitmap.cx > x? pso->sizlBitmap.cx - x: 0;
218 }
219
220 if (y + h > pso->sizlBitmap.cy)
221 {
222 h = pso->sizlBitmap.cy > y? pso->sizlBitmap.cy - y: 0;
223 }
224
225 prcl->left = x;
226 prcl->top = y;
227 prcl->right = x + w;
228 prcl->bottom = y + h;
229
230 DISPDBG((1, "vrdpAdjustRect: result %d-%d %d-%d\n", prcl->left, prcl->right, prcl->top, prcl->bottom));
231}
232
233static int vrdpGetIntersectingClipRects (VRDPCLIPRECTS *pClipRects, SURFOBJ *pso, RECTL *prcl, CLIPOBJ *pco, POINTL *pptlSrc)
234{
235 BOOL bTooManyRects = FALSE;
236
237 DISPDBG((1, "vrdpGetIntersectingClipRects: pso = %p, pptlSrc = %p\n", pso, pptlSrc));
238
239 pso = CONV_SURF(pso);
240
241 pClipRects->rclDstOrig = *prcl;
242 pClipRects->rclDst = *prcl;
243 pClipRects->rects.c = 0;
244
245 vrdpAdjustRect (pso, &pClipRects->rclDst);
246
247 if (pco && (pco->iDComplexity != DC_TRIVIAL))
248 {
249 ULONG iDirection = CD_ANY;
250
251 if (pptlSrc)
252 {
253 /* Operation is performed on the same (screen) surface and enumeration direction
254 * must take into account the position of source and target rectangles.
255 */
256 if (pptlSrc->x <= prcl->left)
257 {
258 if (pptlSrc->y <= prcl->top)
259 {
260 iDirection = CD_LEFTUP;
261 }
262 else
263 {
264 iDirection = CD_LEFTDOWN;
265 }
266 }
267 else
268 {
269 if (pptlSrc->y <= prcl->top)
270 {
271 iDirection = CD_RIGHTUP;
272 }
273 else
274 {
275 iDirection = CD_RIGHTDOWN;
276 }
277 }
278 }
279
280 /* Clip the target rect by entire clipping region. Obtain the effective target. */
281 vrdpIntersectRects (&pClipRects->rclDst, &pClipRects->rclDst, &pco->rclBounds);
282
283 /* Enumerate rectangles. Try to get all rectangles at once and if there is not
284 * enough space (too many rectangles) fail with the bTooManyRects condition.
285 */
286 CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, iDirection, 0);
287
288 bTooManyRects = CLIPOBJ_bEnum(pco, sizeof(pClipRects->rects), &pClipRects->rects.c);
289
290 if (!bTooManyRects)
291 {
292 RECTL *prclClipSrc = &pClipRects->rects.arcl[0];
293 RECTL *prclClipDst = prclClipSrc;
294
295 ULONG cRects = pClipRects->rects.c;
296
297 DISPDBG((1, "%d rects\n", cRects));
298
299 if (cRects > 0)
300 {
301 for (; cRects != 0; cRects--, prclClipSrc++)
302 {
303 vrdpIntersectRects (prclClipDst, prclClipSrc, &pClipRects->rclDst);
304
305 if (vrdpIsRectEmpty (prclClipDst))
306 {
307 pClipRects->rects.c--;
308 }
309 else
310 {
311 prclClipDst++;
312 }
313 }
314 }
315
316 if (pClipRects->rects.c == 0)
317 {
318 pClipRects->rclDst.left = pClipRects->rclDst.right = 0;
319 }
320 DISPDBG((1, "%d rects remains\n", pClipRects->rects.c));
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 VRDEDATABITS 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
403void 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(VRDE_ORDER_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 VRDEORDERBOUNDS 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), VRDE_ORDER_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 VRDEORDERREPEAT 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), VRDE_ORDER_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 VRDEORDERBOUNDS *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 intersection. */
579 return FALSE;
580}
581
582static BOOL vrdpGetIntersectingRects (CLIPRECTS *pRects,
583 const VRDPCLIPRECTS *pClipRects,
584 const VRDEORDERBOUNDS *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
630BOOL 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 VRDEORDERBOUNDS *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 VRDEORDERSOLIDRECT 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), VRDE_ORDER_SOLIDRECT);
692}
693
694static void vrdpReportSolidBlt (PPDEV ppdev,
695 const RECTL *prclTrg,
696 VRDPCLIPRECTS *pClipRects,
697 ULONG rgb,
698 uint8_t rop3)
699{
700 VRDEORDERSOLIDBLT 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), VRDE_ORDER_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 VRDEORDERPATBLTBRUSH 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), VRDE_ORDER_PATBLTBRUSH);
760}
761
762static void vrdpReportDstBlt (PPDEV ppdev,
763 const RECTL *prclTrg,
764 VRDPCLIPRECTS *pClipRects,
765 uint8_t rop3)
766{
767 VRDEORDERDSTBLT 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), VRDE_ORDER_DSTBLT);
776}
777
778static void vrdpReportScreenBlt (PPDEV ppdev,
779 const RECTL *prclTrg,
780 VRDPCLIPRECTS *pClipRects,
781 POINTL *pptlSrc,
782 uint8_t rop3)
783{
784 VRDEORDERSCREENBLT 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), VRDE_ORDER_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 VRDEORDERMEMBLT 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), VRDE_ORDER_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 VRDEORDERCACHEDBITMAP 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), VRDE_ORDER_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 VRDEORDERDELETEDBITMAP order;
882
883 VBVA_ASSERT(sizeof (*phash) == sizeof (order.hash));
884 memcpy (order.hash, phash, sizeof (*phash));
885
886 vrdpReportOrder (ppdev, &order, sizeof (order), VRDE_ORDER_DELETED_BITMAP);
887}
888
889
890/*
891 * VRDP driver functions.
892 */
893
894/* Whether the ROP4 operation requires MASK. */
895#define ROP4_NEED_MASK(__rop4) ( (uint8_t)((__rop4) >> 8) != (uint8_t)(__rop4) )
896
897/* Whether the ROP3 (lower byte of rop4) operation requires BRUSH. */
898#define ROP3_NEED_BRUSH(__rop3) (((((__rop3) >> 4) ^ (__rop3)) & 0x0F) != 0)
899
900/* Whether the ROP3 (lower byte of rop4) operation requires SOURCE. */
901#define ROP3_NEED_SRC(__rop3) (((((__rop3) >> 2) ^ (__rop3)) & 0x33) != 0)
902
903/* Whether the ROP3 (lower byte of rop4) operation requires DESTINATION. */
904#define ROP3_NEED_DST(__rop3) (((((__rop3) >> 1) ^ (__rop3)) & 0x55) != 0)
905
906void vrdpBitBlt (
907 SURFOBJ *psoTrg,
908 SURFOBJ *psoSrc,
909 SURFOBJ *psoMask,
910 CLIPOBJ *pco,
911 XLATEOBJ *pxlo,
912 RECTL *prclTrg,
913 POINTL *pptlSrc,
914 POINTL *pptlMask,
915 BRUSHOBJ *pbo,
916 POINTL *pptlBrush,
917 ROP4 rop4)
918{
919 PPDEV ppdev = (PPDEV)psoTrg->dhpdev;
920
921 /*
922 * BitBlt operation is supported by following RDP orders:
923 * RDP_ORDER_DESTBLT ROP on the screen bits (BLACKNESS, WHITENESS, DSTINVERT).
924 * RDP_ORDER_PATBLT ROP with screen bits and a brush.
925 * RDP_ORDER_SCREENBLT Screen to screen with ROP.
926 * RDP_ORDER_RECT Solid fill (SRCCOPY).
927 * RDP_ORDER_MEMBLT ROP with screen and cached offscreen bitmap.
928 * RDP_ORDER_TRIBLT ROP with screen, cached offscreen bitmap and a brush.
929 *
930 * Actual BitBlts must be mapped to these RDP operations.
931 * Anything that can not be mapped must be emulated with dirty rect.
932 *
933 */
934 VRDPCLIPRECTS clipRects;
935
936 int clipResult;
937
938 RECTL rclTrg = *prclTrg;
939 vrdpOrderRect (&rclTrg);
940
941 DISPDBG((1, "vrdpBitBlt\n"));
942
943 clipResult = vrdpGetIntersectingClipRects (&clipRects, psoTrg, &rclTrg, pco,
944 bIsScreenSurface (psoSrc)? pptlSrc: NULL);
945
946 if (clipResult == VRDP_CLIP_NO_INTERSECTION)
947 {
948 /* Do nothing. The Blt does not affect anything. */
949 DISPDBG((1, "VRDP::vrdpBitBlt: VRDP_CLIP_NO_INTERSECTION!!!\n"));
950 dumpPCO (&rclTrg, pco);
951 }
952 else if (clipResult == VRDP_CLIP_TOO_MANY_RECTS)
953 {
954 /* A very complex clip. Better to emulate it. */
955 DISPDBG((1, "VRDP::vrdpBitBlt: VRDP_CLIP_TOO_MANY_RECTS!!!\n"));
956 dumpPCO (&rclTrg, pco);
957
958 vrdpReportDirtyRects (ppdev, &clipRects);
959 }
960 else if (ROP4_NEED_MASK (rop4))
961 {
962 /* Operation with mask is not supported. */
963 DISPDBG((1, "VRDP::vrdpBitBlt: Operation with mask is not supported.\n"));
964 vrdpReportDirtyRects (ppdev, &clipRects);
965 }
966 else if (ROP3_NEED_BRUSH(rop4))
967 {
968 DISPDBG((1, "VRDP::vrdpBitBlt: Operation requires brush.\n"));
969
970 /* Operation requires brush. */
971
972 if (ROP3_NEED_SRC(rop4))
973 {
974 /* @todo Tree way blt. RDP_ORDER_TRIBLT. */
975 DISPDBG((1, "VRDP::vrdpBitBlt: TRIBLT pbo->iSolidColor = 0x%08X.\n", pbo->iSolidColor));
976 vrdpReportDirtyRects (ppdev, &clipRects);
977 }
978 else
979 {
980 /* Only brush and destination. Check if the brush is solid. */
981 if (pbo->iSolidColor != 0xFFFFFFFF)
982 {
983 /* Solid brush. The iSolidColor is the target surface color. */
984 uint32_t rgb = vrdpColor2RGB (psoTrg, pbo->iSolidColor);
985
986 /* Mix with solid brush. RDP_ORDER_PATBLT. Or RDP_ORDER_RECT for rop4 = 0xF0F0. */
987 DISPDBG((1, "VRDP::vrdpBitBlt: Solid PATBLT color = %08X, rgb %08X.\n", pbo->iSolidColor, rgb));
988
989 if (rop4 == 0xF0F0)
990 {
991 vrdpReportSolidRect (ppdev, &rclTrg, &clipRects, rgb);
992 }
993 else
994 {
995 vrdpReportSolidBlt (ppdev, &rclTrg, &clipRects, rgb, (uint8_t)rop4);
996 }
997 }
998 else
999 {
1000 /* Non solid brush. RDP_ORDER_PATBLT. */
1001 DISPDBG((1, "VRDP::vrdpBitBlt: PATBLT pbo->pvRbrush = %p.\n", pbo->pvRbrush));
1002
1003 /* Realize brush. */
1004 if (!pbo->pvRbrush)
1005 {
1006 BRUSHOBJ_pvGetRbrush (pbo);
1007 }
1008
1009 if (pbo->pvRbrush)
1010 {
1011 /* Brush has been realized. */
1012 VRDPBRUSH *pBrush = (VRDPBRUSH *)pbo->pvRbrush;
1013
1014 if (pBrush->fPattern)
1015 {
1016 vrdpReportPatBlt (ppdev, &rclTrg, &clipRects, pBrush, pptlBrush, (uint8_t)rop4);
1017 }
1018 else
1019 {
1020 // @todo BITMAPCACHE followed by MEMBLT?
1021 vrdpReportDirtyRects (ppdev, &clipRects);
1022 }
1023 }
1024 else
1025 {
1026 /* Unsupported brush format. Fallback to dirty rects. */
1027 vrdpReportDirtyRects (ppdev, &clipRects);
1028 }
1029 }
1030 }
1031 }
1032 else
1033 {
1034 /* Operation does not require brush. */
1035 if (ROP3_NEED_SRC(rop4))
1036 {
1037 DISPDBG((1, "VRDP::vrdpBitBlt: MEMBLT or SCREENBLT.\n"));
1038
1039 /* MEMBLT or SCREENBLT. */
1040 if (bIsScreenSurface (psoSrc))
1041 {
1042 /* Screen to screen transfer. SCREENBLT. */
1043 DISPDBG((1, "VRDP::vrdpBitBlt: SCREENBLT.\n"));
1044 vrdpReportScreenBlt (ppdev, &rclTrg, &clipRects, pptlSrc, (uint8_t)rop4);
1045 }
1046 else
1047 {
1048 /* Offscreen bitmap to screen. MEMBLT. */
1049 VRDPBCHASH hash;
1050 VRDPBCHASH hashDeleted;
1051 int cacheResult;
1052
1053 DISPDBG((1, "VRDP::vrdpBitBlt: MEMBLT.\n"));
1054 if ( (psoSrc->fjBitmap & BMF_DONTCACHE) != 0
1055 || psoSrc->iUniq == 0
1056 /* Bitmaps with hdev == 0 seems to have different RGB layout for 16BPP modes.
1057 * Just do not cache these bitmaps and report the dirty display area instead.
1058 */
1059 || ( psoSrc->hdev == 0
1060 && !(psoSrc->iBitmapFormat == BMF_24BPP || psoSrc->iBitmapFormat == BMF_32BPP)
1061 )
1062 )
1063 {
1064 DISPDBG((1, "MEMBLT: non cacheable bitmap.\n"));
1065 cacheResult = VRDPBMP_RC_NOT_CACHED;
1066 }
1067 else
1068 {
1069 DISPDBG((1, "VRDP::vrdpBitBlt: going to cache.\n"));
1070 cacheResult = vrdpbmpCacheSurface (&ppdev->cache, psoSrc, &hash, &hashDeleted);
1071 }
1072
1073 DISPDBG((1, "MEMBLT: cacheResult 0x%08X. trg %d,%d %dx%d src %dx%d from %d,%d\n",
1074 cacheResult,
1075 rclTrg.left, rclTrg.top,
1076 rclTrg.right - rclTrg.left,
1077 rclTrg.bottom - rclTrg.top,
1078 psoSrc->sizlBitmap.cx, psoSrc->sizlBitmap.cy,
1079 pptlSrc->x, pptlSrc->y));
1080
1081 if (cacheResult & VRDPBMP_RC_F_DELETED)
1082 {
1083 DISPDBG((1, "VRDPBMP_RC_F_DELETED\n"));
1084 vrdpReportDeletedBitmap (ppdev, &hashDeleted);
1085 cacheResult &= ~VRDPBMP_RC_F_DELETED;
1086 }
1087
1088 switch (cacheResult)
1089 {
1090 case VRDPBMP_RC_CACHED:
1091 vrdpReportCachedBitmap (ppdev, psoSrc, &hash);
1092 /* Continue and report MEMBLT order. */
1093
1094 case VRDPBMP_RC_ALREADY_CACHED:
1095 vrdpReportMemBlt (ppdev, &clipRects, pptlSrc, (uint8_t)rop4, &hash);
1096 DISPDBG((1, " %08X %08X %08X %08X\n",
1097 *(uint32_t *)&((uint8_t *)&hash)[0],
1098 *(uint32_t *)&((uint8_t *)&hash)[4],
1099 *(uint32_t *)&((uint8_t *)&hash)[8],
1100 *(uint32_t *)&((uint8_t *)&hash)[12]
1101 ));
1102 break;
1103
1104 default:
1105 /* The surface was not cached. Fallback to dirty rects. */
1106 DISPDBG((1, "MEMBLT: bitmap not cached.\n"));
1107 DISPDBG((1, " DHSURF dhsurf = %p\n", psoSrc->dhsurf));
1108 DISPDBG((1, " HSURF hsurf = %p\n", psoSrc->hsurf));
1109 DISPDBG((1, " DHPDEV dhpdev = %p\n", psoSrc->dhpdev));
1110 DISPDBG((1, " HDEV hdev = %p\n", psoSrc->hdev));
1111 DISPDBG((1, " SIZEL sizlBitmap = %dx%d\n", psoSrc->sizlBitmap.cx, psoSrc->sizlBitmap.cy));
1112 DISPDBG((1, " ULONG cjBits = %p\n", psoSrc->cjBits));
1113 DISPDBG((1, " PVOID pvBits = %p\n", psoSrc->pvBits));
1114 DISPDBG((1, " PVOID pvScan0 = %p\n", psoSrc->pvScan0));
1115 DISPDBG((1, " LONG lDelta = %p\n", psoSrc->lDelta));
1116 DISPDBG((1, " ULONG iUniq = %p\n", psoSrc->iUniq));
1117 DISPDBG((1, " ULONG iBitmapFormat = %p\n", psoSrc->iBitmapFormat));
1118 DISPDBG((1, " USHORT iType = %p\n", psoSrc->iType));
1119 DISPDBG((1, " USHORT fjBitmap = %p\n", psoSrc->fjBitmap));
1120 vrdpReportDirtyRects (ppdev, &clipRects);
1121 }
1122 }
1123 }
1124 else
1125 {
1126 /* No source and no brush, only dest affected. DESTBLT. */
1127 DISPDBG((1, "VRDP::vrdpBitBlt: DSTBLT with rop 0x%08X\n", rop4));
1128 vrdpReportDstBlt (ppdev, &rclTrg, &clipRects, (uint8_t)rop4);
1129 }
1130 }
1131}
1132
1133void vrdpTextOut(
1134 SURFOBJ *pso,
1135 STROBJ *pstro,
1136 FONTOBJ *pfo,
1137 CLIPOBJ *pco,
1138 RECTL *prclExtra, // Obsolete, always NULL
1139 RECTL *prclOpaque,
1140 BRUSHOBJ *pboFore,
1141 BRUSHOBJ *pboOpaque,
1142 POINTL *pptlOrg,
1143 MIX mix
1144 )
1145{
1146 PPDEV ppdev = (PPDEV)pso->dhpdev;
1147
1148 /*
1149 * TextOut operation is supported by RDP_ORDER_TEXT2/FONTCACHE.
1150 */
1151 VRDPCLIPRECTS clipRects;
1152 int clipResult;
1153
1154 RECTL rclArea = prclOpaque? *prclOpaque: pstro->rclBkGround;
1155
1156 clipResult = vrdpGetIntersectingClipRects (&clipRects, pso, &rclArea, pco, NULL);
1157
1158 if (clipResult == VRDP_CLIP_NO_INTERSECTION)
1159 {
1160 /* Do nothing. The operation does not affect anything. */
1161 DISPDBG((1, "VRDP::vrdpTextOut: VRDP_CLIP_NO_INTERSECTION!!!\n"));
1162 dumpPCO (&rclArea, pco);
1163 }
1164 else if (clipResult == VRDP_CLIP_TOO_MANY_RECTS)
1165 {
1166 /* A very complex clip. Better to emulate it. */
1167 DISPDBG((1, "VRDP::vrdpTextOut: VRDP_CLIP_TOO_MANY_RECTS!!!\n"));
1168 dumpPCO (&rclArea, pco);
1169
1170 vrdpReportDirtyRects (ppdev, &clipRects);
1171 }
1172 else if ( pstro->pwszOrg == NULL
1173 || prclExtra != NULL
1174 || (pfo->flFontType & FO_TYPE_RASTER) == 0
1175 || pstro->cGlyphs > VRDP_TEXT_MAX_GLYPHS
1176 || (pboOpaque && pboOpaque->iSolidColor == 0xFFFFFFFF)
1177 || pfo->iUniq == 0
1178 )
1179 {
1180 /* Unknown/unsupported parameters. */
1181 DISPDBG((1, "VRDP::vrdpTextOut: unsupported: pstro->pwszOrg=%p, prclExtra=%p, pfo->flFontType & FO_TYPE_RASTER = 0x%08X, pstro->cGlyphs = %d, pboOpaque->iSolidColor %p, pfo->iUniq = %p\n",
1182 pstro->pwszOrg, prclExtra, pfo->flFontType & FO_TYPE_RASTER, pstro->cGlyphs, pboOpaque? pboOpaque->iSolidColor: 0, pfo->iUniq));
1183 vrdpReportDirtyRects (ppdev, &clipRects);
1184 }
1185 else
1186 {
1187#if 0
1188 /* Testing: report a red rectangle for the text area. */
1189 vrdpReportSolidRect (ppdev, &clipRects, 0x0000FF);
1190#else
1191 /* Try to report the text order. */
1192 ULONG ulForeRGB = pboFore? vrdpColor2RGB (pso, pboFore->iSolidColor): 0;
1193 ULONG ulBackRGB = pboOpaque? vrdpColor2RGB (pso, pboOpaque->iSolidColor): 0;
1194
1195 DISPDBG((1, "VRDP::vrdpTextOut: calling vboxReportText fg %x bg %x\n",
1196 ulForeRGB, ulBackRGB));
1197
1198 if (!vboxReportText (ppdev, &clipRects, pstro, pfo, prclOpaque, ulForeRGB, ulBackRGB))
1199 {
1200 vrdpReportDirtyRects (ppdev, &clipRects);
1201 }
1202#endif
1203 }
1204
1205 return;
1206}
1207
1208void vrdpLineTo(
1209 SURFOBJ *pso,
1210 CLIPOBJ *pco,
1211 BRUSHOBJ *pbo,
1212 LONG x1,
1213 LONG y1,
1214 LONG x2,
1215 LONG y2,
1216 RECTL *prclBounds,
1217 MIX mix
1218 )
1219{
1220 PPDEV ppdev = (PPDEV)pso->dhpdev;
1221
1222 /*
1223 * LineTo operation is supported by RDP_ORDER_LINE.
1224 */
1225 VRDPCLIPRECTS clipRects;
1226 int clipResult;
1227 RECTL rclBoundsOrdered = *prclBounds;
1228
1229 vrdpOrderRect (&rclBoundsOrdered);
1230
1231 clipResult = vrdpGetIntersectingClipRects (&clipRects, pso, &rclBoundsOrdered, pco, NULL);
1232
1233 if (clipResult == VRDP_CLIP_NO_INTERSECTION)
1234 {
1235 /* Do nothing. The Blt does not affect anything. */
1236 DISPDBG((1, "VRDP::vrdpLineTo: VRDP_CLIP_NO_INTERSECTION!!!\n"));
1237 dumpPCO (&rclBoundsOrdered, pco);
1238 }
1239 else if (clipResult == VRDP_CLIP_TOO_MANY_RECTS)
1240 {
1241 /* A very complex clip. Better to emulate it. */
1242 DISPDBG((1, "VRDP::vrdpLineTo: VRDP_CLIP_TOO_MANY_RECTS!!!\n"));
1243 dumpPCO (&rclBoundsOrdered, pco);
1244
1245 vrdpReportDirtyRects (ppdev, &clipRects);
1246 }
1247 else if (pbo->iSolidColor == 0xFFFFFFFF)
1248 {
1249 /* Not solid brushes are not supported. */
1250 vrdpReportDirtyRects (ppdev, &clipRects);
1251 }
1252 else
1253 {
1254 VRDEORDERLINE order;
1255
1256 order.x1 = (int16_t)x1;
1257 order.y1 = (int16_t)y1;
1258 order.x2 = (int16_t)x2;
1259 order.y2 = (int16_t)y2;
1260
1261 order.xBounds1 = ~0;
1262 order.yBounds1 = ~0;
1263 order.xBounds2 = ~0;
1264 order.yBounds2 = ~0;
1265
1266 order.mix = (uint8_t)(mix & 0x1F);
1267 order.rgb = vrdpColor2RGB (pso, pbo->iSolidColor);
1268
1269 DISPDBG((1, "VRDP::vrdpLineTo: LINE %d,%d to %d,%d mix %02X rgb %08X bounds %d-%d %d-%d cliprects %d.\n",
1270 x1, y1, x2, y2, order.mix, order.rgb,
1271 prclBounds->left, prclBounds->right, prclBounds->top, prclBounds->bottom, clipRects.rects.c));
1272
1273 vrdpReportOrderGeneric (ppdev, &clipRects, &order, sizeof (order), VRDE_ORDER_LINE);
1274 }
1275}
1276
1277void vrdpStretchBlt(
1278 SURFOBJ *psoDest,
1279 SURFOBJ *psoSrc,
1280 SURFOBJ *psoMask,
1281 CLIPOBJ *pco,
1282 XLATEOBJ *pxlo,
1283 COLORADJUSTMENT *pca,
1284 POINTL *pptlHTOrg,
1285 RECTL *prclDest,
1286 RECTL *prclSrc,
1287 POINTL *pptlMask,
1288 ULONG iMode
1289 )
1290{
1291 PPDEV ppdev = (PPDEV)psoDest->dhpdev;
1292
1293 vrdpReportDirtyClip (ppdev, pco, prclDest);
1294}
1295
1296void vrdpCopyBits(
1297 SURFOBJ *psoDest,
1298 SURFOBJ *psoSrc,
1299 CLIPOBJ *pco,
1300 XLATEOBJ *pxlo,
1301 RECTL *prclDest,
1302 POINTL *pptlSrc
1303 )
1304{
1305 /* The copy bits is the same as bit blt with particular set of parameters. */
1306 vrdpBitBlt (psoDest, psoSrc, NULL, pco, pxlo, prclDest, pptlSrc, NULL, NULL, NULL, 0xCCCC);
1307}
1308
1309void vrdpPaint(
1310 SURFOBJ *pso,
1311 CLIPOBJ *pco,
1312 BRUSHOBJ *pbo,
1313 POINTL *pptlBrushOrg,
1314 MIX mix
1315 )
1316{
1317 PPDEV ppdev = (PPDEV)pso->dhpdev;
1318
1319 vrdpReportDirtyClip (ppdev, pco, NULL);
1320}
1321
1322void vrdpFillPath(
1323 SURFOBJ *pso,
1324 PATHOBJ *ppo,
1325 CLIPOBJ *pco,
1326 BRUSHOBJ *pbo,
1327 POINTL *pptlBrushOrg,
1328 MIX mix,
1329 FLONG flOptions
1330 )
1331{
1332 PPDEV ppdev = (PPDEV)pso->dhpdev;
1333
1334 vrdpReportDirtyPath (ppdev, pco, ppo);
1335}
1336
1337static void vrdpPointFX2Point (const POINTFIX *pptfx, VRDEORDERPOINT *ppt)
1338{
1339 ppt->x = (int16_t)FXTOLROUND(pptfx->x);
1340 ppt->y = (int16_t)FXTOLROUND(pptfx->y);
1341}
1342
1343static void vrdpPolyPointsAdd (VRDEORDERPOLYPOINTS *pPoints, const VRDEORDERPOINT *ppt)
1344{
1345 VBVA_ASSERT(pPoints->c < RT_ELEMENTS(pPoints->a));
1346
1347 pPoints->a[pPoints->c] = *ppt;
1348
1349 pPoints->c++;
1350}
1351
1352static void vrdpExtendOrderBounds (VRDEORDERBOUNDS *pBounds, const VRDEORDERPOINT *ppt)
1353{
1354 /* Bounds have inclusive pt1 and exclusive pt2. */
1355
1356 if (pBounds->pt1.x > ppt->x) /* Left. */
1357 {
1358 pBounds->pt1.x = ppt->x;
1359 }
1360 if (pBounds->pt1.y > ppt->y) /* Top. */
1361 {
1362 pBounds->pt1.y = ppt->y;
1363 }
1364 if (pBounds->pt2.x <= ppt->x) /* Right. */
1365 {
1366 pBounds->pt2.x = ppt->x + 1;
1367 }
1368 if (pBounds->pt2.y <= ppt->y) /* Bottom. */
1369 {
1370 pBounds->pt2.y = ppt->y + 1;
1371 }
1372}
1373
1374void vrdpStrokePath(
1375 SURFOBJ *pso,
1376 PATHOBJ *ppo,
1377 CLIPOBJ *pco,
1378 XFORMOBJ *pxo,
1379 BRUSHOBJ *pbo,
1380 POINTL *pptlBrushOrg,
1381 LINEATTRS *plineattrs,
1382 MIX mix
1383 )
1384{
1385 PPDEV ppdev = (PPDEV)pso->dhpdev;
1386
1387 /*
1388 * StrokePath operation is supported by RDP_ORDER_POLYGON/POLYLINE/ELLIPSE.
1389 */
1390 VRDPCLIPRECTS clipRects;
1391 int clipResult;
1392 RECTFX rcfxBounds;
1393 RECTL rclBoundsOrdered;
1394
1395 DISPDBG((1, "vrdpStrokePath: pso = %p, ppo = %p, pco = %p, pxo = %p, pbo = %p, pptlBrushOrg = %p, plineattrs = %p, mix = 0x%08X\n",
1396 pso, ppo, pco, pxo, pbo, pptlBrushOrg, plineattrs, mix));
1397
1398 DISPDBG((1, "vrdpStrokePath: ppo: fl = 0x%08X, cCurves = %d\n", ppo->fl, ppo->cCurves));
1399
1400 PATHOBJ_vGetBounds(ppo, &rcfxBounds);
1401
1402 rclBoundsOrdered.left = FXTOLFLOOR(rcfxBounds.xLeft);
1403 rclBoundsOrdered.right = FXTOLCEILING(rcfxBounds.xRight);
1404 rclBoundsOrdered.top = FXTOLFLOOR(rcfxBounds.yTop);
1405 rclBoundsOrdered.bottom = FXTOLCEILING(rcfxBounds.yBottom);
1406
1407 vrdpOrderRect (&rclBoundsOrdered);
1408
1409 DISPDBG((1, "vrdpStrokePath: ppo: bounds %x-%x, %x-%x, %d-%d %d-%d\n",
1410 rcfxBounds.xLeft, rcfxBounds.xRight, rcfxBounds.yTop, rcfxBounds.yBottom,
1411 rclBoundsOrdered.left, rclBoundsOrdered.right, rclBoundsOrdered.top, rclBoundsOrdered.bottom));
1412
1413 clipResult = vrdpGetIntersectingClipRects (&clipRects, pso, &rclBoundsOrdered, pco, NULL);
1414
1415 if (clipResult == VRDP_CLIP_NO_INTERSECTION)
1416 {
1417 /* Do nothing. The operation does not affect anything. */
1418 DISPDBG((1, "VRDP::vrdpStrokePath: VRDP_CLIP_NO_INTERSECTION!!!\n"));
1419 dumpPCO (&rclBoundsOrdered, pco);
1420 }
1421 else if (clipResult == VRDP_CLIP_TOO_MANY_RECTS)
1422 {
1423 /* A very complex clip. Better to emulate it. */
1424 DISPDBG((1, "VRDP::vrdpStrokePath: VRDP_CLIP_TOO_MANY_RECTS!!!\n"));
1425 dumpPCO (&rclBoundsOrdered, pco);
1426
1427 vrdpReportDirtyRects (ppdev, &clipRects);
1428 }
1429 else if (pbo->iSolidColor == 0xFFFFFFFF)
1430 {
1431 /* Not solid brushes are not supported. */
1432 vrdpReportDirtyRects (ppdev, &clipRects);
1433 }
1434 else if (ppo->fl & PO_ELLIPSE)
1435 {
1436 if (vboxOrderSupported (ppdev, VRDE_ORDER_ELLIPSE))
1437 {
1438 VRDEORDERELLIPSE order;
1439
1440 order.pt1.x = (int16_t)FXTOLROUND(rcfxBounds.xLeft + 4);
1441 order.pt1.y = (int16_t)FXTOLROUND(rcfxBounds.yTop + 4);
1442 order.pt2.x = (int16_t)FXTOLROUND(rcfxBounds.xRight - 4);
1443 order.pt2.y = (int16_t)FXTOLROUND(rcfxBounds.yBottom - 4);
1444
1445 order.mix = (uint8_t)(mix & 0x1F);
1446 order.fillMode = 0;
1447 order.rgb = vrdpColor2RGB (pso, pbo->iSolidColor);
1448
1449 vrdpReportOrderGeneric (ppdev, &clipRects, &order, sizeof (order), VRDE_ORDER_ELLIPSE);
1450 }
1451 else
1452 {
1453 DISPDBG((1, "VRDP::vrdpStrokePath: ELLIPSE not supported\n"));
1454 vrdpReportDirtyRects (ppdev, &clipRects);
1455 }
1456 }
1457 else if ( (ppo->fl & PO_BEZIERS) == 0
1458 && (plineattrs->fl & LA_GEOMETRIC) == 0
1459 && plineattrs->pstyle == NULL)
1460 {
1461 unsigned i;
1462 PATHDATA pd;
1463 BOOL bMore;
1464 VRDEORDERPOLYLINE order;
1465 VRDEORDERPOINT ptStart;
1466 VRDEORDERBOUNDS bounds;
1467
1468 order.rgb = vrdpColor2RGB (pso, pbo->iSolidColor);
1469 order.mix = (uint8_t)(mix & 0x1F);
1470
1471 PATHOBJ_vEnumStart (ppo);
1472
1473 order.points.c = 0;
1474
1475 do {
1476 POINTFIX *pptfx;
1477 VRDEORDERPOINT pt;
1478
1479 bMore = PATHOBJ_bEnum (ppo, &pd);
1480
1481 DISPDBG((1, "vrdpStrokePath: pd: flags = 0x%08X, count = %d\n", pd.flags, pd.count));
1482
1483 pptfx = &pd.pptfx[0];
1484
1485 if (pd.flags & PD_BEGINSUBPATH)
1486 {
1487 /* Setup first point. Start a new order. */
1488 DISPDBG((1, "vrdpStrokePath: BEGINSUBPATH.\n"));
1489
1490 VBVA_ASSERT(order.points.c == 0);
1491
1492 vrdpPointFX2Point (pptfx, &ptStart);
1493 order.ptStart = ptStart;
1494 pt = ptStart;
1495
1496 bounds.pt1 = bounds.pt2 = ptStart;
1497
1498 pptfx++;
1499 i = 1;
1500 }
1501 else
1502 {
1503 DISPDBG((1, "vrdpStrokePath: Continue order.\n"));
1504
1505 i = 0;
1506 }
1507
1508 for (; i < pd.count; i++, pptfx++)
1509 {
1510 DISPDBG((1, "vrdpStrokePath: pd: %2d: %x,%x %d,%d\n",
1511 i, pptfx->x, pptfx->y, FXTOLROUND(pptfx->x), FXTOLROUND(pptfx->y)));
1512
1513 vrdpPointFX2Point (pptfx, &pt);
1514 vrdpPolyPointsAdd (&order.points, &pt);
1515 vrdpExtendOrderBounds (&bounds, &pt);
1516
1517 if (order.points.c == RT_ELEMENTS(order.points.a))
1518 {
1519 /* Flush the order and start a new order. */
1520 DISPDBG((1, "vrdpStrokePath: Report order, points overflow.\n"));
1521
1522 vrdpReportOrderGenericBounds (ppdev, &clipRects, &bounds, &order, sizeof (order), VRDE_ORDER_POLYLINE);
1523
1524 order.points.c = 0;
1525 order.ptStart = pt;
1526 bounds.pt1 = bounds.pt2 = pt;
1527 }
1528 }
1529
1530 if (pd.flags & PD_CLOSEFIGURE)
1531 {
1532 /* Encode the start point as the end point. */
1533 DISPDBG((1, "vrdpStrokePath: Report order, CLOSEFIGURE.\n"));
1534
1535 if ( ptStart.x != pt.x
1536 || ptStart.y != pt.y)
1537 {
1538 VBVA_ASSERT(order.points.c < RT_ELEMENTS(order.points.a));
1539
1540 vrdpPolyPointsAdd (&order.points, &ptStart);
1541 vrdpExtendOrderBounds (&bounds, &ptStart);
1542 }
1543 }
1544
1545 if (pd.flags & PD_ENDSUBPATH)
1546 {
1547 /* Finish the order. */
1548 DISPDBG((1, "vrdpStrokePath: Report order, ENDSUBPATH.\n"));
1549
1550 if (order.points.c > 0)
1551 {
1552 vrdpReportOrderGenericBounds (ppdev, &clipRects, &bounds, &order, sizeof (order), VRDE_ORDER_POLYLINE);
1553 }
1554
1555 order.points.c = 0;
1556 }
1557 } while (bMore);
1558 }
1559 else
1560 {
1561 /* Not supported. */
1562 DISPDBG((1, "VRDP::vrdpStrokePath: not supported: ppo->fl = %08X, plineattrs->fl = %08X, plineattrs->pstyle = %08X\n",
1563 ppo->fl, plineattrs->fl, plineattrs->pstyle));
1564
1565 vrdpReportDirtyRects (ppdev, &clipRects);
1566 }
1567
1568 return;
1569}
1570
1571void vrdpStrokeAndFillPath(
1572 SURFOBJ *pso,
1573 PATHOBJ *ppo,
1574 CLIPOBJ *pco,
1575 XFORMOBJ *pxo,
1576 BRUSHOBJ *pboStroke,
1577 LINEATTRS *plineattrs,
1578 BRUSHOBJ *pboFill,
1579 POINTL *pptlBrushOrg,
1580 MIX mixFill,
1581 FLONG flOptions
1582 )
1583{
1584 PPDEV ppdev = (PPDEV)pso->dhpdev;
1585
1586 vrdpReportDirtyPath (ppdev, pco, ppo);
1587}
1588
1589BOOL vrdpRealizeBrush(
1590 BRUSHOBJ *pbo,
1591 SURFOBJ *psoTarget,
1592 SURFOBJ *psoPattern,
1593 SURFOBJ *psoMask,
1594 XLATEOBJ *pxlo,
1595 ULONG iHatch
1596 )
1597{
1598 BOOL bRc = FALSE;
1599
1600 DISPDBG((1, "vrdpRealizeBrush: psoMask = %p, iHatch = %d\n", psoMask, iHatch));
1601
1602 if (psoPattern)
1603 {
1604 DISPDBG((1, " DHSURF dhsurf = %p\n", psoPattern->dhsurf));
1605 DISPDBG((1, " HSURF hsurf = %p\n", psoPattern->hsurf));
1606 DISPDBG((1, " DHPDEV dhpdev = %p\n", psoPattern->dhpdev));
1607 DISPDBG((1, " HDEV hdev = %p\n", psoPattern->hdev));
1608 DISPDBG((1, " SIZEL sizlBitmap = %dx%d\n", psoPattern->sizlBitmap.cx, psoPattern->sizlBitmap.cy));
1609 DISPDBG((1, " ULONG cjBits = %p\n", psoPattern->cjBits));
1610 DISPDBG((1, " PVOID pvBits = %p\n", psoPattern->pvBits));
1611 DISPDBG((1, " PVOID pvScan0 = %p\n", psoPattern->pvScan0));
1612 DISPDBG((1, " LONG lDelta = %p\n", psoPattern->lDelta));
1613 DISPDBG((1, " ULONG iUniq = %p\n", psoPattern->iUniq));
1614 DISPDBG((1, " ULONG iBitmapFormat = %p\n", psoPattern->iBitmapFormat));
1615 DISPDBG((1, " USHORT iType = %p\n", psoPattern->iType));
1616 DISPDBG((1, " USHORT fjBitmap = %p\n", psoPattern->fjBitmap));
1617 }
1618
1619 if (psoPattern
1620 && psoPattern->sizlBitmap.cx == 8
1621 && psoPattern->sizlBitmap.cy == 8
1622 && psoPattern->iBitmapFormat == 1
1623 )
1624 {
1625 uint32_t cbBrush = sizeof (VRDPBRUSH);
1626
1627 VRDPBRUSH *pBrush = (VRDPBRUSH *)BRUSHOBJ_pvAllocRbrush (pbo, cbBrush);
1628
1629 DISPDBG((1, "vrdpRealizeBrush: pattern pBrush = %p, size = %d\n", pBrush, cbBrush));
1630
1631 if (pBrush)
1632 {
1633 int i;
1634 uint8_t *pu8Bits = (uint8_t *)psoPattern->pvScan0;
1635
1636 for (i = 0; i < 8; i++)
1637 {
1638 pBrush->u.pat.au8Pattern[i] = *pu8Bits;
1639
1640 pu8Bits += psoPattern->lDelta;
1641 }
1642
1643 /* Obtain RGB values for the brush fore and background colors:
1644 * "should translate color zero through the XLATEOBJ to get the foreground color for the brush."
1645 */
1646 pBrush->u.pat.rgbFG = vrdpColor2RGB (psoTarget, pxlo->pulXlate[0]);
1647 pBrush->u.pat.rgbBG = vrdpColor2RGB (psoTarget, pxlo->pulXlate[1]);
1648
1649 pBrush->fPattern = TRUE;
1650
1651 bRc = TRUE;
1652 }
1653 }
1654#if 0
1655 else if (psoPattern)
1656 {
1657 /* Color brushes and brushes >8x8 are cached and MEMBLT order generated. */
1658 uint32_t cbBrush = sizeof (VRDPBRUSH) +
1659 psoTarget->sizlBitmap.cx * sizeof (uint32_t) * psoTarget->sizlBitmap.cy;
1660 ??? target
1661
1662 VRDPBRUSH *pBrush = (VRDPBRUSH *)BRUSHOBJ_pvAllocRbrush (pbo, cbBrush);
1663
1664 DISPDBG((1, "vrdpRealizeBrush: bitmap pBrush = %p, size = %d\n", pBrush, cbBrush));
1665
1666 if (pBrush)
1667 {
1668 /* Byte per pattern pixel. */
1669 uint32_t cbSrcBPP = format2BytesPerPixel(psoPattern);
1670
1671 /* Source bits scanline pointer. */
1672 uint8_t *pu8BitsSrcScanLine = (uint8_t *)psoPattern->pvScan0;
1673
1674 /* Target RGB pixel pointer. */
1675 uint32_t *pu32BitsDst = &pBrush->u.bitmap.au32Bits[0];
1676
1677 int y;
1678 for (y = 0; y < psoTarget->sizlBitmap.cy; y++, pu8BitsSrcScanLine += psoPattern->lDelta)
1679 {
1680 uint8_t *pu8BitsSrc = pu8BitsSrcScanLine;
1681
1682 int x;
1683
1684 for (x = 0; x < psoTarget->sizlBitmap.cx; x++, pu8BitsSrc += cbSrcBPP)
1685 {
1686 uint32_t color = 0;
1687
1688 memcpy (&color, pu8BitsSrc, cbSrcBPP);
1689
1690 if (pxlo)
1691 {
1692 color = XLATEOBJ_iXlate (pxlo, color);
1693 }
1694
1695 *pu32BitsDst++ = vrdpColor2RGB (psoTarget, color);
1696
1697 // DISPDBG((1, "%08X", pu32BitsDst[-1]));
1698 }
1699
1700 // DISPDBG((1, "\n"));
1701 }
1702
1703 pBrush->u.bitmap.w = (uint16_t)psoTarget->sizlBitmap.cx;
1704 pBrush->u.bitmap.h = (uint16_t)psoTarget->sizlBitmap.cy;
1705
1706 pBrush->fPattern = FALSE;
1707
1708 bRc = TRUE;
1709 }
1710 }
1711#endif /* 0 */
1712
1713 return bRc;
1714}
1715
1716void vrdpSaveScreenBits(
1717 SURFOBJ *pso,
1718 ULONG iMode,
1719 ULONG_PTR ident,
1720 RECTL *prcl
1721 )
1722{
1723 PPDEV ppdev = (PPDEV)pso->dhpdev;
1724
1725 switch (iMode)
1726 {
1727 case SS_SAVE:
1728 {
1729 VRDEORDERSAVESCREEN order;
1730
1731 order.pt1.x = (int16_t)prcl->left;
1732 order.pt1.y = (int16_t)prcl->top;
1733 order.pt2.x = (int16_t)prcl->right;
1734 order.pt2.y = (int16_t)prcl->bottom;
1735
1736 order.ident = (uint8_t)ident;
1737 order.restore = 0;
1738
1739 vrdpReportOrderGeneric (ppdev, NULL, &order, sizeof (order), VRDE_ORDER_SAVESCREEN);
1740 } break;
1741
1742 case SS_RESTORE:
1743 {
1744 VRDEORDERSAVESCREEN order;
1745
1746 order.pt1.x = (int16_t)prcl->left;
1747 order.pt1.y = (int16_t)prcl->top;
1748 order.pt2.x = (int16_t)prcl->right;
1749 order.pt2.y = (int16_t)prcl->bottom;
1750
1751 order.ident = (uint8_t)ident;
1752 order.restore = 1;
1753
1754 if (vrdpReportOrderGeneric (ppdev, NULL, &order, sizeof (order), VRDE_ORDER_SAVESCREEN))
1755 {
1756 uint8_t *pu8Bits;
1757 int32_t lDelta;
1758 uint32_t w;
1759 uint32_t h;
1760
1761 int cbPixel;
1762
1763 pso = CONV_SURF(pso);
1764
1765 cbPixel = format2BytesPerPixel(pso);
1766
1767 pu8Bits = (uint8_t *)pso->pvScan0 +
1768 pso->lDelta * prcl->top +
1769 cbPixel * prcl->left;
1770
1771 lDelta = pso->lDelta;
1772
1773 w = prcl->right - prcl->left;
1774 h = prcl->bottom - prcl->top;
1775
1776 vrdpWriteBits (ppdev, pu8Bits, lDelta, prcl->left, prcl->top, w, h, cbPixel);
1777 }
1778 } break;
1779
1780 default:
1781 DISPDBG((1, "vrdpSaveScreenBits Invalid mode %d!!!\n", iMode));
1782 }
1783}
1784
1785void vrdpReset (PPDEV ppdev)
1786{
1787 DISPDBG((1, "vrdpReset %p\n", ppdev));
1788
1789 vrdpbmpReset (&ppdev->cache);
1790
1791 return;
1792}
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