Fixed support for vbcc
[AROS.git] / rom / graphics / getdisplayinfodata.c
blobde633d6ae5b9186e19bcc14a418e287000bf771d
1 /*
2 Copyright © 1995-2013, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Graphics function GetDisplayInfoData()
6 Lang: english
7 */
9 #include <aros/debug.h>
10 #include <proto/graphics.h>
11 #include <graphics/displayinfo.h>
12 #include <hidd/graphics.h>
13 #include <proto/oop.h>
14 #include <stdio.h>
15 #include <string.h>
17 #include "graphics_intern.h"
18 #include "compositor_driver.h"
19 #include "dispinfo.h"
21 /****************************************************************************************/
23 static const ULONG size_checks[] =
25 sizeof(struct DisplayInfo),
26 sizeof(struct DimensionInfo),
27 sizeof(struct MonitorInfo),
28 sizeof(struct NameInfo),
31 #define KNOWN_IDS 4
33 static ULONG check_sizes(ULONG tagID, ULONG size);
34 static UBYTE popcount(IPTR x);
36 #define DLONGSZ (sizeof (ULONG) * 2)
37 #define DTAG_TO_IDX(dtag) (((dtag) & 0x7FFFF000) >> 12)
40 * Resolution calculation rules.
42 * MonitorSpec:
43 * ratioh, ratiov - ratio between size of a 1084S and the current monitor
44 * (larger fractions are larger monitors, smaller are smaller)
46 * Screen Resolution:
47 * Since this is related to mouse ticks, it would make sense for this
48 * calculation to be a inverse relationship to overall DPI, instead of
49 * to the number of pixels in the display.
51 * Therefore, Screen Resolution would be calculated as:
53 * res.x = (1280 * 11 * ratioh / pixel_width) >> RATIO_FIXEDPART
54 * res.y = (1024 * 11 * ratiov / pixel_height) >> RATIO_FIXEDPART
56 * Screen DPI can be directly calculated from DrawInfo Resolution as:
58 * #define C_1084_WIDTH_CIN 104 // 10.4 " in centi-inches
59 * #define C_1084_HEIGHT_CIN 78 // 7.8 " in centi-inches
61 * dpi.x = (11 * 1280 * 10) / C_1084_WIDTH_CIN / res.x
62 * dpi.y = (11 * 1024 * 10) / C_1084_HEIGHT_CIN / res.y
64 * Screen DPC (dots per centimeter) is calculated as:
66 * #define C_1084_WIDTH_MM 264 // 10.4 " in mm
67 * #define C_1084_HEIGHT_MM 198 // 7.8 " in mm
69 * dpc.x = 11 * 1280 * 10 / C_1084_WIDTH_MM / res.x
70 * dpc.y = 11 * 1024 * 10 / C_1084_HEIGHT_MM / res.y
72 * Jason S. McMullan <jason.mcmullan@gmail.com>
74 static inline void CalcScreenResolution(Point *res, const struct MonitorSpec *mspc,
75 OOP_Object *sync, struct GfxBase *GfxBase)
77 IPTR width, height;
79 OOP_GetAttr(sync, aHidd_Sync_HDisp, &width);
80 OOP_GetAttr(sync, aHidd_Sync_VDisp, &height);
82 res->x = (1280 * 11 * mspc->ratioh / width ) >> RATIO_FIXEDPART;
83 res->y = (1024 * 11 * mspc->ratiov / height) >> RATIO_FIXEDPART;
86 /*****************************************************************************
88 NAME */
89 #include <proto/graphics.h>
91 AROS_LH5(ULONG, GetDisplayInfoData,
93 /* SYNOPSIS */
94 AROS_LHA(DisplayInfoHandle, handle, A0),
95 AROS_LHA(UBYTE *, buf, A1),
96 AROS_LHA(ULONG, size, D0),
97 AROS_LHA(ULONG, tagID, D1),
98 AROS_LHA(ULONG, ID, D2),
100 /* LOCATION */
101 struct GfxBase *, GfxBase, 126, Graphics)
103 /* FUNCTION
104 Fills buffer with information about displayinfo handle.
106 INPUTS
107 handle - displayinfo handle
108 buf - pointer to destination buffer
109 size - buffer size in bytes
110 tagID - data chunk type
111 DTAG_DISP (DisplayInfo)
112 DTAG_DIMS (DimensionInfo)
113 DTAG_MNTR (MonitorInfo)
114 DTAG_NAME (NameInfo)
115 ID - displayinfo identifier, optionally used if handle is NULL
117 RESULT
118 result - if positive, number of bytes actually transferred
119 if zero, no information for ID was available
121 NOTES
123 EXAMPLE
125 BUGS
127 SEE ALSO
128 FindDisplayInfo(), NextDisplayInfo(), graphics/displayinfo.h
130 INTERNALS
131 This function provides private data in reserved fields of DimensionInfo.
132 It is required by other AROS components. Please keep this in sync when
133 changing the code.
135 HISTORY
137 ******************************************************************************/
139 AROS_LIBFUNC_INIT
141 struct QueryHeader *qh;
142 ULONG structsize;
143 OOP_Object *gfxhidd, *sync, *pf;
144 HIDDT_ModeID hiddmode;
145 struct HIDD_ModeProperties HIDDProps = {0};
147 if (NULL == handle)
149 /* FindDisplayInfo() handles INVALID_ID itself */
150 handle = FindDisplayInfo(ID);
152 else
155 * ID is likely INVALID_ID, but we need its value.
156 * Get it from the handle.
158 ID = DIH(handle)->id | DIH(handle)->drv->id;
161 if (NULL == handle)
163 D(bug("!!! COULD NOT GET HANDLE IN GetDisplayInfoData()\n"));
164 return 0;
167 gfxhidd = DIH(handle)->drv->gfxhidd;
168 hiddmode = DIH(handle)->id;
170 /* Get mode info from the HIDD */
171 if (!HIDD_Gfx_GetMode(gfxhidd, hiddmode, &sync, &pf))
173 D(bug("NO VALID MODE PASSED TO GetDisplayInfoData() !!!\n"));
174 return 0;
177 D(bug("GetDisplayInfoData(handle=%d, tagID=%x)\n"
178 , (ULONG)handle, tagID));
180 /* Build the queryheader */
181 structsize = check_sizes(tagID, size);
182 if (!structsize)
183 return 0;
184 qh = AllocMem(structsize, MEMF_CLEAR);
185 if (!qh)
186 return 0;
188 /* Fill in the queryheader */
189 qh->StructID = tagID;
190 qh->DisplayID = ID;
191 qh->SkipID = TAG_SKIP;
193 qh->Length = (structsize + (DLONGSZ - 1)) / DLONGSZ;
195 switch (tagID)
197 case DTAG_DISP:
199 struct DisplayInfo *di;
200 const struct MonitorSpec *ms;
201 IPTR redmask, greenmask, bluemask;
202 IPTR val = 0;
204 HIDD_Gfx_ModeProperties(gfxhidd, hiddmode, &HIDDProps, sizeof(HIDDProps));
206 di = (struct DisplayInfo *)qh;
208 /* All modes returned from the HIDD are available */
209 di->NotAvailable = FALSE;
212 * Set the propertyflags. We always set DIPF_IS_SPRITES because we always emulate
213 * one sprite for mouse pointer.
215 di->PropertyFlags = DIPF_IS_SPRITES | HIDDProps.DisplayInfoFlags;
218 * Some more tweaks.
219 * All non-planar modes are considered Workbench-compatible. This is done
220 * for compatibility with existing RTG drivers which never set this flag themselves.
221 * This can be considered historical, in initial API design HIDD_Gfx_ModeProperties()
222 * did not exist at all and this flag was simply always set.
223 * In fact all modes can be considered Workbench-compatible. This flag is
224 * known to be used by original AmigaOS screenmode prefs program to filter out
225 * some modes. This program has many replacement which do not obey this flag,
226 * enabling opening Workbench on HAM screen for example.
227 * But we delegate setting this flag to the driver for planar modes. We do it
228 * for 100% compatibility of chipset driver. What if some m68k program has its own
229 * weird assumptions about this bit ?
230 * One more thing to note: we don't set DIPF_IS_FOREIGN bit. It is actually used
231 * only by Picasso96 and only for modes that are not graphics.library compatible.
232 * Many m68k RTG games rely on this flag not being set.
234 OOP_GetAttr(pf, aHidd_PixFmt_StdPixFmt, &val);
235 if (val != vHidd_StdPixFmt_Plane)
236 di->PropertyFlags |= DIPF_IS_WB;
238 /* Compute red green and blue bits */
239 OOP_GetAttr(pf, aHidd_PixFmt_RedMask, &redmask);
240 OOP_GetAttr(pf, aHidd_PixFmt_GreenMask, &greenmask);
241 OOP_GetAttr(pf, aHidd_PixFmt_BlueMask, &bluemask);
243 /* Use gcc builtin function */
244 /* weissms: do not use, can cause undefined symbol _GLOBAL_OFFSET_TABLE_
245 * should work if we use a real cross compiler with static libgcc
246 di->RedBits = __builtin_popcount(redmask);
247 di->GreenBits = __builtin_popcount(greenmask);
248 di->BlueBits = __builtin_popcount(bluemask);
251 di->RedBits = popcount(redmask);
252 di->GreenBits = popcount(greenmask);
253 di->BlueBits = popcount(bluemask);
256 * If number of colors is too large, PaletteRange is set to 65535.
257 * This is the behavior of original AmigaOS(tm).
259 val = 1 << (di->RedBits + di->GreenBits + di->BlueBits);
260 di->PaletteRange = (val > 65535) ? 65535 : val;
262 /* Display resolution in ticks */
263 OOP_GetAttr(sync, aHidd_Sync_MonitorSpec, (IPTR *)&ms);
264 CalcScreenResolution(&di->Resolution, ms, sync, GfxBase);
266 OOP_GetAttr(sync, aHidd_Sync_PixelClock, &val);
267 if (val)
268 di->PixelSpeed = 1000000000 / val;
271 * If the driver says it does not support sprites, we return one sprite.
272 * We emulate it by software in such a case because it's necessary for
273 * the mouse pointer.
275 di->NumStdSprites = (HIDDProps.DisplayInfoFlags & DIPF_IS_SPRITES) ? HIDDProps.NumHWSprites : 1;
277 /* At the moment sprites always have the same resolution as display */
278 di->SpriteResolution = di->Resolution;
281 AROS extensions to allow querying if a hidd bitmap can be displayed
282 via the display compositor, and to enable it.
283 e.g openscreen uses these to determine if a custombitmap may be displayed.
285 di->reserved[0] = (IPTR)compositor_IsBMCompositable;
286 di->reserved[1] = (IPTR)compositor_SetBMCompositable;
288 break;
291 case DTAG_DIMS:
293 struct DimensionInfo *di;
294 IPTR depth, width, height;
295 IPTR minwidth, minheight;
296 IPTR maxwidth, maxheight;
298 OOP_GetAttr(pf, aHidd_PixFmt_Depth, &depth);
299 OOP_GetAttr(sync, aHidd_Sync_HDisp, &width);
300 OOP_GetAttr(sync, aHidd_Sync_VDisp, &height);
301 OOP_GetAttr(sync, aHidd_Sync_HMin, &minwidth);
302 OOP_GetAttr(sync, aHidd_Sync_VMin, &minheight);
303 OOP_GetAttr(sync, aHidd_Sync_HMax, &maxwidth);
304 OOP_GetAttr(sync, aHidd_Sync_VMax, &maxheight);
306 di = (struct DimensionInfo *)qh;
307 di->MaxDepth = depth;
309 di->MinRasterWidth = minwidth;
310 di->MinRasterHeight = minheight;
311 di->MaxRasterWidth = maxwidth;
312 di->MaxRasterHeight = maxheight;
314 di->Nominal.MinX = 0;
315 di->Nominal.MinY = 0;
316 di->Nominal.MaxX = width - 1;
317 di->Nominal.MaxY = height - 1;
319 di->MaxOScan = di->Nominal;
320 di->VideoOScan = di->Nominal;
321 di->TxtOScan = di->Nominal;
322 di->StdOScan = di->Nominal;
324 * FIXME: our graphics subsystem does not have overscan API.
325 di->MaxOScan.MinX = di->Nominal.MinX;
326 di->MaxOScan.MinY = di->Nominal.MinY;
327 di->MaxOScan.MaxX = di->Nominal.MaxX;
328 di->MaxOScan.MaxY = di->Nominal.MaxY;
330 di->VideoOScan.MinX = di->Nominal.MinX;
331 di->VideoOScan.MinY = di->Nominal.MinY;
332 di->VideoOScan.MaxX = di->Nominal.MaxX;
333 di->VideoOScan.MaxY = di->Nominal.MaxY;
335 di->TxtOScan.MinX = di->Nominal.MinX;
336 di->TxtOScan.MinY = di->Nominal.MinY;
337 di->TxtOScan.MaxX = di->Nominal.MaxX;
338 di->TxtOScan.MaxY = di->Nominal.MaxY;
340 di->StdOScan.MinX = di->Nominal.MinX;
341 di->StdOScan.MinY = di->Nominal.MinY;
342 di->StdOScan.MaxX = di->Nominal.MaxX;
343 di->StdOScan.MaxY = di->Nominal.MaxY;
347 * reserved[0] is HIDD composition flags for intuition.library/OpenScreen().
348 * It can't be done in another way because only we (graphics.library) know about existence
349 * of software screen composition.
351 if (DIH(handle)->drv->compositor)
353 IPTR capabilities, state;
354 OOP_GetAttr(DIH(handle)->drv->compositor, aHidd_Compositor_Capabilities, &capabilities);
355 OOP_GetAttr(DIH(handle)->drv->compositor, aHidd_Compositor_State, &state);
356 di->reserved[0] = (capabilities << 16) | state;
358 else
360 HIDD_Gfx_ModeProperties(gfxhidd, hiddmode, &HIDDProps, sizeof(HIDDProps));
361 di->reserved[0] = (HIDDProps.CompositionFlags << 16) | HIDDProps.CompositionFlags;
364 /* This is for cybergraphics.library */
365 di->reserved[1] = (IPTR)pf;
367 break;
370 case DTAG_MNTR:
372 struct MonitorInfo *mi = (struct MonitorInfo *)qh;
374 OOP_GetAttr(sync, aHidd_Sync_MonitorSpec, (IPTR *)&mi->Mspc);
377 mi->ViewPosition.X = ?;
378 mi->ViewPosition.Y = ?;
379 mi->MinRow = ?;
380 mi->MouseTicks.X = ?;
381 mi->MouseTicks.Y = ?;
382 mi->DefaultViewPosition.X = ?;
383 mi->DefaultViewPosition.Y = ?;
386 /* Resolution in ticks */
387 CalcScreenResolution(&mi->ViewResolution, mi->Mspc, sync, GfxBase);
389 mi->TotalRows = mi->Mspc->total_rows;
390 mi->TotalColorClocks = mi->Mspc->total_colorclocks;
391 mi->ViewPositionRange = mi->Mspc->ms_LegalView;
394 * FIXME: For now we don't have a concept of preferred ModeID.
395 * However, see graphics_driver.c/driver_Setup(), it can be useful.
397 mi->PreferredModeID = ID;
399 if (DIH(handle)->drv->compositor)
402 * If we have software screen composition, we know we can compose.
403 * We use MCOMPAT_MIXED here because of changed understanding of what is "monitor".
404 * In AmigaOS(tm) a "monitor" is actually a sync (video mode). Different "monitors"
405 * are actually different modes of the same display (PAL, NTSC, VGA, etc).
406 * In AROS a "monitor" is a single physical display device. Of course we can do
407 * composition only on a single display, but we can compose together different
408 * syncs.
410 mi->Compatibility = MCOMPAT_MIXED;
412 else
414 /* Otherwise query the driver */
415 HIDD_Gfx_ModeProperties(gfxhidd, hiddmode, &HIDDProps, sizeof(HIDDProps));
417 if (HIDDProps.CompositionFlags)
418 mi->Compatibility = (HIDDProps.CompositionFlags & COMPF_SAME) ? MCOMPAT_SELF : MCOMPAT_MIXED;
419 else
420 mi->Compatibility = MCOMPAT_NOBODY;
423 break;
426 case DTAG_NAME:
428 struct NameInfo *ni;
429 IPTR depth, stdpixfmt;
430 STRPTR sync_description;
432 OOP_GetAttr(pf, aHidd_PixFmt_Depth, &depth);
433 OOP_GetAttr(pf, aHidd_PixFmt_StdPixFmt, &stdpixfmt);
435 OOP_GetAttr(sync, aHidd_Sync_Description, (IPTR *)&sync_description);
436 ni = (struct NameInfo *)qh;
438 if (sync_description && sync_description[0] &&
439 (IS_REAL_STDPIXFMT(stdpixfmt) || (stdpixfmt == vHidd_StdPixFmt_Unknown)))
441 STRPTR pixfmt_name = "";
443 switch(stdpixfmt)
445 case vHidd_StdPixFmt_RGB16:
446 case vHidd_StdPixFmt_RGB15:
447 case vHidd_StdPixFmt_RGB24:
448 pixfmt_name = "RGB";
449 break;
451 case vHidd_StdPixFmt_RGB16_LE:
452 case vHidd_StdPixFmt_RGB15_LE:
453 pixfmt_name = "RGB PC";
454 break;
456 case vHidd_StdPixFmt_BGR24:
457 case vHidd_StdPixFmt_BGR16:
458 case vHidd_StdPixFmt_BGR15:
459 pixfmt_name = "BGR";
460 break;
462 case vHidd_StdPixFmt_BGR16_LE:
463 case vHidd_StdPixFmt_BGR15_LE:
464 pixfmt_name = "BGR PC";
465 break;
467 case vHidd_StdPixFmt_ARGB32:
468 pixfmt_name = "ARGB";
469 break;
471 case vHidd_StdPixFmt_BGRA32:
472 pixfmt_name = "BGRA";
473 break;
475 case vHidd_StdPixFmt_RGBA32:
476 pixfmt_name = "RGBA";
477 break;
479 case vHidd_StdPixFmt_0RGB32:
480 pixfmt_name = "0RGB";
481 break;
483 case vHidd_StdPixFmt_BGR032:
484 pixfmt_name = "BGR0";
485 break;
487 case vHidd_StdPixFmt_RGB032:
488 pixfmt_name = "RGB0";
489 break;
492 if (stdpixfmt != vHidd_StdPixFmt_Plane)
493 snprintf(ni->Name, DISPLAYNAMELEN, "%s %2dbit %s",
494 sync_description, (int)depth, pixfmt_name);
495 else
496 strncpy(ni->Name, sync_description, DISPLAYNAMELEN);
498 else
500 IPTR width = 0;
501 IPTR height = 0;
503 OOP_GetAttr(sync, aHidd_Sync_HDisp, &width);
504 OOP_GetAttr(sync, aHidd_Sync_VDisp, &height);
505 snprintf(ni->Name, DISPLAYNAMELEN, "AROS: %ldx%ldx%ld", width, height, depth);
507 break;
510 default:
511 D(bug("!!! UNKNOWN tagID IN CALL TO GetDisplayInfoData() !!!\n"));
512 break;
515 D(bug("GDID: %d\n", structsize));
517 if (size > structsize)
518 size = structsize;
519 CopyMem(qh, buf, size);
520 FreeMem(qh, structsize);
521 /* NULL-terminate the name in case if it was trimmed */
522 if (tagID == DTAG_NAME)
523 buf[size - 1] = 0;
525 return size;
527 AROS_LIBFUNC_EXIT
529 } /* GetDisplayInfoData */
531 /****************************************************************************************/
533 static ULONG check_sizes(ULONG tagID, ULONG size)
535 ULONG idx;
537 idx = DTAG_TO_IDX(tagID);
539 if (idx > KNOWN_IDS)
541 D(bug("!!! INVALID tagID TO GetDisplayInfoData"));
542 return 0;
545 return size_checks[idx];
548 /* taken from http://en.wikipedia.org/wiki/Hamming_weight */
549 static UBYTE popcount(IPTR x) {
550 UBYTE count;
551 for (count=0; x; count++)
552 x &= x-1;
553 return count;