2 Copyright © 2010-2012, The AROS Development Team. All rights reserved.
3 $Id: compositingclass.c 38905 2011-05-29 06:54:59Z deadwood $
12 #define DREDRAWBM(x) x
13 #define DREDRAWSCR(x) x
27 #include <aros/debug.h>
29 #include <proto/exec.h>
30 #include <proto/dos.h>
31 #include <proto/graphics.h>
32 #include <proto/oop.h>
33 #include <proto/utility.h>
35 #include <graphics/view.h>
36 #include <hidd/graphics.h>
38 #include "compositing_intern.h"
40 #define COMPOSITE_PREFS "SYS/compositor.prefs"
41 #define COMPOSITE_PEFSTEMPLATE "ABOVE/S,BELOW/S,LEFT/S,RIGHT/S,ALPHA/S"
57 #define GfxBase compdata->GraphicsBase
59 #define _RECT(x) x.MinX, x.MinY, x.MaxX, x.MaxY
61 #define MAX(a,b) a > b ? a : b
62 #define MIN(a,b) a < b ? a : b
64 static BOOL AndRectRect(struct Rectangle * rect1, struct Rectangle * rect2,
65 struct Rectangle * intersect)
67 intersect->MinX = MAX(rect1->MinX, rect2->MinX);
68 intersect->MinY = MAX(rect1->MinY, rect2->MinY);
69 intersect->MaxX = MIN(rect1->MaxX, rect2->MaxX);
70 intersect->MaxY = MIN(rect1->MaxY, rect2->MaxY);
72 if ((intersect->MinX > intersect->MaxX) ||
73 (intersect->MinY > intersect->MaxY))
79 static struct StackBitMapNode * HIDDCompositingIsBitMapOnStack(struct HIDDCompositingData * compdata, OOP_Object * bm)
81 struct StackBitMapNode * n = NULL;
83 ForeachNode(&compdata->bitmapstack, n)
92 static VOID HIDDCompositingValidateBitMapPositionChange(OOP_Object * bm, SIPTR *newxoffset, SIPTR *newyoffset, LONG displayedwidth, LONG displayedheight)
95 LONG neglimit, poslimit;
97 OOP_GetAttr(bm, aHidd_BitMap_Width, &width);
98 OOP_GetAttr(bm, aHidd_BitMap_Height, &height);
100 /* Check x position */
101 if (width > displayedwidth)
103 neglimit = displayedwidth - width;
109 poslimit = displayedwidth - width;
112 if (*(newxoffset) > poslimit)
113 *(newxoffset) = poslimit;
114 if (*(newxoffset) < neglimit)
115 *(newxoffset) = neglimit;
117 /* Check y position */
118 if (height > displayedheight)
119 neglimit = displayedheight - height; /* Limit for scroll */
122 poslimit = displayedheight - 15; /* Limit for drag */
124 if (*(newyoffset) > poslimit)
125 *(newyoffset) = poslimit;
126 if (*(newyoffset) < neglimit)
127 *(newyoffset) = neglimit;
130 static VOID HIDDCompositingRecalculateVisibleRegions(struct HIDDCompositingData *compdata)
132 struct StackBitMapNode *n = NULL, *tmpn;
133 struct Region *dispvisregion = NULL;
136 DRECALC(bug("[Compositing:%s] Display rect [%d, %d - %d, %d]\n", __PRETTY_FUNCTION__, _RECT(compdata->screenrect)));
139 * This function assumes bitmapstack is in correct Z order:
140 * from topmost to bottom most
142 if ((dispvisregion = NewRegion()) != NULL)
144 OrRectRegion(dispvisregion, &compdata->screenrect);
146 DRECALC(bug("[Compositing:%s] DisplayRegion @ 0x%p\n", __PRETTY_FUNCTION__, dispvisregion));
148 ForeachNodeSafe(&compdata->bitmapstack, n, tmpn)
150 /* Get bitmap bounding box in screen coordinates */
151 struct Rectangle tmprect;
153 n->sbmflags &= ~STACKNODE_VISIBLE;
156 DisposeRegion(n->screenregion);
158 if ((n->screenregion = NewRegion()) != NULL)
160 tmprect.MinX = n->leftedge;
161 tmprect.MaxX = n->leftedge + OOP_GET(n->bm, aHidd_BitMap_Width) - 1;
162 tmprect.MinY = n->topedge;
163 tmprect.MaxY = n->topedge + OOP_GET(n->bm, aHidd_BitMap_Height) - 1;
165 DRECALC(bug("[Compositing:%s] Screen Rect [%d, %d - %d, %d]\n", __PRETTY_FUNCTION__, _RECT(&tmprect)));
167 OrRectRegion(n->screenregion, &tmprect); // Start with the Screen's dimensions ..
168 AndRegionRegion(dispvisregion, n->screenregion); // And adjust for the "Display"
170 if (n->screenregion->RegionRectangle)
173 bmpxfmt = (OOP_Object *)OOP_GET(n->bm, aHidd_BitMap_PixFmt);
174 bmpstdfmt = (int)OOP_GET(bmpxfmt, aHidd_PixFmt_StdPixFmt);
175 DRECALC(bug("[Compositing:%s] Screen BitMap PixFmt %lx @ 0x%p\n", __PRETTY_FUNCTION__, bmpstdfmt, bmpxfmt));
179 case vHidd_StdPixFmt_ARGB32:
180 case vHidd_StdPixFmt_BGRA32:
181 case vHidd_StdPixFmt_RGBA32:
182 case vHidd_StdPixFmt_ABGR32:
184 DRECALC(bug("[Compositing:%s] BitMap has ALPHA\n", __PRETTY_FUNCTION__));
186 n->sbmflags |= STACKNODE_ALPHA;
188 if (!(compdata->alpharegion))
190 compdata->alpharegion = NewRegion();
191 DRECALC(bug("[Compositing:%s] AlphaRegion Allocated @ 0x%p\n", __PRETTY_FUNCTION__, compdata->alpharegion));
194 OrRegionRegion(compdata->alpharegion, n->screenregion);
199 n->sbmflags &= ~STACKNODE_ALPHA;
201 AndRectRect(&n->screenregion->bounds, &compdata->screenrect, &n->screenvisiblerect);
202 ClearRegionRegion(n->screenregion, dispvisregion);
204 if (!(compdata->capabilities & COMPF_ABOVE))
206 tmprect.MinX = compdata->screenrect.MinX;
207 tmprect.MaxX = compdata->screenrect.MaxX;
208 tmprect.MinY = compdata->screenrect.MinY;
209 tmprect.MaxY = n->topedge - 1;
210 ClearRectRegion(dispvisregion, &tmprect);
212 if (!(compdata->capabilities & COMPF_BELOW))
214 tmprect.MinX = compdata->screenrect.MinX;
215 tmprect.MaxX = compdata->screenrect.MaxX;
216 tmprect.MinY = n->topedge + OOP_GET(n->bm, aHidd_BitMap_Height);
217 tmprect.MaxY = compdata->screenrect.MaxY;
218 ClearRectRegion(dispvisregion, &tmprect);
220 if (!(compdata->capabilities & COMPF_LEFT))
222 tmprect.MinX = compdata->screenrect.MinX;
223 tmprect.MaxX = n->leftedge - 1;
224 tmprect.MinY = n->topedge;
225 tmprect.MaxY = n->topedge + OOP_GET(n->bm, aHidd_BitMap_Height) - 1;
226 ClearRectRegion(dispvisregion, &tmprect);
228 if (!(compdata->capabilities & COMPF_RIGHT))
230 tmprect.MinX = n->leftedge + OOP_GET(n->bm, aHidd_BitMap_Width);
231 tmprect.MaxX = compdata->screenrect.MaxX;
232 tmprect.MinY = n->topedge;
233 tmprect.MaxY = n->topedge + OOP_GET(n->bm, aHidd_BitMap_Height) - 1;
234 ClearRectRegion(dispvisregion, &tmprect);
238 n->sbmflags |= STACKNODE_VISIBLE;
241 DRECALC(bug("[Compositing:%s] Bitmap 0x%x, topedge %d, visible %d, [%d, %d - %d, %d]\n", __PRETTY_FUNCTION__,
242 n->bm, n->topedge, (n->sbmflags & STACKNODE_VISIBLE), _RECT(n->screenvisiblerect)));
246 DRECALC(bug("[Compositing:%s] Failed to create Screen Region\n", __PRETTY_FUNCTION__));
249 DisposeRegion(dispvisregion);
253 DRECALC(bug("[Compositing:%s] Failed to create Display Region\n", __PRETTY_FUNCTION__));
257 static HIDDT_ModeID FindBestHiddMode(struct HIDDCompositingData *compdata, ULONG width, ULONG height, ULONG depth, ULONG *res_depth)
259 HIDDT_ModeID mode = vHidd_ModeID_Invalid;
260 OOP_Object *sync, *pf;
263 ULONG found_delta = -1;
264 ULONG found_width = 0;
265 ULONG found_height = 0;
266 ULONG found_depth = 0;
267 HIDDT_ModeID found_mode = vHidd_ModeID_Invalid;
269 DMODE(bug("[%s] Finding best match for mode %ux%ux%u\n", __PRETTY_FUNCTION__, width, height, depth));
271 while ((mode = HIDD_Gfx_NextModeID(compdata->gfx, mode, &sync, &pf)) != vHidd_ModeID_Invalid)
275 DMODE(bug("[%s] Checking mode 0x%08X... ", __PRETTY_FUNCTION__, mode));
276 if (OOP_GET(pf, aHidd_PixFmt_ColorModel) != vHidd_ColorModel_TrueColor)
278 DMODE(bug("Skipped (not truecolor)\n"));
282 OOP_GetAttr(sync, aHidd_Sync_HDisp, &w);
283 OOP_GetAttr(sync, aHidd_Sync_VDisp, &h);
284 OOP_GetAttr(pf, aHidd_PixFmt_Depth, &d);
286 dw = w > width ? w - width : w < width ? width - w : 1;
287 dh = h > height ? h - height : h < height ? height - h : 1;
291 if (delta < found_delta)
293 /* If mode resolution is closer to the needed one, we've got a better match */
300 else if (delta == found_delta)
302 /* If resolution is the same as that of current candidate mode, we can look at depth. */
303 if (found_depth > depth)
306 * Candidate mode if deeper than requested. We can supersede it with another mode
307 * of smaller depth, but which still matches our request.
309 if ((d < found_depth) && (d >= depth))
312 else if (found_depth < depth)
315 * We want better depth than current candidate.
316 * In this case anything deeper will do.
326 * Mode with the same delta, but larger depth, may supersede
327 * previous mode, if we prefer deeper ones.
329 DMODE(bug("Selected (%ldx%ldx%ld, delta = %u)", w, h, d, delta));
336 /* Store mode information */
337 compdata->screenrect.MinX = 0;
338 compdata->screenrect.MinY = 0;
339 compdata->screenrect.MaxX = found_width - 1;
340 compdata->screenrect.MaxY = found_height - 1;
341 *res_depth = found_depth;
346 static void UpdateDisplayMode(struct HIDDCompositingData *compdata)
348 struct StackBitMapNode *n;
349 IPTR modeid, width, height, depth;
350 OOP_Object *sync, *pf;
351 UBYTE comp_depth = 16;
355 * Examine all bitmaps in the stack to figure out the needed depth.
356 * We need a maximum depth of all depths in order to keep correct colors.
357 * But not less than 16 bits, because we can't compose on a LUT screen.
359 * If a LUT bitmap is present in the stack (depth < 9), we request truecolor
360 * screen for better color presentation.
362 * We examine bitmaps in reverse order, in this case 'sync' will hold
363 * information about the top bitmap when we exit the loop.
364 * Size of our composited mode needs to be as close as possible to that one.
366 for (n = (struct StackBitMapNode *)compdata->bitmapstack.mlh_TailPred;
367 n->n.mln_Pred; n = (struct StackBitMapNode *)n->n.mln_Pred)
369 OOP_GetAttr(n->bm, aHidd_BitMap_ModeID, &modeid);
370 HIDD_Gfx_GetMode(compdata->gfx, modeid, &sync, &pf);
372 if (OOP_GET(pf, aHidd_PixFmt_ColorModel) == vHidd_ColorModel_TrueColor)
374 OOP_GetAttr(pf, aHidd_PixFmt_Depth, &depth);
375 if (depth > comp_depth)
381 * If we have a LUT bitmap on stack, we request 24-bit screen
382 * for better color transfer.
388 /* Get the needed size */
389 OOP_GetAttr(sync, aHidd_Sync_HDisp, &width);
390 OOP_GetAttr(sync, aHidd_Sync_VDisp, &height);
392 DSTACK(bug("[%s] Requested mode %ldx%ldx%d\n", __PRETTY_FUNCTION__, width, height, comp_depth));
394 modeid = FindBestHiddMode(compdata, width, height, depth, &found_depth);
395 DSTACK(bug("[%s] Composition Display Mode 0x%08X [current 0x%08X]\n", __PRETTY_FUNCTION__, modeid, compdata->screenmodeid));
397 if (modeid != compdata->screenmodeid)
399 /* The mode is different. Need to prepare information needed for compositing */
400 struct TagItem gctags[] =
402 { aHidd_GC_Foreground, 0x99999999 },
406 /* Signal mode change */
407 compdata->screenmodeid = modeid;
408 compdata->modeschanged = TRUE;
410 /* Get gray foregound */
411 if (found_depth < 24)
412 gctags[0].ti_Data = 0x9492;
414 OOP_SetAttrs(compdata->gc, gctags);
418 static inline void HIDDCompositingRedrawBitmap(struct HIDDCompositingData *compdata, struct StackBitMapNode *n, struct Rectangle *rect)
420 /* The given rectangle is already in screen coordinate system here */
421 ULONG blitwidth = rect->MaxX - rect->MinX + 1;
422 ULONG blitheight = rect->MaxY - rect->MinY + 1;
424 DREDRAWBM(bug("[Compositing:%s] Redraw BitMap 0x%p, Rect[%d, %d - %d, %d]\n", __PRETTY_FUNCTION__, n->bm,
425 rect->MinX, rect->MinY, rect->MaxX, rect->MaxY));
426 DREDRAWBM(bug("[Compositing:%s] Blitting %dx%d [from %d, %d]\n", __PRETTY_FUNCTION__, blitwidth, blitheight,
427 rect->MinX - n->leftedge, rect->MinY - n->topedge));
429 HIDD_Gfx_CopyBox(compdata->gfx, n->bm,
430 /* Transform to source bitmap coord system */
431 rect->MinX - n->leftedge, rect->MinY - n->topedge,
432 compdata->compositedbitmap,
433 rect->MinX, rect->MinY, blitwidth, blitheight,
437 static inline void ClearRect(struct HIDDCompositingData *compdata, ULONG MinX, ULONG MinY, ULONG MaxX, ULONG MaxY)
439 DREDRAWSCR(bug("[Compositing:%s] Clearing [%d, %d - %d, %d]\n", __PRETTY_FUNCTION__,
440 MinX, MinY, MaxX, MaxY));
442 HIDD_BM_FillRect(compdata->compositedbitmap, compdata->gc,
443 MinX, MinY, MaxX, MaxY);
446 static VOID HIDDCompositingRedrawVisibleDisplay(struct HIDDCompositingData *compdata)
448 struct Region *dispvisregion = NULL;
449 struct Rectangle tmprect;
451 struct StackBitMapNode *n;
453 DREDRAWSCR(bug("[Compositing:%s] Redrawing screen (GfxBase @ 0x%p)\n", __PRETTY_FUNCTION__, GfxBase));
455 /* Recalculate visible regions */
456 HIDDCompositingRecalculateVisibleRegions(compdata);
458 if ((dispvisregion = NewRegion()) != NULL)
460 OrRectRegion(dispvisregion, &compdata->screenrect);
461 DRECALC(bug("[Compositing:%s] Display rect [%d, %d - %d, %d]\n", __PRETTY_FUNCTION__, _RECT(compdata->screenrect)));
463 ForeachNode(&compdata->bitmapstack, n)
465 if ((n->sbmflags & STACKNODE_VISIBLE) &&
466 (!(n->sbmflags & STACKNODE_ALPHA)) &&
469 DREDRAWSCR(bug("[Compositing:%s] ScreenRegion @ 0x%p ScreenBitMap @ 0x%p [%d, %d - %d, %d]\n", __PRETTY_FUNCTION__,
470 n->screenregion, n->bm, _RECT(n->screenvisiblerect)));
472 DREDRAWSCR(bug("[Compositing:%s] Redrawing Visible Screen Regions..\n", __PRETTY_FUNCTION__));
473 // Render the visable regions ..
474 struct RegionRectangle * srrect = n->screenregion->RegionRectangle;
477 tmprect.MinX = srrect->bounds.MinX + n->screenregion->bounds.MinX;
478 tmprect.MinY = srrect->bounds.MinY + n->screenregion->bounds.MinY;
479 tmprect.MaxX = srrect->bounds.MaxX + n->screenregion->bounds.MinX;
480 tmprect.MaxY = srrect->bounds.MaxY + n->screenregion->bounds.MinY;
482 DREDRAWSCR(bug("[Compositing:%s] Region [%d, %d - %d, %d]\n", __PRETTY_FUNCTION__, _RECT(&tmprect)));
484 HIDDCompositingRedrawBitmap(compdata, n, &tmprect);
485 HIDD_BM_UpdateRect(compdata->compositedbitmap,
486 tmprect.MinX, tmprect.MinY,
487 tmprect.MaxX - tmprect.MinX + 1,
488 tmprect.MaxY - tmprect.MinY + 1);
490 srrect = srrect->Next;
492 ClearRegionRegion(n->screenregion, dispvisregion);
495 struct RegionRectangle * dispclrrect = dispvisregion->RegionRectangle;
498 struct HIDD_BackFillHookMsg clearmsg;
500 tmprect.MinX = dispclrrect->bounds.MinX + dispvisregion->bounds.MinX;
501 tmprect.MinY = dispclrrect->bounds.MinY + dispvisregion->bounds.MinY;
502 tmprect.MaxX = dispclrrect->bounds.MaxX + dispvisregion->bounds.MinX;
503 tmprect.MaxY = dispclrrect->bounds.MaxY + dispvisregion->bounds.MinY;
505 DREDRAWSCR(bug("[Compositing:%s] Render Display Void Region [%d, %d - %d, %d]\n", __PRETTY_FUNCTION__, _RECT(&tmprect)));
507 clearmsg.bounds = &tmprect;
508 clearmsg.offsetx = 0;
509 clearmsg.offsety = 0;
510 CallHookPkt(compdata->backfillhook, compdata->compositedbitmap, &clearmsg);
511 HIDD_BM_UpdateRect(compdata->compositedbitmap,
512 tmprect.MinX, tmprect.MinY,
513 tmprect.MaxX - tmprect.MinX + 1,
514 tmprect.MaxY - tmprect.MinY + 1);
516 dispclrrect = dispclrrect->Next;
518 ForeachNode(&compdata->bitmapstack, n)
520 if ((n->sbmflags & STACKNODE_VISIBLE) &&
521 (n->sbmflags & STACKNODE_ALPHA) &&
524 DREDRAWSCR(bug("[Compositing:%s] ALPHAScreenRegion @ 0x%p ScreenBitMap @ 0x%p [%d, %d - %d, %d]\n", __PRETTY_FUNCTION__,
525 n->screenregion, n->bm, _RECT(n->screenvisiblerect)));
528 DisposeRegion(dispvisregion);
534 There are several cases that needs to be handled in this code. They are documented
535 below. Please read it before making changes.
536 etb = existing topbitmap
539 cb = composited bitmap
540 fs = covers full screen
541 nfs = not covers full screen
547 The resulting mode is always that of screen bitmap as set in "effect" column.
548 The composited bitmap always matches the resulting screen mode or is NULL.
550 | exiting screen situation | change | effect |
551 | USE CASE: SWITCHING BETWEEN FULL SCREEN SCREENS - SAME MODE |
552 | etb->fs, mA, sb==etb, cb==NULL | ntb->fs, mA | sb==ntb, cb==NULL |
553 | etb->fs, mA, sb==etb, cb!=NULL | ntb->fs, mA | sb==ntb, cb!=NULL |
554 | USE CASE: SWITCHING BETWEEN FULL SCREEN AND NOT FULL SCREEN SCREENS - SAME MODE |
555 | etb->fs, mA, sb==etb, cb==NULL | ntb->nfs, mA | new(cb), sb==cb, cb!=NULL |
556 | etb->fs, mA, sb==etb, cb!=NULL | ntb->nfs, mA | sb==cb, cb!=NULL |
557 | USE CASE: SWITCHING BETWEEN NOT FULL SCREEN AND FULL SCREEN SCREENS - SAME MODE |
558 | etb->nfs, mA, sb==cb, cb==NULL | NOT POSSIBLE |
559 | etb->nfs, mA, sb==cb, cb!=NULL | ntb->fs, mA | sb==ntb, cb!=NULL |
560 | USE CASE: SWITCHING BETWEEN NOT FULL SCREEN AND NOT FULL SCREEN SCREENS - SAME MODE |
561 | etb->nfs, mA, sb==cb, cb==NULL | NOT POSSIBLE |
562 | etb->nfs, mA, sb==cb, cb!=NULL | ntb->nfs, mA | sb==cb, cb!=NULL |
565 | USE CASE: SWITCHING BETWEEN FULL SCREEN SCREENS - DIFFERENT MODES |
566 | etb->fs, mA, sb==etb, cb==NULL | ntb->fs, mB | sb==ntb, cb==NULL |
567 | etb->fs, mA, sb==etb, cb!=NULL | ntb->fs, mB | disp(cb), sb==ntb, cb==NULL |
568 | USE CASE: SWITCHING BETWEEN FULL SCREEN AND NOT FULL SCREEN SCREENS - DIFFERENT MODES |
569 | etb->fs, mA, sb==etb, cb==NULL | ntb->nfs, mB | new(cb), sb==cb, cb!=NULL |
570 | etb->fs, mA, sb==etb, cb!=NULL | ntb->nfs, mB | disp(cb), new(cb), sb==cb, cb!=NULL |
571 | USE CASE: SWITCHING BETWEEN NOT FULL SCREEN AND FULL SCREEN SCREENS - DIFFERENT MODES |
572 | etb->nfs, mA, sb==cb, cb==NULL | NOT POSSIBLE |
573 | etb->nfs, mA, sb==cb, cb!=NULL | ntb->fs, mB | disp(cb), sb==ntb, cb==NULL |
574 | USE CASE: SWITCHING BETWEEN NOT FULL SCREEN AND NOT FULL SCREEN SCREENS - DIFFERENT MODES |
575 | etb->nfs, mA, sb==cb, cb==NULL | NOT POSSIBLE |
576 | etb->nfs, mA, sb==cb, cb!=NULL | ntb->nfs, mB | disp(cb), new(cb), sb==cb, cb!=NULL |
579 | USE CASE: DRAGGING SCREEN DOWN |
580 | etb->fs, mA, sb==etb, cb==NULL | ntb->nfs, mA | new(cb), sb==cb |
581 | etb->fs, mA, sb==etb, cb!=NULL | ntb->nfs, mA | sb==cb |
582 | USE CASE: DRAGGING SCREEN UP |
583 | etb->nfs, mA, sb==cb, cb!=NULL | ntb->fs, mA | sb==etb |
584 | etb->nfs, mA, sb==cb, cb==NULL | NOT POSSIBLE |
586 Resulting rules (order matters):
588 (a) if ((cb!=NULL) && (etb->mode!=ntb->mode)) {dispose(cb), cb=NULL}
589 (b) if ((ntb->nfs) && (cb==NULL)) new(cb)
590 (c) if (ntb->nfs) sb=cb
591 (d) if (ntb->fs) sb=ntb
594 (e) if (oldsb!=sb) modeswitch(sb)
596 02.09.2011: we don't remember sb any more because we don't handle it in any way. Instead
597 we either have or don't have compositedbitmap. If we have it, composition
598 is on (sb = cb). If we don't have it, composition is off (sb = ntb).
600 static BOOL HIDDCompositingToggleCompositing(struct HIDDCompositingData *compdata, BOOL newtop)
603 * If the topbitmap covers the complete screen, show it instead of
604 * compositedbitmap. Remember that screen bitmap -> composited bitmap
605 * mirroring has a negative impact on performance.
607 OOP_Object *oldcompositedbitmap = compdata->compositedbitmap;
608 OOP_Object *newscreenbitmap = NULL;
611 /* (a) If mode change is needed, enforce opening a new screen */
612 if (compdata->modeschanged)
614 D(bug("[Compositing:%s] Display Mode changed\n", __PRETTY_FUNCTION__));
615 compdata->compositedbitmap = NULL;
620 * This condition is enough as compositing allows only dragging screen down
621 * and not up/left/right at the moment.
627 if (compdata->compositedbitmap == NULL)
630 * compositedbitmap == NULL means we were in passthrough mode before,
631 * or have just changed display mode - set up screen for composition.
633 D(bug("[Compositing:%s] Initialising Display-Compositor..\n", __PRETTY_FUNCTION__));
638 * If our display driver uses a framebuffer, we can reuse it.
639 * Copy its original contents back into the bitmap which it replaced,
640 * then change framebuffer's video mode.
641 * Framebuffer is the only bitmap which can change its ModeID on the fly.
643 D(bug("[Compositing:%s] Using Display Famebuffer BitMap @ 0x%p\n", __PRETTY_FUNCTION__, compdata->fb));
645 /* Do this comparison in order not to show the framebuffer twice */
646 if (oldcompositedbitmap != compdata->fb)
649 * 1. It's legal to show the framebuffer itself. This causes copying
650 * back old bitmap contents and detaching from it.
651 * 2. The result of this will always match compdata->fb.
652 * 3. Internally this is a simple blit operation, it can't fail.
654 D(bug("[Compositing:%s] Copying old Famebuffer BitMap\n", __PRETTY_FUNCTION__));
655 compdata->screenbitmap = HIDD_Gfx_Show(compdata->gfx, compdata->fb, fHidd_Gfx_Show_CopyBack);
658 /* Switch display mode on the framebuffer. */
659 OOP_SetAttrsTags(compdata->fb, aHidd_BitMap_ModeID, compdata->screenmodeid, TAG_DONE);
660 /* We are now compositing on the framebuffer */
661 compdata->compositedbitmap = compdata->fb;
666 * There's no framebuffer.
667 * Create a new bitmap that will be used for compositing.
669 struct TagItem bmtags[5];
671 bmtags[0].ti_Tag = aHidd_BitMap_Width; bmtags[0].ti_Data = compdata->screenrect.MaxX + 1;
672 bmtags[1].ti_Tag = aHidd_BitMap_Height; bmtags[1].ti_Data = compdata->screenrect.MaxY + 1;
673 bmtags[2].ti_Tag = aHidd_BitMap_Displayable; bmtags[2].ti_Data = TRUE;
674 bmtags[3].ti_Tag = aHidd_BitMap_ModeID; bmtags[3].ti_Data = compdata->screenmodeid;
675 bmtags[4].ti_Tag = TAG_DONE; bmtags[4].ti_Data = TAG_DONE;
677 compdata->compositedbitmap = HIDD_Gfx_NewBitMap(compdata->gfx, bmtags);
678 D(bug("[Compositing:%s] Created Compositor Display BitMap @ 0x%p\n", __PRETTY_FUNCTION__, compdata->compositedbitmap));
680 /* Mode changed, this bitmap will be shown later */
681 newscreenbitmap = compdata->compositedbitmap;
683 /* NewBitMap can fail, handle this */
684 if (!newscreenbitmap)
688 else /* if (compdata->compositedbitmap == NULL) */
691 * We are already in compositing mode and will stay in it.
692 * Do not destroy our working bitmap.
694 oldcompositedbitmap = NULL;
698 * (c) Here composition is turned on (compositedbitmap != NULL).
699 * Redraw bitmap stack - compensate possible changes
702 HIDDCompositingRedrawVisibleDisplay(compdata);
705 else if (oldcompositedbitmap || newtop)
708 * (d) Set passthrough mode and display the frontmost bitmap.
709 * This is also triggered by 'newtop' parameter, which tells us
710 * that frontmost bitmap has been changed, and we need to display a new one.
711 * Old compositedbitmap has been remembered in the beginning. If it's not
712 * NULL, it will be destroyed in the end.
714 newscreenbitmap = compdata->topbitmap;
715 compdata->compositedbitmap = NULL;
719 DTOGGLE(bug("[Compositing:%s] oldcompbmp 0x%p, topbmp 0x%p, compbmp 0x%p, newscreenbmp 0x%p\n", __PRETTY_FUNCTION__,
720 oldcompositedbitmap, compdata->topbitmap, compdata->compositedbitmap, newscreenbitmap));
723 * (e) If the screenbitmap changed, show the new screenbitmap.
724 * We do it after refreshing, for better visual appearance.
730 compdata->screenbitmap = HIDD_Gfx_Show(compdata->gfx, newscreenbitmap, fHidd_Gfx_Show_CopyBack);
731 D(bug("[Compositing:%s] Displayed bitmap 0x%p, Show returned 0x%p\n", __PRETTY_FUNCTION__, newscreenbitmap, compdata->screenbitmap));
733 /* After Show we need Update for mirroring drivers */
734 if (compdata->screenbitmap)
736 OOP_GetAttr(compdata->screenbitmap, aHidd_BitMap_Width, &w);
737 OOP_GetAttr(compdata->screenbitmap, aHidd_BitMap_Height, &h);
738 HIDD_BM_UpdateRect(compdata->screenbitmap, 0, 0, w, h);
743 * (a) - disposing of oldcompositingbitmap needs to happen after mode switch
744 * since it could have been the current screenbitmap
746 if (oldcompositedbitmap && (oldcompositedbitmap != compdata->fb))
748 D(bug("[Compositing:%s] Disposing old working bitmap 0x%p\n", __PRETTY_FUNCTION__, oldcompositedbitmap));
749 HIDD_Gfx_DisposeBitMap(compdata->gfx, oldcompositedbitmap);
753 compdata->modeschanged = FALSE;
758 static VOID HIDDCompositingPurgeBitMapStack(struct HIDDCompositingData * compdata)
760 struct StackBitMapNode * curr, * next;
762 ForeachNodeSafe(&compdata->bitmapstack, curr, next)
764 if (curr->screenregion)
765 DisposeRegion(curr->screenregion);
767 FreeMem(curr, sizeof(struct StackBitMapNode));
770 NEWLIST(&compdata->bitmapstack);
773 static void HIDDCompositingShowSingle(struct HIDDCompositingData *compdata, OOP_Object *bm)
775 /* Show the single top bitmap */
776 compdata->topbitmap = bm;
777 compdata->screenbitmap = HIDD_Gfx_Show(compdata->gfx, bm, fHidd_Gfx_Show_CopyBack);
779 /* Dispose working bitmap (if any) */
780 if (compdata->compositedbitmap)
782 /* Be careful with the framebuffer */
783 if (compdata->compositedbitmap != compdata->fb)
784 HIDD_Gfx_DisposeBitMap(compdata->gfx, compdata->compositedbitmap);
786 /* This will deactivate us */
787 compdata->compositedbitmap = NULL;
791 /* Emergency error recovery function */
792 static void HIDDCompositingReset(struct HIDDCompositingData *compdata)
794 /* Purge bitmap stack */
795 HIDDCompositingPurgeBitMapStack(compdata);
798 * Reset our internal state so that next BitMapStackChanged
799 * causes complete reinitialization.
801 compdata->screenmodeid = vHidd_ModeID_Invalid;
802 compdata->screenbitmap = NULL;
805 VOID CompositorParseConfig(struct HIDDCompositingData *compdata)
807 struct RDArgs *rdargs;
808 IPTR CompArgs[NOOFARGS] = { 0 };
809 TEXT CompConfig[1024];
811 /* use default amiga-like capabailities */
812 compdata->capabilities = COMPF_ABOVE;
814 rdargs = AllocDosObjectTags(DOS_RDARGS, TAG_END);
815 if ((rdargs != NULL) && (GetVar(COMPOSITE_PREFS, CompConfig, 1024, GVF_GLOBAL_ONLY) != -1))
817 rdargs->RDA_Source.CS_Buffer = CompConfig;
818 rdargs->RDA_Source.CS_Length = strlen(rdargs->RDA_Source.CS_Buffer);
819 rdargs->RDA_DAList = NULL;
820 rdargs->RDA_Buffer = NULL;
821 rdargs->RDA_BufSiz = 0;
822 rdargs->RDA_ExtHelp = NULL;
823 rdargs->RDA_Flags = 0;
825 if (ReadArgs(COMPOSITE_PEFSTEMPLATE, CompArgs, rdargs) != NULL)
827 if (CompArgs[ARG_ABOVE])
828 compdata->capabilities |= COMPF_ABOVE;
830 compdata->capabilities &= ~COMPF_ABOVE;
832 if (CompArgs[ARG_BELOW])
833 compdata->capabilities |= COMPF_BELOW;
835 compdata->capabilities &= ~COMPF_BELOW;
837 if (CompArgs[ARG_LEFT])
838 compdata->capabilities |= COMPF_LEFT;
840 compdata->capabilities &= ~COMPF_LEFT;
842 if (CompArgs[ARG_RIGHT])
843 compdata->capabilities |= COMPF_RIGHT;
845 compdata->capabilities &= ~COMPF_RIGHT;
847 if (CompArgs[ARG_ALPHA])
848 compdata->capabilities |= COMPF_ALPHA;
850 compdata->capabilities &= ~COMPF_ALPHA;
854 FreeDosObject(DOS_RDARGS, rdargs);
858 AROS_UFH3(void, CompositorDefaultBackFillFunc,
859 AROS_UFHA(struct Hook * , h, A0),
860 AROS_UFHA(OOP_Object * , bm, A2),
861 AROS_UFHA(struct HIDD_BackFillHookMsg * , msg, A1))
865 struct HIDDCompositingData *compdata = h->h_Data;
867 D(bug("[%s] HIDDCompositingData @ 0x%p\n", __PRETTY_FUNCTION__, compdata));
869 ClearRect(compdata, msg->bounds->MinX, msg->bounds->MinY, msg->bounds->MaxX, msg->bounds->MaxY);
875 OOP_Object *METHOD(Compositing, Root, New)
877 o = (OOP_Object *)OOP_DoSuperMethod(cl, o, (OOP_Msg) msg);
881 OOP_MethodID disposemid;
882 struct HIDDCompositingData *compdata = OOP_INST_DATA(cl, o);
884 D(bug("[%s] Compositor @ 0x%p, data @ 0x%p\n", __PRETTY_FUNCTION__, o, compdata));
886 CompositorParseConfig(compdata);
888 D(bug("[%s] Composite Capabilities: %08lx\n", __PRETTY_FUNCTION__, compdata->capabilities));
890 compdata->screenmodeid = vHidd_ModeID_Invalid;
892 NEWLIST(&compdata->bitmapstack);
894 compdata->defaultbackfill.h_Entry = (HOOKFUNC)AROS_ASMSYMNAME(CompositorDefaultBackFillFunc);
895 compdata->defaultbackfill.h_Data = compdata;
896 compdata->backfillhook = &compdata->defaultbackfill;
898 InitSemaphore(&compdata->semaphore);
900 compdata->gfx = (OOP_Object *)GetTagData(aHidd_Compositing_GfxHidd, 0, msg->attrList);
901 compdata->fb = (OOP_Object *)GetTagData(aHidd_Compositing_FrameBuffer, 0, msg->attrList);
903 compdata->GraphicsBase = OpenLibrary("graphics.library", 41);
905 /* GfxHidd is mandatory */
906 if ((compdata->GraphicsBase) && (compdata->gfx != NULL))
908 /* Create GC object that will be used for drawing operations */
909 compdata->gc = HIDD_Gfx_NewGC(compdata->gfx, NULL);
911 D(bug("[%s] Compositor GC @ %p\n", __PRETTY_FUNCTION__, compdata->gc));
913 if ((compdata->gfx) && (compdata->gc))
917 /* Creation failed */
918 disposemid = OOP_GetMethodID(IID_Root, moRoot_Dispose);
919 OOP_CoerceMethod(cl, o, &disposemid);
925 void METHOD(Compositing, Root, Dispose)
929 struct HIDDCompositingData *compdata = OOP_INST_DATA(cl, o);
930 bug("[%s] HIDDCompositingData @ 0x%p\n", __PRETTY_FUNCTION__, compdata);
933 OOP_DoSuperMethod(cl, o, &msg->mID);
936 VOID METHOD(Compositing, Root, Get)
938 struct HIDDCompositingData *compdata = OOP_INST_DATA(cl, o);
942 case aoHidd_Compositing_Capabilities:
944 D(bug("[%s] Composite Capabilities: %lx\n", __PRETTY_FUNCTION__, compdata->capabilities));
945 *msg->storage = (IPTR)COMPF_ABOVE|COMPF_BELOW|COMPF_LEFT|COMPF_RIGHT;
948 case aoHidd_Compositing_BackFillHook:
950 D(bug("[%s] BackFillHook: 0x%p\n", __PRETTY_FUNCTION__, compdata->backfillhook));
951 *msg->storage = (IPTR)compdata->backfillhook;
956 OOP_DoSuperMethod(cl, o, &msg->mID);
959 VOID METHOD(Compositing, Root, Set)
961 struct HIDDCompositingData *compdata = OOP_INST_DATA(cl, o);
962 struct TagItem *tag, *tstate = msg->attrList;
964 while ((tag = NextTagItem(&tstate)))
968 case aoHidd_Compositing_Capabilities:
970 D(bug("[%s] Composite Capabilities: %lx -> %lx\n", __PRETTY_FUNCTION__, compdata->capabilities, tag->ti_Data));
971 compdata->capabilities = (ULONG)tag->ti_Data;
974 case aoHidd_Compositing_BackFillHook:
978 D(bug("[%s] BackFillHook: 0x%p -> 0x%p\n", __PRETTY_FUNCTION__, compdata->backfillhook, tag->ti_Data));
979 compdata->backfillhook = (struct Hook *)tag->ti_Data;
983 D(bug("[%s] Default BackFillHook\n", __PRETTY_FUNCTION__));
984 compdata->backfillhook = &compdata->defaultbackfill;
992 OOP_DoSuperMethod(cl, o, &msg->mID);
995 OOP_Object *METHOD(Compositing, Hidd_Compositing, BitMapStackChanged)
997 struct HIDD_ViewPortData *vpdata;
998 struct HIDDCompositingData *compdata = OOP_INST_DATA(cl, o);
999 struct StackBitMapNode *n;
1000 BOOL newtop = FALSE;
1003 DSTACK(bug("[%s] Top bitmap: 0x%lx\n", __PRETTY_FUNCTION__, msg->data->Bitmap));
1005 LOCK_COMPOSITING_WRITE
1007 /* Free all items which are already on the list */
1008 HIDDCompositingPurgeBitMapStack(compdata);
1015 HIDDCompositingShowSingle(compdata, NULL);
1017 /* We know we are inactive after this */
1018 *msg->active = FALSE;
1019 /* This can return NULL, it's okay */
1020 return compdata->screenbitmap;
1023 /* Copy bitmaps pointers to our stack */
1024 for (vpdata = msg->data; vpdata; vpdata = vpdata->Next)
1026 n = AllocMem(sizeof(struct StackBitMapNode), MEMF_ANY | MEMF_CLEAR);
1031 * We need to reset own state and return NULL. graphics.library
1032 * falls back to no composition in this case.
1034 DSTACK(bug("[%s] Error allocating StackBitMapNode!!!\n", __PRETTY_FUNCTION__));
1040 DSTACK(bug("[%s] ViewPort 0x%p, offset (%d, %d)\n", __PRETTY_FUNCTION__, vpdata->vpe->ViewPort, vpdata->vpe->ViewPort->DxOffset, vpdata->vpe->ViewPort->DyOffset));
1042 n->bm = vpdata->Bitmap;
1044 n->leftedge = vpdata->vpe->ViewPort->DxOffset;
1045 n->topedge = vpdata->vpe->ViewPort->DyOffset;
1047 AddTail((struct List *)&compdata->bitmapstack, (struct Node *)n);
1050 /* Switch mode if needed */
1051 UpdateDisplayMode(compdata);
1053 if (msg->data->Bitmap != compdata->topbitmap)
1055 /* Set the new pointer to top bitmap */
1056 compdata->topbitmap = msg->data->Bitmap;
1063 * Validate bitmap offsets - they might not match the compositing rules taking
1064 * new displayedwidth/displayedheight values
1066 ForeachNode(&compdata->bitmapstack, n)
1068 HIDDCompositingValidateBitMapPositionChange(n->bm, &n->leftedge, &n->topedge,
1069 compdata->screenrect.MaxX + 1, compdata->screenrect.MaxY + 1);
1070 DSTACK(bug("[%s] Bitmap 0x%p, display size %d x %d, validated position (%ld, %ld)\n", __PRETTY_FUNCTION__,
1071 n->bm, compdata->screenrect.MaxX + 1, compdata->screenrect.MaxY + 1,
1072 n->leftedge, n->topedge));
1075 /* Toogle compositing based on screen positions */
1076 ok = HIDDCompositingToggleCompositing(compdata, newtop);
1082 HIDDCompositingReset(compdata);
1083 HIDDCompositingShowSingle(compdata, msg->data->Bitmap);
1088 DSTACK(bug("[%s] Done, composited bitmap 0x%p\n", __PRETTY_FUNCTION__, compdata->compositedbitmap));
1090 /* Tell if the composition is active */
1091 *msg->active = compdata->compositedbitmap ? TRUE : FALSE;
1092 /* Return actually displayed bitmap */
1093 return compdata->screenbitmap;
1096 VOID METHOD(Compositing, Hidd_Compositing, BitMapRectChanged)
1098 struct HIDDCompositingData * compdata = OOP_INST_DATA(cl, o);
1100 if (compdata->compositedbitmap)
1102 /* Composition is active, handle redraw if the bitmap is on screen */
1103 struct StackBitMapNode *n;
1105 DUPDATE(bug("[%s] Bitmap 0x%p\n", __PRETTY_FUNCTION__, msg->bm));
1107 LOCK_COMPOSITING_READ
1109 n = HIDDCompositingIsBitMapOnStack(compdata, msg->bm);
1110 if (n && (n->sbmflags & STACKNODE_VISIBLE))
1112 struct Rectangle srcrect, dstandvisrect;
1114 srcrect.MinX = n->leftedge + msg->x;
1115 srcrect.MinY = n->topedge + msg->y;
1116 srcrect.MaxX = n->leftedge + msg->x + msg->width - 1;
1117 srcrect.MaxY = n->topedge + msg->y + msg->height - 1;
1118 DUPDATE(bug("[%s] Bitmap rect [%d, %d - %d, %d]\n", __PRETTY_FUNCTION__, msg->x, msg->y, msg->x + msg->width - 1, msg->y + msg->height - 1));
1120 DUPDATE(bug("[%s] Screen-relative rect [%d, %d - %d, %d]\n", __PRETTY_FUNCTION__, _RECT(srcrect)));
1122 struct RegionRectangle * srrect = n->screenregion->RegionRectangle;
1125 dstandvisrect.MinX = srrect->bounds.MinX + n->screenregion->bounds.MinX;
1126 dstandvisrect.MinY = srrect->bounds.MinY + n->screenregion->bounds.MinY;
1127 dstandvisrect.MaxX = srrect->bounds.MaxX + n->screenregion->bounds.MinX;
1128 dstandvisrect.MaxY = srrect->bounds.MaxY + n->screenregion->bounds.MinY;
1130 if (AndRectRect(&srcrect, &dstandvisrect, &dstandvisrect))
1132 /* Intersection is valid. Blit. */
1133 DUPDATE(bug("[%s] Clipped rect (%d, %d) - (%d, %d)\n", __PRETTY_FUNCTION__, _RECT(dstandvisrect)));
1135 HIDDCompositingRedrawBitmap(compdata, n, &dstandvisrect);
1137 HIDD_BM_UpdateRect(compdata->compositedbitmap,
1138 dstandvisrect.MinX, dstandvisrect.MinY,
1139 dstandvisrect.MaxX - dstandvisrect.MinX + 1,
1140 dstandvisrect.MaxY - dstandvisrect.MinY + 1);
1142 srrect = srrect->Next;
1148 DUPDATE(bug("[%s] Done\n", __PRETTY_FUNCTION__));
1153 * In order to speed things up, we handle passthrough ourselves here.
1154 * It's not difficult.
1156 HIDD_BM_UpdateRect(msg->bm, msg->x, msg->y, msg->width, msg->height);
1160 IPTR METHOD(Compositing, Hidd_Compositing, BitMapPositionChange)
1162 struct HIDDCompositingData *compdata = OOP_INST_DATA(cl, o);
1163 struct StackBitMapNode *n;
1164 IPTR disp_width, disp_height;
1166 LOCK_COMPOSITING_READ
1168 n = HIDDCompositingIsBitMapOnStack(compdata, msg->bm);
1171 /* The bitmap is on display. Validate against screen size */
1172 disp_width = compdata->screenrect.MaxX + 1;
1173 disp_height = compdata->screenrect.MaxY + 1;
1177 /* The bitmap is not displayed yet. Validate against its own ModeID size. */
1178 HIDDT_ModeID modeid = vHidd_ModeID_Invalid;
1179 OOP_Object *sync, *pf;
1181 OOP_GetAttr(msg->bm, aHidd_BitMap_ModeID, &modeid);
1183 if (modeid == vHidd_ModeID_Invalid)
1186 * Nondisplayable bitmaps don't scroll.
1187 * In fact they simply can't get in here because MakeVPort() performs the validation.
1188 * But who knows what bug can slip into someone's software...
1194 HIDD_Gfx_GetMode(compdata->gfx, modeid, &sync, &pf);
1195 OOP_GetAttr(sync, aHidd_Sync_HDisp, &disp_width);
1196 OOP_GetAttr(sync, aHidd_Sync_VDisp, &disp_height);
1199 DMOVE(bug("[%s] Validating bitmap 0x%p, position (%ld, %ld), limits %ld x %ld\n", __PRETTY_FUNCTION__,
1200 msg->bm, *msg->newxoffset, *msg->newyoffset, disp_width, disp_height));
1202 HIDDCompositingValidateBitMapPositionChange(msg->bm, msg->newxoffset, msg->newyoffset,
1203 disp_width, disp_height);
1205 DMOVE(bug("[%s] Validated position (%ld, %ld)\n", __PRETTY_FUNCTION__, *msg->newxoffset, *msg->newyoffset));
1207 if (n && ((*msg->newxoffset != n->leftedge) || (*msg->newyoffset != n->topedge)))
1209 DMOVE(bug("[%s] Old position (%ld, %ld)\n", __PRETTY_FUNCTION__, n->leftedge, n->topedge));
1211 /* Reflect the change if it happened */
1212 n->leftedge = *msg->newxoffset;
1213 n->topedge = *msg->newyoffset;
1215 if (compdata->topbitmap == msg->bm)
1218 * If this is the frontmost bitmap, we may want to toggle compositing,
1219 * if it starts/stops covering the whole screen at one point.
1220 * We don't need to call HIDDCompositingRedrawVisibleDisplay() here because
1221 * HIDDCompositingToggleCompositing() does this itself, for improved
1222 * visual appearance.
1224 HIDDCompositingToggleCompositing(compdata, FALSE);
1227 HIDDCompositingRedrawVisibleDisplay(compdata);
1232 /* Return active state */
1233 return compdata->compositedbitmap ? TRUE : FALSE;
1236 #define NUM_Compositing_Root_METHODS 4
1238 static const struct OOP_MethodDescr Compositing_Root_descr[] =
1240 {(OOP_MethodFunc)Compositing__Root__New, moRoot_New},
1241 {(OOP_MethodFunc)Compositing__Root__Dispose, moRoot_Dispose},
1242 {(OOP_MethodFunc)Compositing__Root__Get, moRoot_Get},
1243 {(OOP_MethodFunc)Compositing__Root__Set, moRoot_Set},
1247 #define NUM_Compositing_Hidd_Compositing_METHODS 3
1249 static const struct OOP_MethodDescr Compositing_Hidd_Compositing_descr[] =
1251 {(OOP_MethodFunc)Compositing__Hidd_Compositing__BitMapStackChanged, moHidd_Compositing_BitMapStackChanged},
1252 {(OOP_MethodFunc)Compositing__Hidd_Compositing__BitMapRectChanged, moHidd_Compositing_BitMapRectChanged},
1253 {(OOP_MethodFunc)Compositing__Hidd_Compositing__BitMapPositionChange, moHidd_Compositing_BitMapPositionChange},
1257 const struct OOP_InterfaceDescr Compositing_ifdescr[] =
1259 {Compositing_Root_descr, IID_Root, NUM_Compositing_Root_METHODS},
1260 {Compositing_Hidd_Compositing_descr, IID_Hidd_Compositing, NUM_Compositing_Hidd_Compositing_METHODS},