Fixes to comments.
[AROS.git] / workbench / devs / monitors / Compositor / compositingclass.c
bloba26de98b423638b929fc9038bdc1d28230fa346f
1 /*
2 Copyright © 2010-2012, The AROS Development Team. All rights reserved.
3 $Id: compositingclass.c 38905 2011-05-29 06:54:59Z deadwood $
4 */
6 #define DEBUG 0
7 #define DTOGGLE(x)
8 #define DMODE(x)
9 #define DMOVE(x)
10 #define DRECALC(x)
11 #define DREDRAWBM(x)
12 #define DREDRAWSCR(x)
13 #define DSTACK(x)
14 #define DUPDATE(x)
16 #include "compositing_intern.h"
18 #include <aros/debug.h>
19 #include <hidd/graphics_inline.h>
21 #include <proto/exec.h>
22 #include <proto/oop.h>
23 #include <proto/utility.h>
25 #define _RECT(x) x.MinX, x.MinY, x.MaxX, x.MaxY
27 #define MAX(a,b) a > b ? a : b
28 #define MIN(a,b) a < b ? a : b
30 static BOOL AndRectRect(struct Rectangle * rect1, struct Rectangle * rect2,
31 struct Rectangle * intersect)
33 intersect->MinX = MAX(rect1->MinX, rect2->MinX);
34 intersect->MinY = MAX(rect1->MinY, rect2->MinY);
35 intersect->MaxX = MIN(rect1->MaxX, rect2->MaxX);
36 intersect->MaxY = MIN(rect1->MaxY, rect2->MaxY);
38 if ((intersect->MinX > intersect->MaxX) ||
39 (intersect->MinY > intersect->MaxY))
40 return FALSE;
41 else
42 return TRUE;
45 static struct StackBitMapNode * HIDDCompositingIsBitMapOnStack(struct HIDDCompositingData * compdata, OOP_Object * bm)
47 struct StackBitMapNode * n = NULL;
49 ForeachNode(&compdata->bitmapstack, n)
51 if (n->bm == bm)
52 return n;
55 return NULL;
58 static VOID HIDDCompositingValidateBitMapPositionChange(OOP_Object * bm, SIPTR *newxoffset, SIPTR *newyoffset, LONG displayedwidth, LONG displayedheight)
60 IPTR width, height;
61 LONG neglimit, poslimit;
63 OOP_GetAttr(bm, aHidd_BitMap_Width, &width);
64 OOP_GetAttr(bm, aHidd_BitMap_Height, &height);
66 /* Check x position */
67 if (width > displayedwidth)
69 neglimit = displayedwidth - width;
70 poslimit = 0;
72 else
74 neglimit = 0;
75 poslimit = displayedwidth - width;
78 if (*(newxoffset) > poslimit)
79 *(newxoffset) = poslimit;
80 if (*(newxoffset) < neglimit)
81 *(newxoffset) = neglimit;
83 /* Check y position */
84 if (height > displayedheight)
85 neglimit = displayedheight - height; /* Limit for scroll */
86 else
87 neglimit = 0;
88 poslimit = displayedheight - 15; /* Limit for drag */
90 if (*(newyoffset) > poslimit)
91 *(newyoffset) = poslimit;
92 if (*(newyoffset) < neglimit)
93 *(newyoffset) = neglimit;
96 static VOID HIDDCompositingRecalculateVisibleRects(struct HIDDCompositingData * compdata)
98 ULONG lastscreenvisibleline = compdata->screenrect.MaxY;
99 struct StackBitMapNode * n = NULL;
101 DRECALC(bug("[Compositing] Screen rect (%d, %d) - (%d, %d)\n", _RECT(compdata->screenrect)));
104 * This function assumes bitmapstack is in correct Z order:
105 * from topmost to bottom most
107 ForeachNode(&compdata->bitmapstack, n)
109 /* Get bitmap bounding box in screen coordinates */
110 struct Rectangle tmprect;
112 tmprect.MinX = n->leftedge;
113 tmprect.MaxX = n->leftedge + OOP_GET(n->bm, aHidd_BitMap_Width) - 1;
114 tmprect.MinY = n->topedge;
115 tmprect.MaxY = n->topedge + OOP_GET(n->bm, aHidd_BitMap_Height) - 1;
117 /* If bitmap's visible portion is smaller, apply this */
118 if (lastscreenvisibleline < tmprect.MaxY)
119 tmprect.MaxY = lastscreenvisibleline;
121 /* Intersect the box with screen rectangle to make sure values are within screen limit */
122 if (AndRectRect(&tmprect, &compdata->screenrect, &n->screenvisiblerect))
124 lastscreenvisibleline = n->screenvisiblerect.MinY - 1;
125 n->isscreenvisible = TRUE;
127 else
128 n->isscreenvisible = FALSE;
130 DRECALC(bug("[Compositing] Bitmap 0x%x, top %d, visible %d, (%d, %d) - (%d, %d)\n",
131 n->bm, n->topedge, n->isscreenvisible, _RECT(n->screenvisiblerect)));
135 static HIDDT_ModeID FindBestHiddMode(struct HIDDCompositingData *compdata, ULONG width, ULONG height, ULONG depth, ULONG *res_depth)
137 HIDDT_ModeID mode = vHidd_ModeID_Invalid;
138 OOP_Object *sync, *pf;
139 IPTR w, h, d;
140 ULONG dw, dh, delta;
141 ULONG found_delta = -1;
142 ULONG found_width = 0;
143 ULONG found_height = 0;
144 ULONG found_depth = 0;
145 HIDDT_ModeID found_mode = vHidd_ModeID_Invalid;
147 DMODE(bug("[FindBestHiddMode] Looking best maching mode for %u x %u x %u\n", width, height, depth));
149 while ((mode = HIDD_Gfx_NextModeID(compdata->gfx, mode, &sync, &pf)) != vHidd_ModeID_Invalid)
151 BOOL match;
153 DMODE(bug("[FindBestHiddMode] Checking mode 0x%08X... ", mode));
154 if (OOP_GET(pf, aHidd_PixFmt_ColorModel) != vHidd_ColorModel_TrueColor)
156 DMODE(bug("Skipped (not truecolor)\n"));
157 continue;
160 OOP_GetAttr(sync, aHidd_Sync_HDisp, &w);
161 OOP_GetAttr(sync, aHidd_Sync_VDisp, &h);
162 OOP_GetAttr(pf, aHidd_PixFmt_Depth, &d);
164 dw = w > width ? w - width : w < width ? width - w : 1;
165 dh = h > height ? h - height : h < height ? height - h : 1;
166 delta = dw * dh;
168 match = FALSE;
169 if (delta < found_delta)
171 /* If mode resolution is closer to the needed one, we've got a better match */
172 found_delta = delta;
173 found_width = w;
174 found_height = h;
176 match = TRUE;
178 else if (delta == found_delta)
180 /* If resolution is the same as that of current candidate mode, we can look at depth. */
181 if (found_depth > depth)
184 * Candidate mode if deeper than requested. We can supersede it with another mode
185 * of smaller depth, but which still matches our request.
187 if ((d < found_depth) && (d >= depth))
188 match = TRUE;
190 else if (found_depth < depth)
193 * We want better depth than current candidate.
194 * In this case anything deeper will do.
196 if (d > found_depth)
197 match = TRUE;
201 if (match)
204 * Mode with the same delta, but larger depth, may supersede
205 * previous mode, if we prefer deeper ones.
207 DMODE(bug("Selected (%ld x %ld x %ld, delta = %u)", w, h, d, delta));
208 found_depth = d;
209 found_mode = mode;
211 DMODE(bug("\n"));
214 /* Store mode information */
215 compdata->screenrect.MinX = 0;
216 compdata->screenrect.MinY = 0;
217 compdata->screenrect.MaxX = found_width - 1;
218 compdata->screenrect.MaxY = found_height - 1;
219 *res_depth = found_depth;
221 return found_mode;
224 static void UpdateDisplayMode(struct HIDDCompositingData *compdata)
226 struct StackBitMapNode *n;
227 IPTR modeid, width, height, depth;
228 OOP_Object *sync, *pf;
229 UBYTE comp_depth = 16;
230 ULONG found_depth;
233 * Examine all bitmaps in the stack to figure out the needed depth.
234 * We need a maximum depth of all depths in order to keep correct colors.
235 * But not less than 16 bits, because we can't compose on a LUT screen.
237 * If a LUT bitmap is present in the stack (depth < 9), we request truecolor
238 * screen for better color presentation.
240 * We examine bitmaps in reverse order, in this case 'sync' will hold
241 * information about the top bitmap when we exit the loop.
242 * Size of our composited mode needs to be as close as possible to that one.
244 for (n = (struct StackBitMapNode *)compdata->bitmapstack.mlh_TailPred;
245 n->n.mln_Pred; n = (struct StackBitMapNode *)n->n.mln_Pred)
247 OOP_GetAttr(n->bm, aHidd_BitMap_ModeID, &modeid);
248 HIDD_Gfx_GetMode(compdata->gfx, modeid, &sync, &pf);
250 if (OOP_GET(pf, aHidd_PixFmt_ColorModel) == vHidd_ColorModel_TrueColor)
252 OOP_GetAttr(pf, aHidd_PixFmt_Depth, &depth);
253 if (depth > comp_depth)
254 comp_depth = depth;
256 else
259 * If we have a LUT bitmap on stack, we request 24-bit screen
260 * for better color transfer.
262 comp_depth = 24;
266 /* Get the needed size */
267 OOP_GetAttr(sync, aHidd_Sync_HDisp, &width);
268 OOP_GetAttr(sync, aHidd_Sync_VDisp, &height);
270 DSTACK(bug("[UpdateDisplayMode] Requested mode %ld x %ld x %d\n", width, height, comp_depth));
272 modeid = FindBestHiddMode(compdata, width, height, depth, &found_depth);
273 DSTACK(bug("[UpdateDisplayMode] Composition mode 0x%08X, current 0x%08X\n", modeid, compdata->screenmodeid));
275 if (modeid != compdata->screenmodeid)
277 /* The mode is different. Need to prepare information needed for compositing */
278 struct TagItem gctags[] =
280 { aHidd_GC_Foreground, 0x99999999 },
281 { TAG_DONE , 0 }
284 /* Signal mode change */
285 compdata->screenmodeid = modeid;
286 compdata->modeschanged = TRUE;
288 /* Get gray foregound */
289 if (found_depth < 24)
290 gctags[0].ti_Data = 0x9492;
292 OOP_SetAttrs(compdata->gc, gctags);
296 static inline void HIDDCompositingRedrawBitmap(struct HIDDCompositingData *compdata, struct StackBitMapNode *n, struct Rectangle *rect)
298 /* The given rectangle is already in screen coordinate system here */
299 ULONG blitwidth = rect->MaxX - rect->MinX + 1;
300 ULONG blitheight = rect->MaxY - rect->MinY + 1;
302 DREDRAWBM(bug("[Compositing] Redraw bitmap 0x%p, rect (%d, %d) - (%d, %d)\n", n->bm,
303 rect->MinX, rect->MinY, rect->MaxX, rect->MaxY));
304 DREDRAWBM(bug("[Compositing] Blitting %d x %d from (%d, %d)\n", blitwidth, blitheight,
305 rect->MinX - n->leftedge, rect->MinY - n->topedge));
307 HIDD_Gfx_CopyBox(compdata->gfx, n->bm,
308 /* Transform to source bitmap coord system */
309 rect->MinX - n->leftedge, rect->MinY - n->topedge,
310 compdata->compositedbitmap,
311 rect->MinX, rect->MinY, blitwidth, blitheight,
312 compdata->gc);
315 static inline void ClearRect(struct HIDDCompositingData *compdata, ULONG MinX, ULONG MinY, ULONG MaxX, ULONG MaxY)
317 DREDRAWSCR(bug("[Compositing] Clearing area (%d, %d) - (%d, %d)\n",
318 MinX, MinY, MaxX, MaxY));
320 HIDD_BM_FillRect(compdata->compositedbitmap, compdata->gc,
321 MinX, MinY, MaxX, MaxY);
324 static VOID HIDDCompositingRedrawVisibleScreen(struct HIDDCompositingData * compdata)
326 struct StackBitMapNode *n;
327 ULONG lastscreenvisibleline = 0;
329 DREDRAWSCR(bug("[Compositing] Redrawing screen\n"));
331 /* Calculations are performed regardless of whether compositedbitmap is
332 being shown. Gfx operations are only performed if compositedbitmap is
333 being shown */
335 /* Recalculate visible rects per screen */
336 HIDDCompositingRecalculateVisibleRects(compdata);
339 * Refresh all bitmaps on stack.
340 * For simplicity, we traverse the list in reverse order (from bottom to top).
341 * This way we can easy figure out spaces between bitmaps (every time we know
342 * final line of previous bitmap or 0 if there was no one).
344 for (n = (struct StackBitMapNode *)compdata->bitmapstack.mlh_TailPred;
345 n->n.mln_Pred; n = (struct StackBitMapNode *)n->n.mln_Pred)
347 DREDRAWSCR(bug("[Compositing] Bitmap 0x%p, visible %d, rect (%d, %d) - (%d, %d)\n",
348 n->bm, n->isscreenvisible, _RECT(n->screenvisiblerect)));
350 if (n->isscreenvisible)
352 /* Redraw the whole visible portion */
353 HIDDCompositingRedrawBitmap(compdata, n, &n->screenvisiblerect);
355 /* Clean up areas revealed by drag */
356 if (n->screenvisiblerect.MinX > 0)
358 /* To the left of bitmap */
359 ClearRect(compdata,
360 0, n->screenvisiblerect.MinY,
361 n->screenvisiblerect.MinX, n->screenvisiblerect.MaxY);
364 if (n->screenvisiblerect.MaxX < compdata->screenrect.MaxX)
366 /* To the right of bitmap */
367 ClearRect(compdata,
368 n->screenvisiblerect.MaxX + 1, n->screenvisiblerect.MinY,
369 compdata->screenrect.MaxX, n->screenvisiblerect.MaxY);
372 if (n->screenvisiblerect.MinY > lastscreenvisibleline)
374 /* Between this and previous bitmap */
375 ClearRect(compdata,
376 0, lastscreenvisibleline,
377 compdata->screenrect.MaxX, n->screenvisiblerect.MinY - 1);
380 /* Update the whole display rectangle (bitmap + space around it) in one operation */
381 HIDD_BM_UpdateRect(compdata->compositedbitmap,
382 0, lastscreenvisibleline,
383 compdata->screenrect.MaxX + 1, n->screenvisiblerect.MaxY - lastscreenvisibleline + 1);
385 lastscreenvisibleline = n->screenvisiblerect.MaxY + 1;
392 There are several cases that needs to be handled in this code. They are documented
393 below. Please read it before making changes.
394 etb = existing topbitmap
395 ntb = new top bitmap
396 sb = screen bitmap
397 cb = composited bitmap
398 fs = covers full screen
399 nfs = not covers full screen
400 mA = mode "A"
401 mB = mode "B"
402 disp() = dispose
403 new() = new
405 The resulting mode is always that of screen bitmap as set in "effect" column.
406 The composited bitmap always matches the resulting screen mode or is NULL.
408 | exiting screen situation | change | effect |
409 | USE CASE: SWITCHING BETWEEN FULL SCREEN SCREENS - SAME MODE |
410 | etb->fs, mA, sb==etb, cb==NULL | ntb->fs, mA | sb==ntb, cb==NULL |
411 | etb->fs, mA, sb==etb, cb!=NULL | ntb->fs, mA | sb==ntb, cb!=NULL |
412 | USE CASE: SWITCHING BETWEEN FULL SCREEN AND NOT FULL SCREEN SCREENS - SAME MODE |
413 | etb->fs, mA, sb==etb, cb==NULL | ntb->nfs, mA | new(cb), sb==cb, cb!=NULL |
414 | etb->fs, mA, sb==etb, cb!=NULL | ntb->nfs, mA | sb==cb, cb!=NULL |
415 | USE CASE: SWITCHING BETWEEN NOT FULL SCREEN AND FULL SCREEN SCREENS - SAME MODE |
416 | etb->nfs, mA, sb==cb, cb==NULL | NOT POSSIBLE |
417 | etb->nfs, mA, sb==cb, cb!=NULL | ntb->fs, mA | sb==ntb, cb!=NULL |
418 | USE CASE: SWITCHING BETWEEN NOT FULL SCREEN AND NOT FULL SCREEN SCREENS - SAME MODE |
419 | etb->nfs, mA, sb==cb, cb==NULL | NOT POSSIBLE |
420 | etb->nfs, mA, sb==cb, cb!=NULL | ntb->nfs, mA | sb==cb, cb!=NULL |
423 | USE CASE: SWITCHING BETWEEN FULL SCREEN SCREENS - DIFFERENT MODES |
424 | etb->fs, mA, sb==etb, cb==NULL | ntb->fs, mB | sb==ntb, cb==NULL |
425 | etb->fs, mA, sb==etb, cb!=NULL | ntb->fs, mB | disp(cb), sb==ntb, cb==NULL |
426 | USE CASE: SWITCHING BETWEEN FULL SCREEN AND NOT FULL SCREEN SCREENS - DIFFERENT MODES |
427 | etb->fs, mA, sb==etb, cb==NULL | ntb->nfs, mB | new(cb), sb==cb, cb!=NULL |
428 | etb->fs, mA, sb==etb, cb!=NULL | ntb->nfs, mB | disp(cb), new(cb), sb==cb, cb!=NULL |
429 | USE CASE: SWITCHING BETWEEN NOT FULL SCREEN AND FULL SCREEN SCREENS - DIFFERENT MODES |
430 | etb->nfs, mA, sb==cb, cb==NULL | NOT POSSIBLE |
431 | etb->nfs, mA, sb==cb, cb!=NULL | ntb->fs, mB | disp(cb), sb==ntb, cb==NULL |
432 | USE CASE: SWITCHING BETWEEN NOT FULL SCREEN AND NOT FULL SCREEN SCREENS - DIFFERENT MODES |
433 | etb->nfs, mA, sb==cb, cb==NULL | NOT POSSIBLE |
434 | etb->nfs, mA, sb==cb, cb!=NULL | ntb->nfs, mB | disp(cb), new(cb), sb==cb, cb!=NULL |
437 | USE CASE: DRAGGING SCREEN DOWN |
438 | etb->fs, mA, sb==etb, cb==NULL | ntb->nfs, mA | new(cb), sb==cb |
439 | etb->fs, mA, sb==etb, cb!=NULL | ntb->nfs, mA | sb==cb |
440 | USE CASE: DRAGGING SCREEN UP |
441 | etb->nfs, mA, sb==cb, cb!=NULL | ntb->fs, mA | sb==etb |
442 | etb->nfs, mA, sb==cb, cb==NULL | NOT POSSIBLE |
444 Resulting rules (order matters):
446 (a) if ((cb!=NULL) && (etb->mode!=ntb->mode)) {dispose(cb), cb=NULL}
447 (b) if ((ntb->nfs) && (cb==NULL)) new(cb)
448 (c) if (ntb->nfs) sb=cb
449 (d) if (ntb->fs) sb=ntb
451 Additional rule:
452 (e) if (oldsb!=sb) modeswitch(sb)
454 02.09.2011: we don't remember sb any more because we don't handle it in any way. Instead
455 we either have or don't have compositedbitmap. If we have it, composition
456 is on (sb = cb). If we don't have it, composition is off (sb = ntb).
458 static BOOL HIDDCompositingToggleCompositing(struct HIDDCompositingData *compdata, BOOL newtop)
461 * If the topbitmap covers the complete screen, show it instead of
462 * compositedbitmap. Remember that screen bitmap -> composited bitmap
463 * mirroring has a negative impact on performance.
465 OOP_Object *oldcompositedbitmap = compdata->compositedbitmap;
466 OOP_Object *newscreenbitmap = NULL;
467 LONG topedge = ((struct StackBitMapNode *)compdata->bitmapstack.mlh_Head)->topedge;
468 BOOL ok = TRUE;
470 /* (a) If mode change is needed, enforce opening a new screen */
471 if (compdata->modeschanged)
473 D(bug("[Compositing] Mode changed\n"));
474 compdata->compositedbitmap = NULL;
478 * This condition is enough as compositing allows only dragging screen down
479 * and not up/left/right at the moment.
481 if (topedge > 0)
483 /* (b) */
484 if (compdata->compositedbitmap == NULL)
487 * compositedbitmap == NULL means we were in passthrough mode before.
488 * Set up screen for composition.
490 if (compdata->fb)
493 * If our display driver uses a framebuffer, we can reuse it.
494 * Copy its original contents back into the bitmap which it replaced,
495 * then change framebuffer's video mode.
496 * Framebuffer is the only bitmap which can change its ModeID on the fly.
498 D(bug("[Compositing] Using framebuffer bitmap 0x%p\n", compdata->fb));
500 /* Do this comparison in order not to show the framebuffer twice */
501 if (oldcompositedbitmap != compdata->fb)
504 * 1. It's legal to show the framebuffer itself. This causes copying
505 * back old bitmap contents and detaching from it.
506 * 2. The result of this will always match compdata->fb.
507 * 3. Internally this is a simple blit operation, it can't fail.
509 compdata->screenbitmap = HIDD_Gfx_Show(compdata->gfx, compdata->fb, fHidd_Gfx_Show_CopyBack);
512 /* Switch display mode on the framebuffer. */
513 OOP_SetAttrsTags(compdata->fb, aHidd_BitMap_ModeID, compdata->screenmodeid, TAG_DONE);
514 /* We are now compositing on the framebuffer */
515 compdata->compositedbitmap = compdata->fb;
517 else
520 * There's no framebuffer.
521 * Create a new bitmap that will be used for compositing.
523 struct TagItem bmtags[5];
525 bmtags[0].ti_Tag = aHidd_BitMap_Width; bmtags[0].ti_Data = compdata->screenrect.MaxX + 1;
526 bmtags[1].ti_Tag = aHidd_BitMap_Height; bmtags[1].ti_Data = compdata->screenrect.MaxY + 1;
527 bmtags[2].ti_Tag = aHidd_BitMap_Displayable; bmtags[2].ti_Data = TRUE;
528 bmtags[3].ti_Tag = aHidd_BitMap_ModeID; bmtags[3].ti_Data = compdata->screenmodeid;
529 bmtags[4].ti_Tag = TAG_DONE; bmtags[4].ti_Data = TAG_DONE;
531 compdata->compositedbitmap = HIDD_Gfx_NewBitMap(compdata->gfx, bmtags);
532 D(bug("[Compositing] Created working bitmap 0x%p\n", compdata->compositedbitmap));
534 /* Mode changed, this bitmap will be shown later */
535 newscreenbitmap = compdata->compositedbitmap;
537 /* NewBitMap can fail, handle this */
538 if (!newscreenbitmap)
539 ok = FALSE;
542 else /* if (compdata->compositedbitmap == NULL) */
545 * We are already in compositing mode and will stay in it.
546 * Do not destroy our working bitmap.
548 oldcompositedbitmap = NULL;
552 * (c) Here composition is turned on (compositedbitmap != NULL).
553 * Redraw bitmap stack - compensate possible changes
555 if (ok)
556 HIDDCompositingRedrawVisibleScreen(compdata);
558 else if (oldcompositedbitmap || newtop)
561 * (d) Set passthrough mode and display the frontmost bitmap.
562 * This is also triggered by 'newtop' parameter, which tells us
563 * that frontmost bitmap has been changed, and we need to display a new one.
564 * Old compositedbitmap has been remembered in the beginning. If it's not
565 * NULL, it will be destroyed in the end.
567 newscreenbitmap = compdata->topbitmap;
568 compdata->compositedbitmap = NULL;
571 DTOGGLE(bug("[Compositing] Toggle te %d, oldcomp 0x%P, top 0x%P, comp 0x%P, newscreen 0x%P\n",
572 topedge, oldcompositedbitmap, compdata->topbitmap, compdata->compositedbitmap, newscreenbitmap));
575 * (e) If the screenbitmap changed, show the new screenbitmap.
576 * We do it after refreshing, for better visual appearance.
578 if (newscreenbitmap)
580 IPTR w, h;
582 compdata->screenbitmap = HIDD_Gfx_Show(compdata->gfx, newscreenbitmap, fHidd_Gfx_Show_CopyBack);
583 D(bug("[Compositing] Displayed bitmap 0x%p, Show returned 0x%p\n", newscreenbitmap, compdata->screenbitmap));
585 /* After Show we need Update for mirroring drivers */
586 if (compdata->screenbitmap)
588 OOP_GetAttr(compdata->screenbitmap, aHidd_BitMap_Width, &w);
589 OOP_GetAttr(compdata->screenbitmap, aHidd_BitMap_Height, &h);
590 HIDD_BM_UpdateRect(compdata->screenbitmap, 0, 0, w, h);
595 * (a) - disposing of oldcompositingbitmap needs to happen after mode switch
596 * since it could have been the current screenbitmap
598 if (oldcompositedbitmap && (oldcompositedbitmap != compdata->fb))
600 D(bug("[Compositing] Disposing old working bitmap 0x%p\n", oldcompositedbitmap));
601 HIDD_Gfx_DisposeBitMap(compdata->gfx, oldcompositedbitmap);
604 /* Handled */
605 compdata->modeschanged = FALSE;
607 return ok;
610 static VOID HIDDCompositingPurgeBitMapStack(struct HIDDCompositingData * compdata)
612 struct StackBitMapNode * curr, * next;
614 ForeachNodeSafe(&compdata->bitmapstack, curr, next)
616 FreeMem(curr, sizeof(struct StackBitMapNode));
619 NEWLIST(&compdata->bitmapstack);
622 static void HIDDCompositingShowSingle(struct HIDDCompositingData *compdata, OOP_Object *bm)
624 /* Show the single top bitmap */
625 compdata->topbitmap = bm;
626 compdata->screenbitmap = HIDD_Gfx_Show(compdata->gfx, bm, fHidd_Gfx_Show_CopyBack);
628 /* Dispose working bitmap (if any) */
629 if (compdata->compositedbitmap)
631 /* Be careful with the framebuffer */
632 if (compdata->compositedbitmap != compdata->fb)
633 HIDD_Gfx_DisposeBitMap(compdata->gfx, compdata->compositedbitmap);
635 /* This will deactivate us */
636 compdata->compositedbitmap = NULL;
640 /* Emergency error recovery function */
641 static void HIDDCompositingReset(struct HIDDCompositingData *compdata)
643 /* Purge bitmap stack */
644 HIDDCompositingPurgeBitMapStack(compdata);
647 * Reset our internal state so that next BitMapStackChanged
648 * causes complete reinitialization.
650 compdata->screenmodeid = vHidd_ModeID_Invalid;
651 compdata->screenbitmap = NULL;
654 /* PUBLIC METHODS */
655 OOP_Object *METHOD(Compositing, Root, New)
657 o = (OOP_Object *)OOP_DoSuperMethod(cl, o, (OOP_Msg) msg);
659 if (o)
661 OOP_MethodID disposemid;
662 struct HIDDCompositingData *compdata = OOP_INST_DATA(cl, o);
664 NEWLIST(&compdata->bitmapstack);
665 compdata->screenmodeid = vHidd_ModeID_Invalid;
666 InitSemaphore(&compdata->semaphore);
668 compdata->gfx = (OOP_Object *)GetTagData(aHidd_Compositing_GfxHidd, 0, msg->attrList);
669 compdata->fb = (OOP_Object *)GetTagData(aHidd_Compositing_FrameBuffer, 0, msg->attrList);
671 /* GfxHidd is mandatory */
672 if (compdata->gfx != NULL)
674 /* Create GC object that will be used for drawing operations */
675 compdata->gc = HIDD_Gfx_NewGC(compdata->gfx, NULL);
677 if (compdata->gfx)
678 return o;
681 /* Creation failed */
683 disposemid = OOP_GetMethodID(IID_Root, moRoot_Dispose);
684 OOP_CoerceMethod(cl, o, &disposemid);
687 return NULL;
690 VOID METHOD(Compositing, Root, Get)
692 if (msg->attrID == aHidd_Compositing_Capabilities)
694 *msg->storage = COMPF_ABOVE;
695 return;
698 OOP_DoSuperMethod(cl, o, &msg->mID);
701 OOP_Object *METHOD(Compositing, Hidd_Compositing, BitMapStackChanged)
703 struct HIDD_ViewPortData *vpdata;
704 struct HIDDCompositingData *compdata = OOP_INST_DATA(cl, o);
705 struct StackBitMapNode *n;
706 BOOL newtop = FALSE;
707 BOOL ok = TRUE;
709 DSTACK(bug("[BitMapStackChanged] Top bitmap: 0x%lx\n", msg->data->Bitmap));
711 LOCK_COMPOSITING_WRITE
713 /* Free all items which are already on the list */
714 HIDDCompositingPurgeBitMapStack(compdata);
716 if (!msg->data)
718 UNLOCK_COMPOSITING
720 /* Blank screen */
721 HIDDCompositingShowSingle(compdata, NULL);
723 /* We know we are inactive after this */
724 *msg->active = FALSE;
725 /* This can return NULL, it's okay */
726 return compdata->screenbitmap;
729 /* Copy bitmaps pointers to our stack */
730 for (vpdata = msg->data; vpdata; vpdata = vpdata->Next)
732 n = AllocMem(sizeof(struct StackBitMapNode), MEMF_ANY | MEMF_CLEAR);
733 if (!n)
736 * Error happened.
737 * We need to reset own state and return NULL. graphics.library
738 * falls back to no composition in this case.
740 DSTACK(bug("[BitMapStackChanged] Error allocating StackBitMapNode!!!\n"));
742 ok = FALSE;
743 break;
746 DSTACK(bug("[BitMapStackChanged] ViewPort 0x%p, offset (%d, %d)\n", vpdata->vpe->ViewPort, vpdata->vpe->ViewPort->DxOffset, vpdata->vpe->ViewPort->DyOffset));
748 n->bm = vpdata->Bitmap;
749 n->isscreenvisible = FALSE;
750 n->leftedge = vpdata->vpe->ViewPort->DxOffset;
751 n->topedge = vpdata->vpe->ViewPort->DyOffset;
753 AddTail((struct List *)&compdata->bitmapstack, (struct Node *)n);
756 /* Switch mode if needed */
757 UpdateDisplayMode(compdata);
759 if (msg->data->Bitmap != compdata->topbitmap)
761 /* Set the new pointer to top bitmap */
762 compdata->topbitmap = msg->data->Bitmap;
763 newtop = TRUE;
766 if (ok)
769 * Validate bitmap offsets - they might not match the compositing rules taking
770 * new displayedwidth/displayedheight values
772 ForeachNode(&compdata->bitmapstack, n)
774 HIDDCompositingValidateBitMapPositionChange(n->bm, &n->leftedge, &n->topedge,
775 compdata->screenrect.MaxX + 1, compdata->screenrect.MaxY + 1);
776 DSTACK(bug("[BitMapStackChanged] Bitmap 0x%p, display size %d x %d, validated position (%ld, %ld)\n",
777 n->bm, compdata->screenrect.MaxX + 1, compdata->screenrect.MaxY + 1,
778 n->leftedge, n->topedge));
781 /* Toogle compositing based on screen positions */
782 ok = HIDDCompositingToggleCompositing(compdata, newtop);
785 /* Handle error */
786 if (!ok)
788 HIDDCompositingReset(compdata);
789 HIDDCompositingShowSingle(compdata, msg->data->Bitmap);
792 UNLOCK_COMPOSITING
794 DSTACK(bug("[BitMapStackChanged] Done, composited bitmap 0x%p\n", compdata->compositedbitmap));
796 /* Tell if the composition is active */
797 *msg->active = compdata->compositedbitmap ? TRUE : FALSE;
798 /* Return actually displayed bitmap */
799 return compdata->screenbitmap;
802 VOID METHOD(Compositing, Hidd_Compositing, BitMapRectChanged)
804 struct HIDDCompositingData * compdata = OOP_INST_DATA(cl, o);
806 if (compdata->compositedbitmap)
808 /* Composition is active, handle redraw if the bitmap is on screen */
809 struct StackBitMapNode *n;
811 DUPDATE(bug("[BitMapRectChanged] Bitmap 0x%p\n", msg->bm));
813 LOCK_COMPOSITING_READ
815 n = HIDDCompositingIsBitMapOnStack(compdata, msg->bm);
816 if (n && n->isscreenvisible)
818 /* Rectangle in bitmap coord system */
819 struct Rectangle srcrect, dstandvisrect;
821 srcrect.MinX = msg->x;
822 srcrect.MinY = msg->y;
823 srcrect.MaxX = msg->x + msg->width - 1;
824 srcrect.MaxY = msg->y + msg->height - 1;
825 DUPDATE(bug("[BitMapRectChanged] Bitmap rect (%d, %d) - (%d, %d)\n", _RECT(srcrect)));
827 /* Transform the rectangle to screen coord system */
828 srcrect.MinX += n->leftedge;
829 srcrect.MaxX += n->leftedge;
830 srcrect.MinY += n->topedge;
831 srcrect.MaxY += n->topedge;
832 DUPDATE(bug("[BitMapRectChanged] Screen-relative rect (%d, %d) - (%d, %d)\n", _RECT(srcrect)));
834 /* Find intersection of visible screen rect and bitmap rect */
835 if (AndRectRect(&srcrect, &n->screenvisiblerect, &dstandvisrect))
837 /* Intersection is valid. Blit. */
838 DUPDATE(bug("[BitMapRectChanged] Clipped rect (%d, %d) - (%d, %d)\n", _RECT(dstandvisrect)));
840 HIDDCompositingRedrawBitmap(compdata, n, &dstandvisrect);
842 HIDD_BM_UpdateRect(compdata->compositedbitmap,
843 dstandvisrect.MinX, dstandvisrect.MinY,
844 dstandvisrect.MaxX - dstandvisrect.MinX + 1,
845 dstandvisrect.MaxY - dstandvisrect.MinY + 1);
849 UNLOCK_COMPOSITING
851 DUPDATE(bug("[BitMapRectChanged] Done\n"));
853 else
856 * In order to speed things up, we handle passthrough ourselves here.
857 * It's not difficult.
859 HIDD_BM_UpdateRect(msg->bm, msg->x, msg->y, msg->width, msg->height);
863 IPTR METHOD(Compositing, Hidd_Compositing, BitMapPositionChange)
865 struct HIDDCompositingData *compdata = OOP_INST_DATA(cl, o);
866 struct StackBitMapNode *n;
867 IPTR disp_width, disp_height;
869 LOCK_COMPOSITING_READ
871 n = HIDDCompositingIsBitMapOnStack(compdata, msg->bm);
872 if (n)
874 /* The bitmap is on display. Validate against screen size */
875 disp_width = compdata->screenrect.MaxX + 1;
876 disp_height = compdata->screenrect.MaxY + 1;
878 else
880 /* The bitmap is not displayed yet. Validate against its own ModeID size. */
881 HIDDT_ModeID modeid = vHidd_ModeID_Invalid;
882 OOP_Object *sync, *pf;
884 OOP_GetAttr(msg->bm, aHidd_BitMap_ModeID, &modeid);
886 if (modeid == vHidd_ModeID_Invalid)
889 * Nondisplayable bitmaps don't scroll.
890 * In fact they simply can't get in here because MakeVPort() performs the validation.
891 * But who knows what bug can slip into someone's software...
893 UNLOCK_COMPOSITING
894 return FALSE;
897 HIDD_Gfx_GetMode(compdata->gfx, modeid, &sync, &pf);
898 OOP_GetAttr(sync, aHidd_Sync_HDisp, &disp_width);
899 OOP_GetAttr(sync, aHidd_Sync_VDisp, &disp_height);
902 DMOVE(bug("[BitMapPositionChange] Validating bitmap 0x%p, position (%ld, %ld), limits %ld x %ld\n",
903 msg->bm, *msg->newxoffset, *msg->newyoffset, disp_width, disp_height));
905 HIDDCompositingValidateBitMapPositionChange(msg->bm, msg->newxoffset, msg->newyoffset,
906 disp_width, disp_height);
908 DMOVE(bug("[BitMapPositionChange] Validated position (%ld, %ld)\n", *msg->newxoffset, *msg->newyoffset));
910 if (n && ((*msg->newxoffset != n->leftedge) || (*msg->newyoffset != n->topedge)))
912 DMOVE(bug("[BitMapPositionChange] Old position (%ld, %ld)\n", n->leftedge, n->topedge));
914 /* Reflect the change if it happened */
915 n->leftedge = *msg->newxoffset;
916 n->topedge = *msg->newyoffset;
918 if (compdata->topbitmap == msg->bm)
921 * If this is the frontmost bitmap, we may want to toggle compositing,
922 * if it starts/stops covering the whole screen at one point.
923 * We don't need to call HIDDCompositingRedrawVisibleScreen() here because
924 * HIDDCompositingToggleCompositing() does this itself, for improved
925 * visual appearance.
927 HIDDCompositingToggleCompositing(compdata, FALSE);
929 else
930 HIDDCompositingRedrawVisibleScreen(compdata);
933 UNLOCK_COMPOSITING
935 /* Return active state */
936 return compdata->compositedbitmap ? TRUE : FALSE;
939 #define NUM_Compositing_Root_METHODS 2
941 static const struct OOP_MethodDescr Compositing_Root_descr[] =
943 {(OOP_MethodFunc)Compositing__Root__New, moRoot_New},
944 {(OOP_MethodFunc)Compositing__Root__Get, moRoot_Get},
945 {NULL, 0}
948 #define NUM_Compositing_Hidd_Compositing_METHODS 3
950 static const struct OOP_MethodDescr Compositing_Hidd_Compositing_descr[] =
952 {(OOP_MethodFunc)Compositing__Hidd_Compositing__BitMapStackChanged, moHidd_Compositing_BitMapStackChanged},
953 {(OOP_MethodFunc)Compositing__Hidd_Compositing__BitMapRectChanged, moHidd_Compositing_BitMapRectChanged},
954 {(OOP_MethodFunc)Compositing__Hidd_Compositing__BitMapPositionChange, moHidd_Compositing_BitMapPositionChange},
955 {NULL, 0}
958 const struct OOP_InterfaceDescr Compositing_ifdescr[] =
960 {Compositing_Root_descr, IID_Root, NUM_Compositing_Root_METHODS},
961 {Compositing_Hidd_Compositing_descr, IID_Hidd_Compositing, NUM_Compositing_Hidd_Compositing_METHODS},
962 {NULL, NULL}