register the software rasterizer with the gfx root
[AROS.git] / rom / graphics / graphics_driver.c
blob28a2ce2d6ae7d94fa7beb10ea6312108b8e83056
1 /*
2 Copyright © 1995-2017, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Driver for using gfxhidd for gfx output
6 Lang: english
7 */
9 #include <aros/debug.h>
11 #include <proto/exec.h>
12 #include <proto/graphics.h>
13 #include <proto/arossupport.h>
14 #include <proto/utility.h>
15 #include <proto/oop.h>
17 #include <exec/memory.h>
18 #include <exec/semaphores.h>
19 #include <clib/macros.h>
21 #include <graphics/rastport.h>
22 #include <graphics/gfxbase.h>
23 #include <graphics/text.h>
24 #include <graphics/view.h>
25 #include <graphics/layers.h>
26 #include <graphics/clip.h>
27 #include <graphics/gfxmacros.h>
28 #include <graphics/regions.h>
29 #include <graphics/scale.h>
31 #include <oop/oop.h>
32 #include <utility/tagitem.h>
33 #include <aros/asmcall.h>
35 #include <intuition/intuition.h>
37 #include <hidd/compositor.h>
38 #include <hidd/gfx.h>
40 #include <cybergraphx/cybergraphics.h>
42 #include <stdio.h>
43 #include <string.h>
45 #include "graphics_intern.h"
46 #include "compositor_driver.h"
47 #include "fakegfxhidd.h"
48 #include "intregions.h"
49 #include "dispinfo.h"
50 #include "gfxfuncsupport.h"
51 #include "fontsupport.h"
53 #define DEBUG_INIT(x) x
54 #define DEBUG_LOADVIEW(x)
56 /* Define this if you wish to enforce using software mouse sprite
57 even for drivers that support hardware one. Useful for debugging
58 and testing
59 #define FORCE_SOFTWARE_SPRITE */
61 struct ETextFont
63 struct TextFont etf_Font;
66 /* *********************** RastPort extra data handling *********************** */
68 struct gfx_driverdata *AllocDriverData(struct RastPort *rp, BOOL alloc, struct GfxBase *GfxBase)
70 struct gfx_driverdata *dd = ObtainDriverData(rp);
72 if (alloc && !dd)
74 dd = AllocVec(sizeof(struct gfx_driverdata), MEMF_CLEAR);
75 if (dd)
77 rp->RP_Extra = dd;
78 dd->dd_RastPort = rp;
82 return dd;
85 /* *********************** Display driver handling *********************** */
87 int driver_init(struct GfxBase * GfxBase)
89 OOP_Class *baseGfx;
91 EnterFunc(bug("driver_init()\n"));
93 /* Our underlying RTG subsystem core must be already up and running */
94 if (!OpenLibrary("gfx.hidd", 0))
95 return FALSE;
97 baseGfx = OOP_FindClass(CLID_Hidd_Gfx);
99 /* Initialize the semaphores */
100 InitSemaphore(&(PrivGBase(GfxBase)->blit_sema));
102 /* Init the needed attrbases */
104 __IHidd_BitMap = OOP_ObtainAttrBase(IID_Hidd_BitMap);
105 __IHidd_GC = OOP_ObtainAttrBase(IID_Hidd_GC);
106 __IHidd_Sync = OOP_ObtainAttrBase(IID_Hidd_Sync);
107 __IHidd_PixFmt = OOP_ObtainAttrBase(IID_Hidd_PixFmt);
108 __IHidd_PlanarBM = OOP_ObtainAttrBase(IID_Hidd_PlanarBM);
109 __IHidd_Gfx = OOP_ObtainAttrBase(IID_Hidd_Gfx);
110 __IHidd_FakeGfxHidd = OOP_ObtainAttrBase(IID_Hidd_FakeGfxHidd);
112 if (__IHidd_BitMap &&
113 __IHidd_GC &&
114 __IHidd_Sync &&
115 __IHidd_PixFmt &&
116 __IHidd_PlanarBM &&
117 __IHidd_Gfx &&
118 __IHidd_FakeGfxHidd)
120 CDD(GfxBase)->gcClass = OOP_FindClass(CLID_Hidd_GC);
121 if (!CDD(GfxBase)->gcClass)
122 return FALSE;
124 /* Init display mode database */
125 InitSemaphore(&CDD(GfxBase)->displaydb_sem);
126 CDD(GfxBase)->invalid_id = INVALID_ID;
127 CDD(GfxBase)->last_id = AROS_RTG_MONITOR_ID;
129 /* Init software driver */
130 CDD(GfxBase)->memorygfx = HW_AddDriver(PrivGBase(GfxBase)->GfxRoot, baseGfx, NULL);
131 DEBUG_INIT(bug("[driver_init] Memory driver object 0x%p\n", CDD(GfxBase)->memorygfx));
133 if (CDD(GfxBase)->memorygfx)
135 struct TagItem bm_create_tags[] =
137 { aHidd_BitMap_GfxHidd , (IPTR)CDD(GfxBase)->memorygfx },
138 { aHidd_PlanarBM_BitMap, 0 },
139 { TAG_DONE , 0 }
142 CDD(GfxBase)->planarbm_cache = create_object_cache(NULL, CLID_Hidd_PlanarBM, bm_create_tags, GfxBase);
143 DEBUG_INIT(bug("[driver_init] Planar bitmap cache 0x%p\n", CDD(GfxBase)->planarbm_cache));
145 if (CDD(GfxBase)->planarbm_cache)
147 CDD(GfxBase)->gc_cache = create_object_cache(NULL, CLID_Hidd_GC, NULL, GfxBase);
148 DEBUG_INIT(bug("[driver_init] GC cache 0x%p\n", CDD(GfxBase)->planarbm_cache));
150 if (CDD(GfxBase)->gc_cache)
151 ReturnInt("driver_init", int, TRUE);
153 delete_object_cache(CDD(GfxBase)->planarbm_cache, GfxBase);
155 OOP_DisposeObject(CDD(GfxBase)->memorygfx);
159 ReturnInt("driver_init", int, FALSE);
162 /* Called after DOS is up & running */
163 static OOP_Object *create_framebuffer(struct monitor_driverdata *mdd, struct GfxBase *GfxBase)
165 struct TagItem fbtags[] = {
166 { aHidd_BitMap_FrameBuffer, TRUE },
167 { aHidd_BitMap_ModeID, 0 },
168 { TAG_DONE, 0 }
171 HIDDT_ModeID hiddmode;
172 OOP_Object *fb = NULL;
174 /* Get the highest available resolution at the best possible depth */
175 hiddmode = get_best_resolution_and_depth(mdd, GfxBase);
176 if (vHidd_ModeID_Invalid == hiddmode) {
177 D(bug("!!! create_framebuffer(): COULD NOT GET HIDD MODEID !!!\n"));
178 } else {
179 /* Create the framebuffer object */
180 fbtags[1].ti_Data = hiddmode;
181 fb = HIDD_Gfx_CreateObject(mdd->gfxhidd, PrivGBase(GfxBase)->basebm, fbtags);
184 return fb;
188 * Set up graphics display driver.
189 * Creates necessary OS structures around it.
191 * gfxhidd - newly created driver object
192 * result - master driver structure
195 struct monitor_driverdata *driver_Setup(OOP_Object *gfxhidd, struct GfxBase *GfxBase)
197 ULONG cnt = 0;
198 IPTR hwcursor = 0;
199 IPTR fbtype = vHidd_FrameBuffer_Direct; /* We default to direct for historical reasons */
200 UWORD compose = 0;
201 BOOL can_compose = FALSE;
202 BOOL ok = TRUE;
203 ULONG i;
204 HIDDT_ModeID *modes, *m;
205 struct monitor_driverdata *mdd;
206 struct HIDD_ModeProperties props = {0};
208 D(bug("[driver_Setup] gfxhidd=0x%p (%s)\n", gfxhidd, OOP_OCLASS(gfxhidd)->ClassNode.ln_Name));
210 modes = HIDD_Gfx_QueryModeIDs(gfxhidd, NULL);
211 if (!modes)
212 return NULL;
214 /* Count number of display modes */
215 for (m = modes; *m != vHidd_ModeID_Invalid; m ++)
216 cnt++;
218 mdd = AllocVec(sizeof(struct monitor_driverdata) + cnt * sizeof(struct DisplayInfoHandle), MEMF_PUBLIC|MEMF_CLEAR);
219 D(bug("[driver_Setup] Allocated driverdata at 0x%p\n", mdd));
220 if (!mdd)
222 HIDD_Gfx_ReleaseModeIDs(gfxhidd, modes);
223 return NULL;
226 mdd->gfxhidd_orig = gfxhidd;
229 * 1. Fill in ModeID database in the driverdata.
230 * 2. Check if at least one mode supports composition.
231 * 3. Check if the driver has at least one non-palettized mode.
232 * (2) and (3) are needed to determine if we need/can use software screen
233 * composition with this driver.
235 for (i = 0; i <= cnt; i++)
237 mdd->modes[i].id = modes[i];
238 mdd->modes[i].drv = mdd;
240 /* Watch out! The last record in the array is terminator (vHidd_ModeID_Invalid) */
241 if ((i < cnt) && (!compose))
243 HIDD_Gfx_ModeProperties(gfxhidd, modes[i], &props, sizeof(props));
244 compose |= props.CompositionFlags;
246 if (!can_compose)
248 OOP_Object *sync, *pf;
249 IPTR colmod;
251 HIDD_Gfx_GetMode(gfxhidd, modes[i], &sync, &pf);
252 OOP_GetAttr(pf, aHidd_PixFmt_ColorModel, &colmod);
254 if (colmod == vHidd_ColorModel_TrueColor)
257 * At the moment software compositor supports only truecolor screens.
258 * There also definitions for DirectColor, gray, etc, but there is
259 * no such hardware supported by now.
261 can_compose = TRUE;
267 HIDD_Gfx_ReleaseModeIDs(gfxhidd, modes);
269 /* Query properties of our driver */
270 #ifndef FORCE_SOFTWARE_SPRITE
271 OOP_GetAttr(gfxhidd, aHidd_Gfx_HWSpriteTypes, &hwcursor);
272 #endif
273 OOP_GetAttr(gfxhidd, aHidd_Gfx_FrameBufferType, &fbtype);
275 if (hwcursor)
277 mdd->gfxhidd = gfxhidd;
279 else
281 D(bug("[driver_Setup] Hardware mouse cursor is not supported, using fakegfx.hidd\n"));
283 mdd->gfxhidd = init_fakegfxhidd(gfxhidd, GfxBase);
284 if (mdd->gfxhidd)
285 mdd->flags |= DF_UseFakeGfx;
286 else
287 ok = FALSE;
290 if (ok)
292 D(bug("[driver_Setup] Ok, framebuffer type %ld\n", fbtype));
295 * Instantiate framebuffer if needed.
296 * Note that we perform this operation on fakegfx.hidd if it was plugged in.
297 * This enables software mouse sprite on a framebuffer.
299 switch (fbtype)
301 case vHidd_FrameBuffer_Direct:
302 mdd->flags |= DF_DirectFB;
304 case vHidd_FrameBuffer_Mirrored:
305 mdd->framebuffer = create_framebuffer(mdd, GfxBase);
306 break;
309 if ((fbtype == vHidd_FrameBuffer_None) || mdd->framebuffer)
311 D(bug("[driver_Setup] FRAMEBUFFER OK: %p\n", mdd->framebuffer));
313 if ((!compose) && can_compose)
315 D(bug("[driver_Setup] Software screen composition required\n"));
317 mdd->flags |= DF_SoftCompose;
318 compositor_Setup(mdd, GfxBase);
321 return mdd;
324 if (mdd->framebuffer)
325 OOP_DisposeObject(mdd->framebuffer);
326 } /* if (fake gfx stuff ok) */
328 if (mdd->flags & DF_UseFakeGfx)
329 OOP_DisposeObject(mdd->gfxhidd);
331 FreeVec(mdd);
333 return NULL;
337 * Completely remove a driver from the OS.
339 * mdd - Driver structure to remove.
341 * Note that removing a driver is very unsafe operation. You must be
342 * sure that no bitmaps of this driver exist at the moment. Perhaps
343 * something should be done with it.
347 void driver_Expunge(struct monitor_driverdata *mdd, struct GfxBase *GfxBase)
349 /* Notify Intuition */
350 if (CDD(GfxBase)->DriverNotify)
351 CDD(GfxBase)->DriverNotify(mdd->userdata, FALSE, CDD(GfxBase)->notify_data);
353 /* Dispose associated stuff */
354 OOP_DisposeObject(mdd->compositor);
355 OOP_DisposeObject(mdd->framebuffer);
357 if (mdd->flags & DF_UseFakeGfx)
358 OOP_DisposeObject(mdd->gfxhidd);
360 /* Dispose driver object. This will take care about syncs etc */
361 OOP_DisposeObject(mdd->gfxhidd_orig );
363 FreeVec(mdd);
366 #if 0 /* Unused? */
368 static ULONG getbitmappixel(struct BitMap *bm
369 , LONG x
370 , LONG y
371 , UBYTE depth
372 , UBYTE plane_mask)
374 UBYTE i;
375 ULONG idx;
377 ULONG mask;
378 ULONG pen = 0;
380 idx = COORD_TO_BYTEIDX(x, y, bm->BytesPerRow);
381 mask = XCOORD_TO_MASK( x );
383 for (i = depth - 1; depth; i -- , depth -- )
385 pen <<= 1; /* stegerg: moved to here, was inside if!? */
387 if ((1L << i) & plane_mask)
389 UBYTE *plane = bm->Planes[i];
391 if (plane == (PLANEPTR)-1)
393 pen |= 1;
395 else if (plane != NULL)
397 if ((plane[idx] & mask) != 0)
398 pen |= 1;
403 return pen;
406 #endif
408 /* This is called for every ViewPorts chain during MrgCop() */
409 ULONG driver_PrepareViewPorts(struct HIDD_ViewPortData *vpd, struct View *v, struct monitor_driverdata *mdd, struct GfxBase *GfxBase)
411 /* Do not bother the driver if there's nothing to prepare. Can be changed if needed. */
412 return vpd ? HIDD_Gfx_PrepareViewPorts(mdd->gfxhidd, vpd, v) : MCOP_OK;
416 * This is called for every ViewPorts chain during LoadView()
417 * LoadView() actually has no rights for errors because error condition
418 * in it will screw up the display, likely with no chance to recover.
419 * Because of this we always return zero here.
421 ULONG driver_LoadViewPorts(struct HIDD_ViewPortData *vpd, struct View *v, struct monitor_driverdata *mdd, struct GfxBase *GfxBase)
423 struct BitMap *bitmap;
424 OOP_Object *bm, *fb;
425 BOOL compositing = FALSE;
427 DEBUG_LOADVIEW(bug("[driver_LoadViewPorts] Showing ViewPortData 0x%p, BitMap object 0x%p\n", vpd, vpd ? vpd->Bitmap : NULL));
428 mdd->display = vpd;
430 /* First try the new method */
431 if (HIDD_Gfx_ShowViewPorts(mdd->gfxhidd, vpd))
433 DEBUG_LOADVIEW(bug("[driver_LoadViewPorts] ShowViewPorts() worked\n"));
434 return 0;
438 * ShowViewPorts not supported.
439 * Perhaps we can use software screen compositor. But for proper operation
440 * we need to figure out our frontmost bitmap.
442 if (vpd)
444 bitmap = vpd->vpe->ViewPort->RasInfo->BitMap;
445 bm = vpd->Bitmap;
447 else
449 bitmap = NULL;
450 bm = NULL;
452 DEBUG_LOADVIEW(bug("[driver_LoadViewPorts] Old bitmap 0x%p, New bitmap 0x%p, object 0x%p\n", mdd->frontbm, bitmap, bm));
454 if (mdd->compositor)
457 * Compositor present. Give ViewPorts chain to it.
458 * For improved visual appearance it will call Show itself and return its result.
459 * The compositor is expected to handle all possible failures internally. If some
460 * internal error happens, it must fail back to single HIDD_Gfx_Show().
462 fb = compositor_LoadViewPorts(mdd->compositor, vpd, &compositing, GfxBase);
463 DEBUG_LOADVIEW(bug("[driver_LoadViewPorts] Compositor returned 0x%p, active: %d\n", fb, compositing));
465 else
468 * First check if the bitmap is already displayed. If so, do nothing (because
469 * displaying the same bitmap twice may cause some problems)
471 if (mdd->frontbm == bitmap)
472 return 0;
474 fb = HIDD_Gfx_Show(mdd->gfxhidd, bm, fHidd_Gfx_Show_CopyBack);
475 DEBUG_LOADVIEW(bug("[driver_LoadViewPorts] Show() returned 0x%p\n", fb));
478 /* Summary of possible responses (when no error happened):
479 NoFrameBuffer = FALSE: bm = NULL -> fb != NULL and bm != fb
480 NoFrameBuffer = FALSE: bm != NULL -> fb != NULL and bm != fb
481 NoFrameBuffer = TRUE : bm = NULL -> fb == NULL and bm == fb
482 NoFrameBuffer = TRUE : bm != NULL -> fb != NULL and bm == fb
484 if (fb)
486 /* The screen is not empty, 'fb' is on display now. */
487 IPTR width, height;
489 /* Uninstall the framebuffer from old frontmost BitMap (if present) */
490 UninstallFB(mdd, GfxBase);
493 * We need to always remember our new frontmost bitmap, even if we do not work
494 * with a framebuffer. This is needed for the check against showing the same
495 * bitmap twice.
497 mdd->frontbm = bitmap;
500 * Install the framebuffer into new bitmap. Only if software composition is inactive.
501 * If it is active, our BitMap is mirrored, not replaced.
503 if (!compositing)
504 InstallFB(mdd, GfxBase);
506 /* Tell the driver to refresh the screen */
507 OOP_GetAttr(fb, aHidd_BitMap_Width, &width);
508 OOP_GetAttr(fb, aHidd_BitMap_Height, &height);
509 DEBUG_LOADVIEW(bug("[driver_LoadViewPorts] Updating display, new size: %d x %d\n", width, height));
511 HIDD_BM_UpdateRect(fb, 0, 0, width, height);
513 else
516 * Screen is empty, simply reset the current bitmap.
517 * Only framebuffer-less driver can return NULL. So we don't need
518 * to call UninstallFB() here.
520 mdd->frontbm = NULL;
523 return 0;
527 * In-Place framebuffer install/uninstall routines.
529 * The idea behind: we gave some bitmap to display, the driver *HAS COPIED* it
530 * into the framebuffer. After this we must use a framebuffer bitmap instead of
531 * original one for all rendering operations.
532 * When another bitmap is displayed, the framebuffer contents will be put back
533 * into the original bitmap, and we will swap it back.
535 * This swap actually happens only of DF_DirectFB is set for the driver.
537 * FIXME: THIS IS NOT THREADSAFE
538 * To make this threadsafe we have to lock all gfx access in all the rendering
539 * calls.
541 void InstallFB(struct monitor_driverdata *mdd, struct GfxBase *GfxBase)
543 if ((mdd->flags & DF_DirectFB) && mdd->frontbm)
545 struct BitMap *bitmap = mdd->frontbm;
546 OOP_Object *pf;
548 /* Backup original data */
549 mdd->bm_bak = HIDD_BM_OBJ(bitmap);
550 mdd->colmod_bak = HIDD_BM_COLMOD(bitmap);
551 mdd->colmap_bak = HIDD_BM_COLMAP(bitmap);
553 /* Insert the framebuffer in its place */
554 OOP_GetAttr(mdd->framebuffer, aHidd_BitMap_PixFmt, (IPTR *)&pf);
556 HIDD_BM_OBJ(bitmap) = mdd->framebuffer;
557 HIDD_BM_COLMOD(bitmap) = OOP_GET(pf, aHidd_PixFmt_ColorModel);
558 HIDD_BM_COLMAP(bitmap) = (OOP_Object *)OOP_GET(mdd->framebuffer, aHidd_BitMap_ColorMap);
560 DEBUG_LOADVIEW(bug("[driver_LoadViewPorts] Installed framebuffer: BitMap 0x%p, object 0x%p\n", mdd->frontbm, mdd->bm_bak));
564 void UninstallFB(struct monitor_driverdata *mdd, struct GfxBase *GfxBase)
566 if (mdd->bm_bak)
568 /* Put back the old values into the old bitmap */
569 struct BitMap *oldbm = mdd->frontbm;
571 DEBUG_LOADVIEW(bug("[driver_LoadViewPorts] Uninstalling framebuffer: BitMap 0x%p, object 0x%p\n", mdd->frontbm, mdd->bm_bak));
573 HIDD_BM_OBJ(oldbm) = mdd->bm_bak;
574 HIDD_BM_COLMOD(oldbm) = mdd->colmod_bak;
575 HIDD_BM_COLMAP(oldbm) = mdd->colmap_bak;
577 /* No framebuffer installed */
578 mdd->bm_bak = NULL;
582 /* Find the first visible ViewPortData for the specified monitor in the View */
583 struct HIDD_ViewPortData *driver_FindViewPorts(struct View *view, struct monitor_driverdata *mdd, struct GfxBase *GfxBase)
585 struct ViewPort *vp;
587 for (vp = view->ViewPort; vp; vp = vp->Next)
589 if (!(vp->Modes & VP_HIDE))
591 struct ViewPortExtra *vpe = (struct ViewPortExtra *)GfxLookUp(vp);
593 if (VPE_DRIVER(vpe) == mdd)
594 return VPE_DATA(vpe);
597 return NULL;
601 * Iterate through HIDD_ViewPortData chains in the view and call
602 * the specified function for every chain and every driver.
603 * The function will be called at least once for every driver.
604 * If there is no ViewPorts for the driver, the function will be
605 * called with ViewPortData = NULL.
607 ULONG DoViewFunction(struct View *view, VIEW_FUNC fn, struct GfxBase *GfxBase)
609 struct monitor_driverdata *mdd;
610 ULONG rc = 0;
612 ObtainSemaphoreShared(&CDD(GfxBase)->displaydb_sem);
614 for (mdd = CDD(GfxBase)->monitors; mdd; mdd = mdd->next)
616 struct HIDD_ViewPortData *vpd = NULL;
619 * Find the first visible ViewPort for this display. It
620 * will be a start of bitmaps chain to process.
622 if (view)
623 vpd = driver_FindViewPorts(view, mdd, GfxBase);
625 rc = fn(vpd, view, mdd, GfxBase);
627 /* Interrupt immediately if the callback returned error */
628 if (rc)
629 break;
632 ReleaseSemaphore(&CDD(GfxBase)->displaydb_sem);
634 return rc;