2 Copyright © 1995-2015, The AROS Development Team. All rights reserved.
5 Desc: Graphics function BestModeIDA()
9 #include <aros/debug.h>
10 #include <cybergraphx/cybergraphics.h>
11 #include <graphics/modeid.h>
12 #include <hidd/graphics.h>
13 #include <proto/graphics.h>
14 #include <proto/utility.h>
15 #include <proto/oop.h>
19 #include "graphics_intern.h"
20 #include "gfxfuncsupport.h"
24 * There are lots of parameters and it's totally inoptimal to pass them
25 * as separate arguments.
26 * Instead we store our search state as a structure.
32 ULONG dipf_mustnothave
;
50 static void BestModeIDForMonitor(struct monitor_driverdata
*mdd
, struct MatchData
*args
, ULONG modemask
, struct GfxBase
*GfxBase
)
52 struct DisplayInfoHandle
*dinfo
;
53 struct DisplayInfo disp
;
54 struct DimensionInfo dims
;
60 OOP_GetAttr(mdd
->gfxhidd
, aHidd_Gfx_DriverName
, (IPTR
*)&name
);
61 if (strcmp(args
->boardname
, name
)) {
62 D(bug("[Gfx] %s: CYBRBIDTG_BoardName didn't match. '%s' != '%s'\n", __PRETTY_FUNCTION__
, args
->boardname
, name
));
67 for (dinfo
= mdd
->modes
; dinfo
->id
!= vHidd_ModeID_Invalid
; dinfo
++)
69 UWORD gm_width
, gm_height
;
70 ULONG modeid
= mdd
->id
| dinfo
->id
;
72 D(bug("[Gfx] %s: Checking ModeID 0x%08X (0x%08X 0x%08X)... ", __PRETTY_FUNCTION__
, modeid
, modeid
& modemask
, modemask
));
74 if (args
->monitorid
!= INVALID_ID
&& (args
->monitorid
& modemask
) != (modeid
& modemask
))
76 D(bug("BIDTAG_MonitorID 0x%08X didn't match\n", args
->monitorid
, args
->monitorid
& modemask
, modemask
));
80 if (GetDisplayInfoData(dinfo
, (UBYTE
*)&disp
, sizeof(disp
), DTAG_DISP
, modeid
) < offsetof(struct DisplayInfo
, pad2
))
82 D(bug("No DisplayInfo!\n"));
86 /* Filter out not available modes */
87 if (disp
.NotAvailable
)
89 D(bug("Not available: %u\n", disp
.NotAvailable
));
93 /* Filter out modes which do not meet out special needs */
94 if (disp
.PropertyFlags
& args
->dipf_mustnothave
)
96 D(bug("Has MustNotHave flags: 0x%08lX\n", disp
.PropertyFlags
));
99 if ((disp
.PropertyFlags
& args
->dipf_musthave
) != args
->dipf_musthave
)
101 D(bug("Does not have MustHave flags: 0x%08lX\n", disp
.PropertyFlags
));
105 if (GetDisplayInfoData(dinfo
, (UBYTE
*)&dims
, sizeof(dims
), DTAG_DIMS
, modeid
) < offsetof(struct DimensionInfo
, MaxOScan
))
107 D(bug("No DimensionInfo!\n"));
110 gm_width
= dims
.Nominal
.MaxX
- dims
.Nominal
.MinX
+ 1;
111 gm_height
= dims
.Nominal
.MaxY
- dims
.Nominal
.MinY
+ 1;
112 D(bug("%ux%ux%u", gm_width
, gm_height
, dims
.MaxDepth
));
114 /* FIXME: Take aspect ratio into account (nominal_width : nominal_height) */
116 /* Check if mode is not worse than requested */
117 if ( disp
.RedBits
>= args
->redbits
118 && disp
.GreenBits
>= args
->greenbits
119 && disp
.BlueBits
>= args
->bluebits
120 && dims
.MaxDepth
>= args
->depth
121 && gm_width
>= args
->desired_width
122 && gm_height
>= args
->desired_height
)
124 /* Check if this mode matches closer than the one we already found */
125 if ((dims
.MaxDepth
<= args
->found_depth
) &&
126 (gm_width
<= args
->found_width
) && (gm_height
<= args
->found_height
))
128 /* Remember the new mode only if something changed. This prevents unwanted
129 jumping to another display (several displays may have the same modes,
130 in this case the last display will be picked up without this check. */
131 if ((dims
.MaxDepth
< args
->found_depth
) ||
132 (gm_width
< args
->found_width
) || (gm_height
< args
->found_height
))
134 args
->found_id
= modeid
;
135 args
->found_depth
= dims
.MaxDepth
;
136 args
->found_width
= gm_width
;
137 args
->found_height
= gm_height
;
145 } /* for (each mode) */
148 static BOOL
FindBestModeIDForMonitor(struct monitor_driverdata
*monitor
, struct MatchData
*args
, ULONG modemask
, struct GfxBase
*GfxBase
)
150 /* First we try to search in preferred monitor (if present) */
152 BestModeIDForMonitor(monitor
, args
, modemask
, GfxBase
);
154 /* And if nothing was found there, check other monitors */
155 if (args
->found_id
== INVALID_ID
)
157 struct monitor_driverdata
*mdd
;
159 for (mdd
= CDD(GfxBase
)->monitors
; mdd
; mdd
= mdd
->next
)
162 BestModeIDForMonitor(mdd
, args
, modemask
, GfxBase
);
165 return args
->found_id
!= INVALID_ID
;
168 /*****************************************************************************
171 #include <proto/graphics.h>
173 AROS_LH1(ULONG
, BestModeIDA
,
176 AROS_LHA(struct TagItem
*, TagItems
, A0
),
179 struct GfxBase
*, GfxBase
, 175, Graphics
)
184 TagItems - pointer to an array of TagItems
187 BIDTAG_ViewPort (struct ViewPort *) - Viewport for which a mode is searched. Default: NULL
188 BIDTAG_MonitorID (ULONG) - Returned ID must use this monitor
189 BIDTAG_SourceID (ULONG) - Use this ModeID instead of a ViewPort.
190 DIPFMustHave mask is made up of the
191 ((DisplayInfo->PropertyFlags of this ID & SPECIAL_FLAGS) |
194 if BIDTAG_ViewPort was passed: VPModeID(vp), else the
195 DIPFMustHave and DIPFMustNotHave are unchanged.
196 BIDTAG_Depth (UBYTE) - Minimal depth. Default:
197 if BIDTAG_ViewPort is passed: vp->RasInfo->BitMap->Depth,
199 BIDTAG_NominalWidth (UWORD),
200 BIDTAG_NominalHeight (UWORD) - Aspect ratio. Default:
201 if BIDTAG_SourceID: SourceID NominalDimensionInfo
202 if BIDTAG_ViewPort: vp->DWidth and vp->DHeight
204 BIDTAG_DesiredWidth (UWORD) - Width. Default: DIBTAG_NominalWidth.
205 BIDTAG_DesiredHeight (UWORD) - Height. Default: BIDTAG_NominalHeight.
206 BIDTAG_RedBits (UBYTE),
207 BIDTAG_GreenBits (UBYTE),
208 BIDTAG_BlueBits (UBYTE) - Bits per gun the mode must support. Default: 4
209 BIDTAG_DIPFMustHave (ULONG) - DIPF flags the resulting mode must have
210 BIDTAG_DIPFMustNotHave (ULONG) - DIPF flags the resulting mode must not have
213 ID - ID of the best mode to use, or INVALID_ID if a match
223 graphics/modeid.h, graphics/displayinfo.h
226 This function also processes CYBRBIDTG_BoardName tag. This is private
227 to AROS, do not rely on it!
231 ******************************************************************************/
235 struct TagItem
*tag
, *tstate
= TagItems
;
236 struct DisplayInfoHandle
*dinfo
;
237 struct DisplayInfo disp
;
238 struct DimensionInfo dims
;
239 struct monitor_driverdata
*monitor
;
240 struct ViewPort
*vp
= NULL
;
241 ULONG sourceid
= INVALID_ID
;
242 struct MatchData args
=
244 0, SPECIAL_FLAGS
, /* DIPF */
245 4, 4, 4, /* RGB bits */
247 INVALID_ID
, /* Monitor ID */
248 NULL
, /* Board name */
249 0, 0, /* Nominal size */
250 0, 0, /* Desired size */
251 INVALID_ID
, /* Found ID */
252 -1, /* Found depth */
253 -1, -1 /* Found size */
256 D(bug("[Gfx] %s()\n", __PRETTY_FUNCTION__
));
258 /* Obtain default monitor driver */
259 monitor
= MonitorFromSpec(GfxBase
->default_monitor
, GfxBase
);
261 /* Get defaults which can be overriden */
262 while ((tag
= NextTagItem(&tstate
)))
266 case BIDTAG_DIPFMustHave
:
267 args
.dipf_musthave
= tag
->ti_Data
;
270 case BIDTAG_DIPFMustNotHave
:
271 args
.dipf_mustnothave
= tag
->ti_Data
;
274 case BIDTAG_MonitorID
:
275 args
.monitorid
= tag
->ti_Data
;
279 args
.redbits
= tag
->ti_Data
;
282 case BIDTAG_BlueBits
:
283 args
.bluebits
= tag
->ti_Data
;
286 case BIDTAG_ViewPort
:
287 /* If we got ViewPort, obtain some more defaults from it */
288 vp
= (struct ViewPort
*)tag
->ti_Data
;
289 args
.nominal_width
= vp
->DWidth
;
290 args
.nominal_height
= vp
->DHeight
;
291 args
.depth
= GET_BM_DEPTH(vp
->RasInfo
->BitMap
);
292 sourceid
= GetVPModeID(vp
);
293 monitor
= GET_VP_DRIVERDATA(vp
);
296 /* Offer some help to cybergraphics.library */
297 case CYBRBIDTG_BoardName
:
298 args
.boardname
= (STRPTR
)tag
->ti_Data
;
303 /* Then process SourceID, it overrides ViewPort size and mode and specifies current monitor */
304 sourceid
= GetTagData(BIDTAG_SourceID
, sourceid
, TagItems
);
305 if (sourceid
!= INVALID_ID
)
307 /* Patch musthave flags */
308 if (GetDisplayInfoData(NULL
, (UBYTE
*)&disp
, sizeof(disp
), DTAG_DISP
, sourceid
) >= offsetof(struct DisplayInfo
, Resolution
))
309 args
.dipf_musthave
|= (disp
.PropertyFlags
& SPECIAL_FLAGS
);
313 /* Override monitor and nominal size from source ID only if there was no ViewPort specified */
314 dinfo
= FindDisplayInfo(sourceid
);
316 monitor
= dinfo
->drv
;
318 if (GetDisplayInfoData(dinfo
, (UBYTE
*)&dims
, sizeof(dims
), DTAG_DIMS
, sourceid
) >= offsetof(struct DimensionInfo
, MaxOScan
))
320 args
.nominal_width
= dims
.Nominal
.MaxX
- dims
.Nominal
.MinX
+ 1;
321 args
.nominal_height
= dims
.Nominal
.MaxY
- dims
.Nominal
.MinY
+ 1;
326 /* Get high-priority parameters */
327 args
.nominal_width
= GetTagData(BIDTAG_NominalWidth
, args
.nominal_width
, TagItems
);
328 args
.nominal_height
= GetTagData(BIDTAG_NominalHeight
, args
.nominal_height
, TagItems
);
329 args
.desired_width
= GetTagData(BIDTAG_DesiredWidth
, args
.nominal_width
, TagItems
);
330 args
.desired_height
= GetTagData(BIDTAG_DesiredHeight
, args
.nominal_height
, TagItems
);
331 args
.depth
= GetTagData(BIDTAG_Depth
, args
.depth
, TagItems
);
333 /* Exclude flags in MustHave from MustNotHave (CHECKME: if this correct?) */
334 args
.dipf_mustnothave
&= ~args
.dipf_musthave
;
336 if (!args
.nominal_width
)
338 D(bug("[Gfx] %s: obtaining nominal values ...\n", __PRETTY_FUNCTION__
));
340 if (monitor
&& monitor
->gfxhidd
)
342 D(bug("[Gfx] %s: querying monitors gfx driver @ 0x%p\n", __PRETTY_FUNCTION__
, monitor
->gfxhidd
));
343 HIDD_Gfx_NominalDimensions(monitor
->gfxhidd
, &args
.nominal_width
, &args
.nominal_height
, &args
.depth
);
347 // fallback to hardcoded values..
348 args
.nominal_width
= 640;
349 args
.nominal_height
= 480;
354 D(bug("[Gfx] %s: Desired mode: %dx%dx%d, MonitorID 0x%08lX, MustHave 0x%08lX, MustNotHave 0x%08lX\n", __PRETTY_FUNCTION__
,
355 args
.desired_width
, args
.desired_height
, args
.depth
, args
.monitorid
, args
.dipf_musthave
, args
.dipf_mustnothave
));
357 /* OK, now we try to search for a mode that has the supplied charateristics. */
358 ObtainSemaphoreShared(&CDD(GfxBase
)->displaydb_sem
);
360 /* First try to find exact match */
361 FindBestModeIDForMonitor(monitor
, &args
, ~0, GfxBase
);
363 /* Handle situation where program only asks for specific monitor
364 * (for example only PAL_MONITOR_ID or NTSC_MONITOR_ID bits set)
365 * but it also requests hires or larger resolution.
366 * We must always return chipset mode if PAL or NTSC bits are set.
367 * Mask out screen mode bits (MONITOR_ID_MASK)
369 if (args
.found_id
== INVALID_ID
&& args
.monitorid
!= INVALID_ID
) {
370 FindBestModeIDForMonitor(monitor
, &args
, MONITOR_ID_MASK
, GfxBase
);
373 /* Still not found, AROS_MONITOR_ID_MASK.
374 * Mask out bit 12 in monitorid because the user may (and will) pass in IDs defined in include/graphics/modeid.h
375 * (like PAL_MONITOR_ID, VGA_MONITOR_ID, etc) which have bit 12 set)
377 if (args
.found_id
== INVALID_ID
&& args
.monitorid
!= INVALID_ID
) {
378 FindBestModeIDForMonitor(monitor
, &args
, AROS_MONITOR_ID_MASK
, GfxBase
);
381 ReleaseSemaphore(&CDD(GfxBase
)->displaydb_sem
);
383 D(bug("[Gfx] %s: Returning mode ID 0x%08lX\n", __PRETTY_FUNCTION__
, args
.found_id
));
384 return args
.found_id
;