Fix IO memory access .. SB128 driver makes noises in VMWare - CMI is untested (Curren...
[AROS.git] / rom / graphics / graphics_driver.c
blob12e489e5becb0d69234bf7057a45eb2ff69cea3a
1 /*
2 Copyright © 1995-2011, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Driver for using gfxhidd for gfx output
6 Lang: english
7 */
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>
30 #include <oop/oop.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>
40 #include <stdio.h>
41 #include <string.h>
43 #include "graphics_intern.h"
44 #include "fakegfxhidd.h"
45 #include "intregions.h"
46 #include "dispinfo.h"
47 #include "gfxfuncsupport.h"
48 #include "fontsupport.h"
50 #define SDEBUG 0
51 #define DEBUG 0
52 #include <aros/debug.h>
54 #define DEBUG_INIT(x)
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
59 and testing
60 #define FORCE_SOFTWARE_SPRITE */
62 struct ETextFont
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)
74 LONG hash;
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;
94 LONG hash;
95 BOOL retval = FALSE;
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))
104 retval = TRUE;
105 break;
108 // ReleaseSemaphore(&PrivGBase(GfxBase)->driverdatasem);
110 return retval;
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;
124 else
126 /* We have detected a manually cloned rastport. Mark it as 'valid'
127 (backpointer to itself) but with NULL driverdata and non-self
128 cleanup */
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);
136 if (dd)
138 if (!(rp->Flags & RPF_SELF_CLEANUP) && FindDriverData(dd, rp, GfxBase))
140 dd->dd_LockCount++;
142 else
144 RP_DRIVERDATA(rp) = NULL;
145 dd = NULL;
149 if (!dd)
151 dd = AllocPooled(PrivGBase(GfxBase)->driverdatapool, sizeof(*dd));
152 if (dd)
154 struct monitor_driverdata *sdd;
155 struct TagItem gc_tags[] = {{ TAG_DONE}};
157 if (rp->BitMap)
158 sdd = GET_BM_DRIVERDATA(rp->BitMap);
159 else
160 sdd = (struct monitor_driverdata *)CDD(GfxBase);
162 dd->dd_GC = HIDD_Gfx_NewGC(sdd->gfxhidd, gc_tags);
163 if (dd->dd_GC)
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);
175 else
177 FreePooled(PrivGBase(GfxBase)->driverdatapool, dd, sizeof(*dd));
178 dd = NULL;
181 } /* if (dd) */
183 } /* if (!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?? */
199 dd->dd_LockCount--;
201 // Don't do this:
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);
221 else
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);
232 if (dd)
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);
239 else
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))
258 return FALSE;
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 &&
275 __IHidd_GC &&
276 __IHidd_Sync &&
277 __IHidd_PixFmt &&
278 __IHidd_PlanarBM &&
279 __IHidd_Gfx &&
280 __IHidd_FakeGfxHidd)
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 },
294 { TAG_DONE , 0UL }
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 },
322 { TAG_DONE, 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"));
332 } else {
333 /* Create the framebuffer object */
334 fbtags[1].ti_Data = hiddmode;
335 fb = HIDD_Gfx_NewBitMap(mdd->gfxhidd, fbtags);
338 return fb;
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)
351 ULONG cnt = 0;
352 IPTR hwcursor = 0;
353 IPTR noframebuffer = 0;
354 BOOL ok = TRUE;
355 ULONG i;
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);
362 if (!modes)
363 return NULL;
365 /* Count number of display modes */
366 for (m = modes; *m != vHidd_ModeID_Invalid; m ++)
367 cnt++;
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));
371 if (!mdd) {
372 HIDD_Gfx_ReleaseModeIDs(gfxhidd, modes);
373 return NULL;
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);
388 #endif
389 OOP_GetAttr(gfxhidd, aHidd_Gfx_NoFrameBuffer, &noframebuffer);
391 if (hwcursor) {
392 mdd->gfxhidd = gfxhidd;
393 } else {
394 D(bug("[driver_Setup] Hardware mouse cursor is not supported, using fakegfx.hidd\n"));
396 mdd->gfxhidd = init_fakegfxhidd(gfxhidd, GfxBase);
397 if (mdd->gfxhidd)
398 mdd->flags |= DF_UseFakeGfx;
399 else
400 ok = FALSE;
403 if (ok) {
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);
410 if (mdd->gc_cache) {
411 D(bug("[driver_Setup] GC Cache created\n"));
413 if (!noframebuffer)
414 /* Note that we perform this operation on fakegfx.hidd if it was
415 plugged in */
416 mdd->framebuffer = create_framebuffer(mdd, GfxBase);
418 if (noframebuffer || mdd->framebuffer) {
419 D(bug("[driver_Setup] FRAMEBUFFER OK: %p\n", mdd->framebuffer));
420 return mdd;
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);
433 FreeVec(mdd);
435 return NULL;
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);
457 if (mdd->gc_cache)
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 );
467 FreeVec(mdd);
470 #if 0 /* Unused? */
472 static ULONG getbitmappixel(struct BitMap *bm
473 , LONG x
474 , LONG y
475 , UBYTE depth
476 , UBYTE plane_mask)
478 UBYTE i;
479 ULONG idx;
481 ULONG mask;
482 ULONG pen = 0;
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)
497 pen |= 1;
499 else if (plane != NULL)
501 if ((plane[idx] & mask) != 0)
502 pen |= 1;
507 return pen;
510 #endif
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;
528 OOP_Object *bm, *fb;
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));
533 mdd->display = vpd;
535 /* First try the new method */
536 if (HIDD_Gfx_ShowViewPorts(mdd->gfxhidd, vpd))
538 DEBUG_LOADVIEW(bug("[driver_LoadViewPorts] ShowViewPorts() worked\n"));
539 return 0;
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) */
545 if (vpd)
547 bitmap = vpd->vpe->ViewPort->RasInfo->BitMap;
548 bm = vpd->Bitmap;
550 else
552 bitmap = NULL;
553 bm = NULL;
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)
558 return 0;
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
569 if (fb)
571 IPTR width, height;
573 /* Do not swap bitmaps for NoFrameBuffer drivers */
574 /* Detection: these kind of drivers must return the same bitmap they received */
575 if (fb != bm)
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;
597 mdd->bm_bak = bm;
598 mdd->colmod_bak = bitmap ? HIDD_BM_COLMOD(bitmap) : 0;
599 mdd->colmap_bak = bitmap ? HIDD_BM_COLMAP(bitmap) : NULL;
601 if (bitmap)
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);
625 else
626 mdd->frontbm = NULL;
628 return 0;
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)
634 struct ViewPort *vp;
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);
646 return NULL;
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;
659 ULONG rc = 0;
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.
671 if (view)
672 vpd = driver_FindViewPorts(view, mdd, GfxBase);
674 rc = fn(vpd, view, mdd, GfxBase);
676 /* Interrupt immediately if the callback returned error */
677 if (rc)
678 break;
681 ReleaseSemaphore(&CDD(GfxBase)->displaydb_sem);
683 return rc;