2 Copyright © 1995-2017, The AROS Development Team. All rights reserved.
5 Desc: Driver for using gfxhidd for gfx output
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>
32 #include <utility/tagitem.h>
33 #include <aros/asmcall.h>
35 #include <intuition/intuition.h>
37 #include <hidd/compositor.h>
40 #include <cybergraphx/cybergraphics.h>
45 #include "graphics_intern.h"
46 #include "compositor_driver.h"
47 #include "fakegfxhidd.h"
48 #include "intregions.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
59 #define FORCE_SOFTWARE_SPRITE */
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
);
74 dd
= AllocVec(sizeof(struct gfx_driverdata
), MEMF_CLEAR
);
85 /* *********************** Display driver handling *********************** */
87 int driver_init(struct GfxBase
* GfxBase
)
91 EnterFunc(bug("driver_init()\n"));
93 /* Our underlying RTG subsystem core must be already up and running */
94 if (!OpenLibrary("gfx.hidd", 0))
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
&&
120 CDD(GfxBase
)->gcClass
= OOP_FindClass(CLID_Hidd_GC
);
121 if (!CDD(GfxBase
)->gcClass
)
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 },
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 },
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"));
179 /* Create the framebuffer object */
180 fbtags
[1].ti_Data
= hiddmode
;
181 fb
= HIDD_Gfx_CreateObject(mdd
->gfxhidd
, PrivGBase(GfxBase
)->basebm
, fbtags
);
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
)
199 IPTR fbtype
= vHidd_FrameBuffer_Direct
; /* We default to direct for historical reasons */
201 BOOL can_compose
= FALSE
;
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
);
214 /* Count number of display modes */
215 for (m
= modes
; *m
!= vHidd_ModeID_Invalid
; m
++)
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
));
222 HIDD_Gfx_ReleaseModeIDs(gfxhidd
, modes
);
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
;
248 OOP_Object
*sync
, *pf
;
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.
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
);
273 OOP_GetAttr(gfxhidd
, aHidd_Gfx_FrameBufferType
, &fbtype
);
277 mdd
->gfxhidd
= gfxhidd
;
281 D(bug("[driver_Setup] Hardware mouse cursor is not supported, using fakegfx.hidd\n"));
283 mdd
->gfxhidd
= init_fakegfxhidd(gfxhidd
, GfxBase
);
285 mdd
->flags
|= DF_UseFakeGfx
;
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.
301 case vHidd_FrameBuffer_Direct
:
302 mdd
->flags
|= DF_DirectFB
;
304 case vHidd_FrameBuffer_Mirrored
:
305 mdd
->framebuffer
= create_framebuffer(mdd
, GfxBase
);
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
);
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
);
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
);
368 static ULONG
getbitmappixel(struct BitMap
*bm
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)
395 else if (plane
!= NULL
)
397 if ((plane
[idx
] & mask
) != 0)
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
;
425 BOOL compositing
= FALSE
;
427 DEBUG_LOADVIEW(bug("[driver_LoadViewPorts] Showing ViewPortData 0x%p, BitMap object 0x%p\n", vpd
, vpd
? vpd
->Bitmap
: NULL
));
430 /* First try the new method */
431 if (HIDD_Gfx_ShowViewPorts(mdd
->gfxhidd
, vpd
))
433 DEBUG_LOADVIEW(bug("[driver_LoadViewPorts] ShowViewPorts() worked\n"));
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.
444 bitmap
= vpd
->vpe
->ViewPort
->RasInfo
->BitMap
;
452 DEBUG_LOADVIEW(bug("[driver_LoadViewPorts] Old bitmap 0x%p, New bitmap 0x%p, object 0x%p\n", mdd
->frontbm
, bitmap
, bm
));
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
));
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
)
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
486 /* The screen is not empty, 'fb' is on display now. */
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
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.
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
);
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.
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
541 void InstallFB(struct monitor_driverdata
*mdd
, struct GfxBase
*GfxBase
)
543 if ((mdd
->flags
& DF_DirectFB
) && mdd
->frontbm
)
545 struct BitMap
*bitmap
= mdd
->frontbm
;
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
)
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 */
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
)
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
);
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
;
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.
623 vpd
= driver_FindViewPorts(view
, mdd
, GfxBase
);
625 rc
= fn(vpd
, view
, mdd
, GfxBase
);
627 /* Interrupt immediately if the callback returned error */
632 ReleaseSemaphore(&CDD(GfxBase
)->displaydb_sem
);