2 Copyright © 1995-2011, The AROS Development Team. All rights reserved.
5 Desc: Driver for using gfxhidd for gfx output
9 #include <proto/exec.h>
10 #include <proto/graphics.h>
11 #include <proto/layers.h>
12 #include <proto/arossupport.h>
13 #include <proto/utility.h>
14 #include <proto/oop.h>
16 #include <exec/memory.h>
17 #include <exec/semaphores.h>
18 #include <clib/macros.h>
20 #include <graphics/rastport.h>
21 #include <graphics/gfxbase.h>
22 #include <graphics/text.h>
23 #include <graphics/view.h>
24 #include <graphics/layers.h>
25 #include <graphics/clip.h>
26 #include <graphics/gfxmacros.h>
27 #include <graphics/regions.h>
28 #include <graphics/scale.h>
31 #include <utility/tagitem.h>
32 #include <aros/asmcall.h>
34 #include <intuition/intuition.h>
36 #include <hidd/graphics.h>
38 #include <cybergraphx/cybergraphics.h>
43 #include "graphics_intern.h"
44 #include "fakegfxhidd.h"
45 #include "intregions.h"
47 #include "gfxfuncsupport.h"
48 #include "fontsupport.h"
52 #include <aros/debug.h>
55 #define DEBUG_LOADVIEW(x)
57 /* Define this if you wish to enforce using software mouse sprite
58 even for drivers that support hardware one. Useful for debugging
60 #define FORCE_SOFTWARE_SPRITE */
64 struct TextFont etf_Font
;
68 /* InitDriverData() just allocates memory for the struct. To use e.g. */
69 /* AreaPtrns, UpdateAreaPtrn() has to allocate the memory for the */
70 /* Pattern itself (and free previously used memory!) */
72 static inline void AddDriverDataToList(struct gfx_driverdata
*dd
, struct GfxBase
* GfxBase
)
76 hash
= CalcHashIndex((IPTR
)dd
, DRIVERDATALIST_HASHSIZE
);
78 // ObtainSemaphore(&PrivGBase(GfxBase)->driverdatasem);
79 AddTail((struct List
*)&PrivGBase(GfxBase
)->driverdatalist
[hash
], (struct Node
*)&dd
->dd_Node
);
80 // ReleaseSemaphore(&PrivGBase(GfxBase)->driverdatasem);
84 static inline void RemoveDriverDataFromList(struct gfx_driverdata
*dd
, struct GfxBase
*GfxBase
)
86 // ObtainSemaphore(&PrivGBase(GfxBase)->driverdatasem);
87 Remove((struct Node
*)&dd
->dd_Node
);
88 // ReleaseSemaphore(&PrivGBase(GfxBase)->driverdatasem);
91 static inline BOOL
FindDriverData(struct gfx_driverdata
*dd
, struct RastPort
*rp
, struct GfxBase
*GfxBase
)
93 struct gfx_driverdata
*hn
= NULL
;
97 hash
= CalcHashIndex((IPTR
)dd
, DRIVERDATALIST_HASHSIZE
);
99 // ObtainSemaphore(&PrivGBase(GfxBase)->driverdatasem);
100 ForeachNode((struct List
*)&PrivGBase(GfxBase
)->driverdatalist
[hash
], hn
)
102 if ((hn
== dd
) && (hn
->dd_RastPort
== rp
))
108 // ReleaseSemaphore(&PrivGBase(GfxBase)->driverdatasem);
113 BOOL
ObtainDriverData(struct RastPort
*rp
, struct GfxBase
*GfxBase
)
115 struct gfx_driverdata
*dd
;
117 if (RP_BACKPOINTER(rp
) == rp
)
119 if (rp
->Flags
& RPF_SELF_CLEANUP
)
121 if (RP_DRIVERDATA(rp
)) return TRUE
;
126 /* We have detected a manually cloned rastport. Mark it as 'valid'
127 (backpointer to itself) but with NULL driverdata and non-self
129 RP_DRIVERDATA(rp
) = NULL
;
130 rp
->Flags
&= ~RPF_SELF_CLEANUP
;
131 RP_BACKPOINTER(rp
) = rp
;
134 ObtainSemaphore(&PrivGBase(GfxBase
)->driverdatasem
);
135 dd
= RP_DRIVERDATA(rp
);
138 if (!(rp
->Flags
& RPF_SELF_CLEANUP
) && FindDriverData(dd
, rp
, GfxBase
))
144 RP_DRIVERDATA(rp
) = NULL
;
151 dd
= AllocPooled(PrivGBase(GfxBase
)->driverdatapool
, sizeof(*dd
));
154 struct monitor_driverdata
*sdd
;
155 struct TagItem gc_tags
[] = {{ TAG_DONE
}};
158 sdd
= GET_BM_DRIVERDATA(rp
->BitMap
);
160 sdd
= (struct monitor_driverdata
*)CDD(GfxBase
);
162 dd
->dd_GC
= HIDD_Gfx_NewGC(sdd
->gfxhidd
, gc_tags
);
165 dd
->dd_RastPort
= rp
;
166 dd
->dd_LockCount
= 1;
168 RP_DRIVERDATA(rp
) = dd
;
169 rp
->Flags
|= RPF_DRIVER_INITED
;
171 if (!(rp
->Flags
& RPF_SELF_CLEANUP
)) AddDriverDataToList(dd
, GfxBase
);
173 if (rp
->BitMap
) SetABPenDrMd(rp
, (UBYTE
)rp
->FgPen
, (UBYTE
)rp
->BgPen
, rp
->DrawMode
);
177 FreePooled(PrivGBase(GfxBase
)->driverdatapool
, dd
, sizeof(*dd
));
185 ReleaseSemaphore(&PrivGBase(GfxBase
)->driverdatasem
);
187 return dd
? TRUE
: FALSE
;
190 void ReleaseDriverData(struct RastPort
*rp
, struct GfxBase
*GfxBase
)
192 struct gfx_driverdata
*dd
= GetDriverData(rp
);
194 if (!(rp
->Flags
& RPF_SELF_CLEANUP
))
196 /* FIXME: stegerg 23 jan 2004: needs semprotection, too! */
197 /* CHECKME: stegerg 23 feb 2005: really?? */
203 // if (!dd->dd_LockCount) KillDriverData(rp, GfxBase);
205 // some garbage collection should later hunt for dd's with
206 // 0 lockcount and possibly non-usage for a certain amount
207 // of time and get rid of them.
211 void KillDriverData(struct RastPort
*rp
, struct GfxBase
*GfxBase
)
213 if (RP_BACKPOINTER(rp
) == rp
)
215 struct gfx_driverdata
*dd
= NULL
;
217 if (rp
->Flags
& RPF_SELF_CLEANUP
)
219 dd
= RP_DRIVERDATA(rp
);
223 ObtainSemaphore(&PrivGBase(GfxBase
)->driverdatasem
);
224 if (FindDriverData(RP_DRIVERDATA(rp
), rp
, GfxBase
))
226 dd
= RP_DRIVERDATA(rp
);
227 RemoveDriverDataFromList(dd
, GfxBase
);
229 ReleaseSemaphore(&PrivGBase(GfxBase
)->driverdatasem
);
234 struct monitor_driverdata
*sdd
;
236 /* rp->BitMap may not be valid anymore! */
237 if (0) // (rp->BitMap)
238 sdd
= GET_BM_DRIVERDATA(rp
->BitMap
);
240 sdd
= (struct monitor_driverdata
*)CDD(GfxBase
);
242 HIDD_Gfx_DisposeGC(sdd
->gfxhidd
, dd
->dd_GC
);
243 FreePooled(PrivGBase(GfxBase
)->driverdatapool
, dd
, sizeof(*dd
));
244 RP_DRIVERDATA(rp
) = NULL
;
251 int driver_init(struct GfxBase
* GfxBase
)
254 EnterFunc(bug("driver_init()\n"));
256 /* Our underlying RTG subsystem core must be already up and running */
257 if (!OpenLibrary("graphics.hidd", 0))
260 /* Initialize the semaphores */
261 InitSemaphore(&(PrivGBase(GfxBase
)->blit_sema
));
263 /* Init the needed attrbases */
265 __IHidd_BitMap
= OOP_ObtainAttrBase(IID_Hidd_BitMap
);
266 __IHidd_GC
= OOP_ObtainAttrBase(IID_Hidd_GC
);
267 __IHidd_Sync
= OOP_ObtainAttrBase(IID_Hidd_Sync
);
268 __IHidd_PixFmt
= OOP_ObtainAttrBase(IID_Hidd_PixFmt
);
269 __IHidd_PlanarBM
= OOP_ObtainAttrBase(IID_Hidd_PlanarBM
);
270 __IHidd_Gfx
= OOP_ObtainAttrBase(IID_Hidd_Gfx
);
271 __IHidd_FakeGfxHidd
= OOP_ObtainAttrBase(IID_Hidd_FakeGfxHidd
);
274 if (__IHidd_BitMap
&&
282 /* Init display mode database */
283 InitSemaphore(&CDD(GfxBase
)->displaydb_sem
);
284 CDD(GfxBase
)->invalid_id
= INVALID_ID
;
285 CDD(GfxBase
)->last_id
= AROS_RTG_MONITOR_ID
;
287 /* Init memory driver */
288 CDD(GfxBase
)->memorygfx
= OOP_NewObject(NULL
, CLID_Hidd_Gfx
, NULL
);
289 DEBUG_INIT(bug("[driver_init] Memory driver object 0x%p\n", CDD(GfxBase
)->memorygfx
));
290 if (CDD(GfxBase
)->memorygfx
) {
291 struct TagItem bm_create_tags
[] = {
292 { aHidd_BitMap_GfxHidd
, (IPTR
)CDD(GfxBase
)->memorygfx
},
293 { aHidd_PlanarBM_AllocPlanes
, FALSE
},
297 CDD(GfxBase
)->planarbm_cache
= create_object_cache(NULL
, CLID_Hidd_PlanarBM
, bm_create_tags
, GfxBase
);
298 DEBUG_INIT(bug("[driver_init] Planar bitmap cache 0x%p\n", CDD(GfxBase
)->planarbm_cache
));
299 if (CDD(GfxBase
)->planarbm_cache
) {
300 struct TagItem gc_create_tags
[] = { { TAG_DONE
, 0UL } };
302 CDD(GfxBase
)->gc_cache
= create_object_cache(NULL
, CLID_Hidd_GC
, gc_create_tags
, GfxBase
);
303 DEBUG_INIT(bug("[driver_init] GC cache 0x%p\n", CDD(GfxBase
)->planarbm_cache
));
304 if (CDD(GfxBase
)->gc_cache
)
305 ReturnInt("driver_init", int, TRUE
);
306 delete_object_cache(CDD(GfxBase
)->planarbm_cache
, GfxBase
);
309 OOP_DisposeObject(CDD(GfxBase
)->memorygfx
);
313 ReturnInt("driver_init", int, FALSE
);
316 /* Called after DOS is up & running */
317 static OOP_Object
*create_framebuffer(struct monitor_driverdata
*mdd
, struct GfxBase
*GfxBase
)
319 struct TagItem fbtags
[] = {
320 { aHidd_BitMap_FrameBuffer
, TRUE
},
321 { aHidd_BitMap_ModeID
, 0 },
325 HIDDT_ModeID hiddmode
;
326 OOP_Object
*fb
= NULL
;
328 /* Get the highest available resolution at the best possible depth */
329 hiddmode
= get_best_resolution_and_depth(mdd
, GfxBase
);
330 if (vHidd_ModeID_Invalid
== hiddmode
) {
331 D(bug("!!! create_framebuffer(): COULD NOT GET HIDD MODEID !!!\n"));
333 /* Create the framebuffer object */
334 fbtags
[1].ti_Data
= hiddmode
;
335 fb
= HIDD_Gfx_NewBitMap(mdd
->gfxhidd
, fbtags
);
342 * Set up graphics display driver.
343 * Creates necessary OS structures around it.
345 * gfxhidd - newly created driver object
346 * result - master driver structure
349 struct monitor_driverdata
*driver_Setup(OOP_Object
*gfxhidd
, struct GfxBase
*GfxBase
)
353 IPTR noframebuffer
= 0;
356 HIDDT_ModeID
*modes
, *m
;
357 struct monitor_driverdata
*mdd
;
359 D(bug("[driver_Setup] gfxhidd=0x%p\n", gfxhidd
));
361 modes
= HIDD_Gfx_QueryModeIDs(gfxhidd
, NULL
);
365 /* Count number of display modes */
366 for (m
= modes
; *m
!= vHidd_ModeID_Invalid
; m
++)
369 mdd
= AllocVec(sizeof(struct monitor_driverdata
) + cnt
* sizeof(struct DisplayInfoHandle
), MEMF_PUBLIC
|MEMF_CLEAR
);
370 D(bug("[driver_Setup] Allocated driverdata at 0x%p\n", mdd
));
372 HIDD_Gfx_ReleaseModeIDs(gfxhidd
, modes
);
376 mdd
->gfxhidd_orig
= gfxhidd
;
378 /* Fill in ModeID database in the driverdata */
379 for (i
= 0; i
<= cnt
; i
++) {
380 mdd
->modes
[i
].id
= modes
[i
];
381 mdd
->modes
[i
].drv
= mdd
;
384 HIDD_Gfx_ReleaseModeIDs(gfxhidd
, modes
);
386 #ifndef FORCE_SOFTWARE_SPRITE
387 OOP_GetAttr(gfxhidd
, aHidd_Gfx_HWSpriteTypes
, &hwcursor
);
389 OOP_GetAttr(gfxhidd
, aHidd_Gfx_NoFrameBuffer
, &noframebuffer
);
392 mdd
->gfxhidd
= gfxhidd
;
394 D(bug("[driver_Setup] Hardware mouse cursor is not supported, using fakegfx.hidd\n"));
396 mdd
->gfxhidd
= init_fakegfxhidd(gfxhidd
, GfxBase
);
398 mdd
->flags
|= DF_UseFakeGfx
;
404 struct TagItem gc_create_tags
[] = { { TAG_DONE
, 0UL } };
406 D(bug("[driver_Setup] Ok\n"));
408 /* FIXME: perhaps driver should be able to supply own GC class? */
409 mdd
->gc_cache
= create_object_cache(NULL
, CLID_Hidd_GC
, gc_create_tags
, GfxBase
);
411 D(bug("[driver_Setup] GC Cache created\n"));
414 /* Note that we perform this operation on fakegfx.hidd if it was
416 mdd
->framebuffer
= create_framebuffer(mdd
, GfxBase
);
418 if (noframebuffer
|| mdd
->framebuffer
) {
419 D(bug("[driver_Setup] FRAMEBUFFER OK: %p\n", mdd
->framebuffer
));
423 if (mdd
->framebuffer
)
424 OOP_DisposeObject(mdd
->framebuffer
);
426 delete_object_cache(mdd
->gc_cache
, GfxBase
);
427 } /* if (gc object cache ok) */
428 } /* if (fake gfx stuff ok) */
430 if (mdd
->flags
& DF_UseFakeGfx
)
431 OOP_DisposeObject(mdd
->gfxhidd
);
439 * Completely remove a driver from the OS.
441 * mdd - Driver structure to remove.
443 * Note that removing a driver is very unsafe operation. You must be
444 * sure that no bitmaps of this driver exist at the moment. Perhaps
445 * something should be done with it.
449 void driver_Expunge(struct monitor_driverdata
*mdd
, struct GfxBase
*GfxBase
)
451 if (CDD(GfxBase
)->DriverNotify
)
452 CDD(GfxBase
)->DriverNotify(mdd
->userdata
, FALSE
, CDD(GfxBase
)->notify_data
);
454 if (mdd
->framebuffer
)
455 OOP_DisposeObject(mdd
->framebuffer
);
458 delete_object_cache(mdd
->gc_cache
, GfxBase
);
460 if (mdd
->flags
& DF_UseFakeGfx
)
461 OOP_DisposeObject(mdd
->gfxhidd
);
463 /* Dispose driver object. This will take care about syncs etc */
464 if (mdd
->gfxhidd_orig
)
465 OOP_DisposeObject(mdd
->gfxhidd_orig
);
472 static ULONG
getbitmappixel(struct BitMap
*bm
484 idx
= COORD_TO_BYTEIDX(x
, y
, bm
->BytesPerRow
);
485 mask
= XCOORD_TO_MASK( x
);
487 for (i
= depth
- 1; depth
; i
-- , depth
-- )
489 pen
<<= 1; /* stegerg: moved to here, was inside if!? */
491 if ((1L << i
) & plane_mask
)
493 UBYTE
*plane
= bm
->Planes
[i
];
495 if (plane
== (PLANEPTR
)-1)
499 else if (plane
!= NULL
)
501 if ((plane
[idx
] & mask
) != 0)
512 /* This is called for every ViewPorts chain during MrgCop() */
513 ULONG
driver_PrepareViewPorts(struct HIDD_ViewPortData
*vpd
, struct View
*v
, struct monitor_driverdata
*mdd
, struct GfxBase
*GfxBase
)
515 /* Do not bother the driver if there's nothing to prepare. Can be changed if needed. */
516 return vpd
? HIDD_Gfx_PrepareViewPorts(mdd
->gfxhidd
, vpd
, v
) : MCOP_OK
;
520 * This is called for every ViewPorts chain during LoadView()
521 * LoadView() actually has no rights for errors because error condition
522 * in it will screw up the display, likely with no chance to recover.
523 * Because of this we always return zero here.
525 ULONG
driver_LoadViewPorts(struct HIDD_ViewPortData
*vpd
, struct View
*v
, struct monitor_driverdata
*mdd
, struct GfxBase
*GfxBase
)
527 struct BitMap
*bitmap
;
529 OOP_Object
*cmap
, *pf
;
530 HIDDT_ColorModel colmod
;
532 DEBUG_LOADVIEW(bug("[driver_LoadViewPorts] Showing ViewPortData 0x%p, BitMap object 0x%p\n", vpd
, vpd
? vpd
->Bitmap
: NULL
));
535 /* First try the new method */
536 if (HIDD_Gfx_ShowViewPorts(mdd
->gfxhidd
, vpd
))
538 DEBUG_LOADVIEW(bug("[driver_LoadViewPorts] ShowViewPorts() worked\n"));
542 /* If it failed, we may be working with a framebuffer. First check if the bitmap
543 is already displayed. If so, do nothing (because displaying the same bitmap twice may
544 cause some problems) */
547 bitmap
= vpd
->vpe
->ViewPort
->RasInfo
->BitMap
;
555 DEBUG_LOADVIEW(bug("[driver_LoadViewPorts] Old bitmap 0x%p, New bitmap 0x%p, object 0x%p\n", mdd
->frontbm
, bitmap
, bm
));
557 if (mdd
->frontbm
== bitmap
)
560 fb
= HIDD_Gfx_Show(mdd
->gfxhidd
, bm
, fHidd_Gfx_Show_CopyBack
);
561 DEBUG_LOADVIEW(bug("[driver_LoadViewPorts] Show() returned 0x%p\n", fb
));
563 /* Summary of possible responses (when no error happened):
564 NoFrameBuffer = FALSE: bm = NULL -> fb != NULL and bm != fb
565 NoFrameBuffer = FALSE: bm != NULL -> fb != NULL and bm != fb
566 NoFrameBuffer = TRUE : bm = NULL -> fb == NULL and bm == fb
567 NoFrameBuffer = TRUE : bm != NULL -> fb != NULL and bm == fb
573 /* Do not swap bitmaps for NoFrameBuffer drivers */
574 /* Detection: these kind of drivers must return the same bitmap they received */
578 * FIXME: THIS IS NOT THREADSAFE
579 * To make this threadsafe we have to lock
580 * all gfx access in all the rendering calls
583 DEBUG_LOADVIEW(bug("[driver_LoadViewPorts] Replacing framebuffer\n"));
585 /* Set this as the active screen */
586 if (NULL
!= mdd
->frontbm
)
588 struct BitMap
*oldbm
;
590 /* Put back the old values into the old bitmap */
591 oldbm
= mdd
->frontbm
;
592 HIDD_BM_OBJ(oldbm
) = mdd
->bm_bak
;
593 HIDD_BM_COLMOD(oldbm
) = mdd
->colmod_bak
;
594 HIDD_BM_COLMAP(oldbm
) = mdd
->colmap_bak
;
598 mdd
->colmod_bak
= bitmap
? HIDD_BM_COLMOD(bitmap
) : 0;
599 mdd
->colmap_bak
= bitmap
? HIDD_BM_COLMAP(bitmap
) : NULL
;
603 /* Insert the framebuffer in its place */
604 OOP_GetAttr(fb
, aHidd_BitMap_ColorMap
, (IPTR
*)&cmap
);
605 OOP_GetAttr(fb
, aHidd_BitMap_PixFmt
, (IPTR
*)&pf
);
606 OOP_GetAttr(pf
, aHidd_PixFmt_ColorModel
, &colmod
);
608 HIDD_BM_OBJ(bitmap
) = fb
;
609 HIDD_BM_COLMOD(bitmap
) = colmod
;
610 HIDD_BM_COLMAP(bitmap
) = cmap
;
614 /* We need to always remember our new frontmost bitmap, even if we do not work
615 with a framebuffer */
616 mdd
->frontbm
= bitmap
;
618 /* Tell the driver to refresh the screen */
619 OOP_GetAttr(fb
, aHidd_BitMap_Width
, &width
);
620 OOP_GetAttr(fb
, aHidd_BitMap_Height
, &height
);
621 DEBUG_LOADVIEW(bug("[driver_LoadViewPorts] Updating framebuffer, new size: %d x %d\n", width
, height
));
623 HIDD_BM_UpdateRect(fb
, 0, 0, width
, height
);
631 /* Find the first visible ViewPortData for the specified monitor in the View */
632 struct HIDD_ViewPortData
*driver_FindViewPorts(struct View
*view
, struct monitor_driverdata
*mdd
, struct GfxBase
*GfxBase
)
636 for (vp
= view
->ViewPort
; vp
; vp
= vp
->Next
)
638 if (!(vp
->Modes
& VP_HIDE
))
640 struct ViewPortExtra
*vpe
= (struct ViewPortExtra
*)GfxLookUp(vp
);
642 if (VPE_DRIVER(vpe
) == mdd
)
643 return VPE_DATA(vpe
);
650 * Iterate through HIDD_ViewPortData chains in the view and call
651 * the specified function for every chain and every driver.
652 * The function will be called at least once for every driver.
653 * If there is no ViewPorts for the driver, the function will be
654 * called with ViewPortData = NULL.
656 ULONG
DoViewFunction(struct View
*view
, VIEW_FUNC fn
, struct GfxBase
*GfxBase
)
658 struct monitor_driverdata
*mdd
;
661 ObtainSemaphoreShared(&CDD(GfxBase
)->displaydb_sem
);
663 for (mdd
= CDD(GfxBase
)->monitors
; mdd
; mdd
= mdd
->next
)
665 struct HIDD_ViewPortData
*vpd
= NULL
;
668 * Find the first visible ViewPort for this display. It
669 * will be a start of bitmaps chain to process.
672 vpd
= driver_FindViewPorts(view
, mdd
, GfxBase
);
674 rc
= fn(vpd
, view
, mdd
, GfxBase
);
676 /* Interrupt immediately if the callback returned error */
681 ReleaseSemaphore(&CDD(GfxBase
)->displaydb_sem
);