VirtualBox

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

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

Inform VBVA and VRDP about rectangle updated within DdLock/DdUnlock (fixes missing images in Word).

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