Documented GVF_SAVE_VAR alongside other flags, and removed a query/doubt
[AROS.git] / rom / graphics / bestmodeida.c
blobc8666c2b9d42e2a7c50f230a5f105f5c7722c525
1 /*
2 Copyright © 1995-2015, 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("[Gfx] %s: CYBRBIDTG_BoardName didn't match. '%s' != '%s'\n", __PRETTY_FUNCTION__, 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("[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));
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 /*****************************************************************************
170 NAME */
171 #include <proto/graphics.h>
173 AROS_LH1(ULONG, BestModeIDA,
175 /* SYNOPSIS */
176 AROS_LHA(struct TagItem *, TagItems, A0),
178 /* LOCATION */
179 struct GfxBase *, GfxBase, 175, Graphics)
181 /* FUNCTION
183 INPUTS
184 TagItems - pointer to an array of TagItems
186 TAGS
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) |
192 DIPFMustHave flags).
193 Default:
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,
198 else 1.
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
203 or 640 x 200.
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
212 RESULT
213 ID - ID of the best mode to use, or INVALID_ID if a match
214 could not be found
216 NOTES
218 EXAMPLE
220 BUGS
222 SEE ALSO
223 graphics/modeid.h, graphics/displayinfo.h
225 INTERNALS
226 This function also processes CYBRBIDTG_BoardName tag. This is private
227 to AROS, do not rely on it!
229 HISTORY
231 ******************************************************************************/
233 AROS_LIBFUNC_INIT
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 */
246 1, /* Depth */
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)))
264 switch (tag->ti_Tag)
266 case BIDTAG_DIPFMustHave:
267 args.dipf_musthave = tag->ti_Data;
268 break;
270 case BIDTAG_DIPFMustNotHave:
271 args.dipf_mustnothave = tag->ti_Data;
272 break;
274 case BIDTAG_MonitorID:
275 args.monitorid = tag->ti_Data;
276 break;
278 case BIDTAG_RedBits:
279 args.redbits = tag->ti_Data;
280 break;
282 case BIDTAG_BlueBits:
283 args.bluebits = tag->ti_Data;
284 break;
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);
294 break;
296 /* Offer some help to cybergraphics.library */
297 case CYBRBIDTG_BoardName:
298 args.boardname = (STRPTR)tag->ti_Data;
299 break;
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);
311 if (!vp)
313 /* Override monitor and nominal size from source ID only if there was no ViewPort specified */
314 dinfo = FindDisplayInfo(sourceid);
315 if (dinfo)
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);
345 else
347 // fallback to hardcoded values..
348 args.nominal_width = 640;
349 args.nominal_height = 480;
350 args.depth = 1;
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);
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("[Gfx] %s: Returning mode ID 0x%08lX\n", __PRETTY_FUNCTION__, args.found_id));
384 return args.found_id;
386 AROS_LIBFUNC_EXIT
387 } /* BestModeIDA */