2 Copyright © 1995-2013, 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("CYBRBIDTG_BoardName didn't match. '%s' != '%s'\n", 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("[BestModeID] Checking ModeID 0x%08X (0x%08X 0x%08X)... ", 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
;
169 static void FillNominal(struct GfxBase
*GfxBase
, struct MatchData
*args
)
171 struct monitor_driverdata
*mdd
;
172 /* Detect if we have RTG modes or only chipset modes.
173 * How to do this properly?
175 for (mdd
= CDD(GfxBase
)->monitors
; mdd
; mdd
= mdd
->next
) {
176 if (mdd
->id
& mdd
->mask
) /* Chipset = monitor ID zero */
179 /* Chipset only: set PAL/NTSC defaults */
180 args
->nominal_width
= GfxBase
->NormalDisplayColumns
;
181 args
->nominal_height
= GfxBase
->NormalDisplayRows
;
185 /*****************************************************************************
188 #include <proto/graphics.h>
190 AROS_LH1(ULONG
, BestModeIDA
,
193 AROS_LHA(struct TagItem
*, TagItems
, A0
),
196 struct GfxBase
*, GfxBase
, 175, Graphics
)
201 TagItems - pointer to an array of TagItems
204 BIDTAG_ViewPort (struct ViewPort *) - Viewport for which a mode is searched. Default: NULL
205 BIDTAG_MonitorID (ULONG) - Returned ID must use this monitor
206 BIDTAG_SourceID (ULONG) - Use this ModeID instead of a ViewPort.
207 DIPFMustHave mask is made up of the
208 ((DisplayInfo->PropertyFlags of this ID & SPECIAL_FLAGS) |
211 if BIDTAG_ViewPort was passed: VPModeID(vp), else the
212 DIPFMustHave and DIPFMustNotHave are unchanged.
213 BIDTAG_Depth (UBYTE) - Minimal depth. Default:
214 if BIDTAG_ViewPort is passed: vp->RasInfo->BitMap->Depth,
216 BIDTAG_NominalWidth (UWORD),
217 BIDTAG_NominalHeight (UWORD) - Aspect radio. Default:
218 if BIDTAG_SourceID: SourceID NominalDimensionInfo
219 if BIDTAG_ViewPort: vp->DWidth and vp->DHeight
221 BIDTAG_DesiredWidth (UWORD) - Width. Default: DIBTAG_NominalWidth.
222 BIDTAG_DesiredHeight (UWORD) - Height. Default: BIDTAG_NominalHeight.
223 BIDTAG_RedBits (UBYTE),
224 BIDTAG_GreenBits (UBYTE),
225 BIDTAG_BlueBits (UBYTE) - Bits per gun the mode must support. Default: 4
226 BIDTAG_DIPFMustHave (ULONG) - DIPF flags the resulting mode must have
227 BIDTAG_DIPFMustNotHave (ULONG) - DIPF flags the resulting mode must not have
230 ID - ID of the best mode to use, or INVALID_ID if a match
240 graphics/modeid.h, graphics/displayinfo.h
243 This function also processes CYBRBIDTG_BoardName tag. This is private
244 to AROS, do not rely on it!
248 ******************************************************************************/
252 struct TagItem
*tag
, *tstate
= TagItems
;
253 struct DisplayInfoHandle
*dinfo
;
254 struct DisplayInfo disp
;
255 struct DimensionInfo dims
;
256 struct monitor_driverdata
*monitor
;
257 struct ViewPort
*vp
= NULL
;
258 ULONG sourceid
= INVALID_ID
;
259 struct MatchData args
=
261 0, SPECIAL_FLAGS
, /* DIPF */
262 4, 4, 4, /* RGB bits */
264 INVALID_ID
, /* Monitor ID */
265 NULL
, /* Board name */
266 640, 480, /* Nominal size */
267 0, 0, /* Desired size */
268 INVALID_ID
, /* Found ID */
269 -1, /* Found depth */
270 -1, -1 /* Found size */
273 /* Obtain default monitor driver */
274 monitor
= MonitorFromSpec(GfxBase
->default_monitor
, GfxBase
);
276 FillNominal(GfxBase
, &args
);
279 /* Get defaults which can be overriden */
280 while ((tag
= NextTagItem(&tstate
)))
284 case BIDTAG_DIPFMustHave
:
285 args
.dipf_musthave
= tag
->ti_Data
;
288 case BIDTAG_DIPFMustNotHave
:
289 args
.dipf_mustnothave
= tag
->ti_Data
;
292 case BIDTAG_MonitorID
:
293 args
.monitorid
= tag
->ti_Data
;
297 args
.redbits
= tag
->ti_Data
;
300 case BIDTAG_BlueBits
:
301 args
.bluebits
= tag
->ti_Data
;
304 case BIDTAG_ViewPort
:
305 /* If we got ViewPort, obtain some more defaults from it */
306 vp
= (struct ViewPort
*)tag
->ti_Data
;
307 args
.nominal_width
= vp
->DWidth
;
308 args
.nominal_height
= vp
->DHeight
;
309 args
.depth
= GET_BM_DEPTH(vp
->RasInfo
->BitMap
);
310 sourceid
= GetVPModeID(vp
);
311 monitor
= GET_VP_DRIVERDATA(vp
);
314 /* Offer some help to cybergraphics.library */
315 case CYBRBIDTG_BoardName
:
316 args
.boardname
= (STRPTR
)tag
->ti_Data
;
321 /* Then process SourceID, it overrides ViewPort size and mode and specifies current monitor */
322 sourceid
= GetTagData(BIDTAG_SourceID
, sourceid
, TagItems
);
323 if (sourceid
!= INVALID_ID
)
325 /* Patch musthave flags */
326 if (GetDisplayInfoData(NULL
, (UBYTE
*)&disp
, sizeof(disp
), DTAG_DISP
, sourceid
) >= offsetof(struct DisplayInfo
, Resolution
))
327 args
.dipf_musthave
|= (disp
.PropertyFlags
& SPECIAL_FLAGS
);
331 /* Override monitor and nominal size from source ID only if there was no ViewPort specified */
332 dinfo
= FindDisplayInfo(sourceid
);
334 monitor
= dinfo
->drv
;
336 if (GetDisplayInfoData(dinfo
, (UBYTE
*)&dims
, sizeof(dims
), DTAG_DIMS
, sourceid
) >= offsetof(struct DimensionInfo
, MaxOScan
))
338 args
.nominal_width
= dims
.Nominal
.MaxX
- dims
.Nominal
.MinX
+ 1;
339 args
.nominal_height
= dims
.Nominal
.MaxY
- dims
.Nominal
.MinY
+ 1;
344 /* Get high-priority parameters */
345 args
.nominal_width
= GetTagData(BIDTAG_NominalWidth
, args
.nominal_width
, TagItems
);
346 args
.nominal_height
= GetTagData(BIDTAG_NominalHeight
, args
.nominal_height
, TagItems
);
347 args
.desired_width
= GetTagData(BIDTAG_DesiredWidth
, args
.nominal_width
, TagItems
);
348 args
.desired_height
= GetTagData(BIDTAG_DesiredHeight
, args
.nominal_height
, TagItems
);
349 args
.depth
= GetTagData(BIDTAG_Depth
, args
.depth
, TagItems
);
351 /* Exclude flags in MustHave from MustNotHave (CHECKME: if this correct?) */
352 args
.dipf_mustnothave
&= ~args
.dipf_musthave
;
354 D(bug("[BestModeIDA] Desired mode: %dx%dx%d, MonitorID 0x%08lX, MustHave 0x%08lX, MustNotHave 0x%08lX\n",
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("[BestModeIDA] Returning mode ID 0x%08lX\n", args
.found_id
));
384 return args
.found_id
;