2 Copyright © 2010-2012, The AROS Development Team. All rights reserved.
3 $Id: compositingclass.c 38905 2011-05-29 06:54:59Z deadwood $
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
))
45 static struct StackBitMapNode
* HIDDCompositingIsBitMapOnStack(struct HIDDCompositingData
* compdata
, OOP_Object
* bm
)
47 struct StackBitMapNode
* n
= NULL
;
49 ForeachNode(&compdata
->bitmapstack
, n
)
58 static VOID
HIDDCompositingValidateBitMapPositionChange(OOP_Object
* bm
, SIPTR
*newxoffset
, SIPTR
*newyoffset
, LONG displayedwidth
, LONG displayedheight
)
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
;
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 */
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
;
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
;
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
)
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"));
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;
169 if (delta
< found_delta
)
171 /* If mode resolution is closer to the needed one, we've got a better match */
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
))
190 else if (found_depth
< depth
)
193 * We want better depth than current candidate.
194 * In this case anything deeper will do.
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
));
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
;
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;
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
)
259 * If we have a LUT bitmap on stack, we request 24-bit screen
260 * for better color transfer.
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 },
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
,
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
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 */
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 */
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 */
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
397 cb = composited bitmap
398 fs = covers full screen
399 nfs = not covers full screen
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
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
;
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.
484 if (compdata
->compositedbitmap
== NULL
)
487 * compositedbitmap == NULL means we were in passthrough mode before.
488 * Set up screen for composition.
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
;
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
)
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
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.
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
);
605 compdata
->modeschanged
= FALSE
;
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
;
655 OOP_Object
*METHOD(Compositing
, Root
, New
)
657 o
= (OOP_Object
*)OOP_DoSuperMethod(cl
, o
, (OOP_Msg
) msg
);
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
);
681 /* Creation failed */
683 disposemid
= OOP_GetMethodID(IID_Root
, moRoot_Dispose
);
684 OOP_CoerceMethod(cl
, o
, &disposemid
);
690 VOID
METHOD(Compositing
, Root
, Get
)
692 if (msg
->attrID
== aHidd_Compositing_Capabilities
)
694 *msg
->storage
= COMPF_ABOVE
;
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
;
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
);
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
);
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"));
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
;
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
);
788 HIDDCompositingReset(compdata
);
789 HIDDCompositingShowSingle(compdata
, msg
->data
->Bitmap
);
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);
851 DUPDATE(bug("[BitMapRectChanged] Done\n"));
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
);
874 /* The bitmap is on display. Validate against screen size */
875 disp_width
= compdata
->screenrect
.MaxX
+ 1;
876 disp_height
= compdata
->screenrect
.MaxY
+ 1;
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...
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
927 HIDDCompositingToggleCompositing(compdata
, FALSE
);
930 HIDDCompositingRedrawVisibleScreen(compdata
);
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
},
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
},
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
},