debug.library: use quick sort to sort the segments
[AROS.git] / rom / graphics / bestmodeida.c
blob6a70322ab30c04736def802f8871a65cd41cebf9
1 /*
2 Copyright © 1995-2013, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Graphics function BestModeIDA()
6 Lang: english
7 */
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>
17 #include <stddef.h>
19 #include "graphics_intern.h"
20 #include "gfxfuncsupport.h"
21 #include "dispinfo.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.
28 struct MatchData
30 /* Arguments */
31 ULONG dipf_musthave;
32 ULONG dipf_mustnothave;
33 UBYTE redbits;
34 UBYTE greenbits;
35 UBYTE bluebits;
36 UBYTE depth;
37 ULONG monitorid;
38 STRPTR boardname;
39 UWORD nominal_width;
40 UWORD nominal_height;
41 UWORD desired_width;
42 UWORD desired_height;
43 /* Results */
44 ULONG found_id;
45 UWORD found_depth;
46 UWORD found_width;
47 UWORD found_height;
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;
56 if (args->boardname)
58 STRPTR name;
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));
63 return;
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));
77 continue;
80 if (GetDisplayInfoData(dinfo, (UBYTE *)&disp, sizeof(disp), DTAG_DISP, modeid) < offsetof(struct DisplayInfo, pad2))
82 D(bug("No DisplayInfo!\n"));
83 continue;
86 /* Filter out not available modes */
87 if (disp.NotAvailable)
89 D(bug("Not available: %u\n", disp.NotAvailable));
90 continue;
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));
97 continue;
99 if ((disp.PropertyFlags & args->dipf_musthave) != args->dipf_musthave)
101 D(bug("Does not have MustHave flags: 0x%08lX\n", disp.PropertyFlags));
102 continue;
105 if (GetDisplayInfoData(dinfo, (UBYTE *)&dims, sizeof(dims), DTAG_DIMS, modeid) < offsetof(struct DimensionInfo, MaxOScan))
107 D(bug("No DimensionInfo!\n"));
108 continue;
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;
139 D(bug(" Match!\n"));
143 D(bug("\n"));
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) */
151 if (monitor)
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)
161 if (mdd != monitor)
162 BestModeIDForMonitor(mdd, args, modemask, GfxBase);
165 return args->found_id != INVALID_ID;
168 #ifdef __mc68000
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 */
177 return;
179 /* Chipset only: set PAL/NTSC defaults */
180 args->nominal_width = GfxBase->NormalDisplayColumns;
181 args->nominal_height = GfxBase->NormalDisplayRows;
183 #endif
185 /*****************************************************************************
187 NAME */
188 #include <proto/graphics.h>
190 AROS_LH1(ULONG, BestModeIDA,
192 /* SYNOPSIS */
193 AROS_LHA(struct TagItem *, TagItems, A0),
195 /* LOCATION */
196 struct GfxBase *, GfxBase, 175, Graphics)
198 /* FUNCTION
200 INPUTS
201 TagItems - pointer to an array of TagItems
203 TAGS
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) |
209 DIPFMustHave flags).
210 Default:
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,
215 else 1.
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
220 or 640 x 200.
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
229 RESULT
230 ID - ID of the best mode to use, or INVALID_ID if a match
231 could not be found
233 NOTES
235 EXAMPLE
237 BUGS
239 SEE ALSO
240 graphics/modeid.h, graphics/displayinfo.h
242 INTERNALS
243 This function also processes CYBRBIDTG_BoardName tag. This is private
244 to AROS, do not rely on it!
246 HISTORY
248 ******************************************************************************/
250 AROS_LIBFUNC_INIT
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 */
263 1, /* Depth */
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);
275 #ifdef __mc68000
276 FillNominal(GfxBase, &args);
277 #endif
279 /* Get defaults which can be overriden */
280 while ((tag = NextTagItem(&tstate)))
282 switch (tag->ti_Tag)
284 case BIDTAG_DIPFMustHave:
285 args.dipf_musthave = tag->ti_Data;
286 break;
288 case BIDTAG_DIPFMustNotHave:
289 args.dipf_mustnothave = tag->ti_Data;
290 break;
292 case BIDTAG_MonitorID:
293 args.monitorid = tag->ti_Data;
294 break;
296 case BIDTAG_RedBits:
297 args.redbits = tag->ti_Data;
298 break;
300 case BIDTAG_BlueBits:
301 args.bluebits = tag->ti_Data;
302 break;
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);
312 break;
314 /* Offer some help to cybergraphics.library */
315 case CYBRBIDTG_BoardName:
316 args.boardname = (STRPTR)tag->ti_Data;
317 break;
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);
329 if (!vp)
331 /* Override monitor and nominal size from source ID only if there was no ViewPort specified */
332 dinfo = FindDisplayInfo(sourceid);
333 if (dinfo)
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);
362 #ifdef __mc68000
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);
372 #endif
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;
386 AROS_LIBFUNC_EXIT
387 } /* BestModeIDA */