2 Copyright © 1995-2013, The AROS Development Team. All rights reserved.
5 Desc: Graphics function GetDisplayInfoData()
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>
17 #include "graphics_intern.h"
18 #include "compositing_driver.h"
21 /****************************************************************************************/
23 static const ULONG size_checks
[] =
25 sizeof(struct DisplayInfo
),
26 sizeof(struct DimensionInfo
),
27 sizeof(struct MonitorInfo
),
28 sizeof(struct NameInfo
),
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.
43 * ratioh, ratiov - ratio between size of a 1084S and the current monitor
44 * (larger fractions are larger monitors, smaller are smaller)
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
)
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 /*****************************************************************************
89 #include <proto/graphics.h>
91 AROS_LH5(ULONG
, GetDisplayInfoData
,
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
),
101 struct GfxBase
*, GfxBase
, 126, Graphics
)
104 Fills buffer with information about displayinfo handle.
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)
115 ID - displayinfo identifier, optionally used if handle is NULL
118 result - if positive, number of bytes actually transferred
119 if zero, no information for ID was available
128 FindDisplayInfo(), NextDisplayInfo(), graphics/displayinfo.h
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
137 ******************************************************************************/
141 struct QueryHeader
*qh
;
143 OOP_Object
*gfxhidd
, *sync
, *pf
;
144 HIDDT_ModeID hiddmode
;
145 struct HIDD_ModeProperties HIDDProps
= {0};
149 /* FindDisplayInfo() handles INVALID_ID itself */
150 handle
= FindDisplayInfo(ID
);
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
;
163 D(bug("!!! COULD NOT GET HANDLE IN GetDisplayInfoData()\n"));
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"));
177 D(bug("GetDisplayInfoData(handle=%d, tagID=%x)\n"
178 , (ULONG
)handle
, tagID
));
180 /* Build the queryheader */
181 structsize
= check_sizes(tagID
, size
);
184 qh
= AllocMem(structsize
, MEMF_CLEAR
);
188 /* Fill in the queryheader */
189 qh
->StructID
= tagID
;
191 qh
->SkipID
= TAG_SKIP
;
193 qh
->Length
= (structsize
+ (DLONGSZ
- 1)) / DLONGSZ
;
199 struct DisplayInfo
*di
;
200 const struct MonitorSpec
*ms
;
201 IPTR redmask
, greenmask
, bluemask
;
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
;
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
= 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
);
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
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
;
285 struct DimensionInfo
*di
;
286 IPTR depth
, width
, height
;
287 IPTR minwidth
, minheight
;
288 IPTR maxwidth
, maxheight
;
290 OOP_GetAttr(pf
, aHidd_PixFmt_Depth
, &depth
);
291 OOP_GetAttr(sync
, aHidd_Sync_HDisp
, &width
);
292 OOP_GetAttr(sync
, aHidd_Sync_VDisp
, &height
);
293 OOP_GetAttr(sync
, aHidd_Sync_HMin
, &minwidth
);
294 OOP_GetAttr(sync
, aHidd_Sync_VMin
, &minheight
);
295 OOP_GetAttr(sync
, aHidd_Sync_HMax
, &maxwidth
);
296 OOP_GetAttr(sync
, aHidd_Sync_VMax
, &maxheight
);
298 di
= (struct DimensionInfo
*)qh
;
299 di
->MaxDepth
= depth
;
301 di
->MinRasterWidth
= minwidth
;
302 di
->MinRasterHeight
= minheight
;
303 di
->MaxRasterWidth
= maxwidth
;
304 di
->MaxRasterHeight
= maxheight
;
306 di
->Nominal
.MinX
= 0;
307 di
->Nominal
.MinY
= 0;
308 di
->Nominal
.MaxX
= width
- 1;
309 di
->Nominal
.MaxY
= height
- 1;
311 di
->MaxOScan
= di
->Nominal
;
312 di
->VideoOScan
= di
->Nominal
;
313 di
->TxtOScan
= di
->Nominal
;
314 di
->StdOScan
= di
->Nominal
;
316 * FIXME: our graphics subsystem does not have overscan API.
317 di->MaxOScan.MinX = di->Nominal.MinX;
318 di->MaxOScan.MinY = di->Nominal.MinY;
319 di->MaxOScan.MaxX = di->Nominal.MaxX;
320 di->MaxOScan.MaxY = di->Nominal.MaxY;
322 di->VideoOScan.MinX = di->Nominal.MinX;
323 di->VideoOScan.MinY = di->Nominal.MinY;
324 di->VideoOScan.MaxX = di->Nominal.MaxX;
325 di->VideoOScan.MaxY = di->Nominal.MaxY;
327 di->TxtOScan.MinX = di->Nominal.MinX;
328 di->TxtOScan.MinY = di->Nominal.MinY;
329 di->TxtOScan.MaxX = di->Nominal.MaxX;
330 di->TxtOScan.MaxY = di->Nominal.MaxY;
332 di->StdOScan.MinX = di->Nominal.MinX;
333 di->StdOScan.MinY = di->Nominal.MinY;
334 di->StdOScan.MaxX = di->Nominal.MaxX;
335 di->StdOScan.MaxY = di->Nominal.MaxY;
339 * reserved[0] is HIDD composition flags for intuition.library/OpenScreen().
340 * It can't be done in another way because only we (graphics.library) know about existence
341 * of software screen composition.
343 if (DIH(handle
)->drv
->composer
)
345 OOP_GetAttr(DIH(handle
)->drv
->composer
, aHidd_Compositing_Capabilities
, &di
->reserved
[0]);
349 HIDD_Gfx_ModeProperties(gfxhidd
, hiddmode
, &HIDDProps
, sizeof(HIDDProps
));
350 di
->reserved
[0] = HIDDProps
.CompositionFlags
;
353 /* This is for cybergraphics.library */
354 di
->reserved
[1] = (IPTR
)pf
;
361 struct MonitorInfo
*mi
= (struct MonitorInfo
*)qh
;
363 OOP_GetAttr(sync
, aHidd_Sync_MonitorSpec
, (IPTR
*)&mi
->Mspc
);
366 mi->ViewPosition.X = ?;
367 mi->ViewPosition.Y = ?;
369 mi->MouseTicks.X = ?;
370 mi->MouseTicks.Y = ?;
371 mi->DefaultViewPosition.X = ?;
372 mi->DefaultViewPosition.Y = ?;
375 /* Resolution in ticks */
376 CalcScreenResolution(&mi
->ViewResolution
, mi
->Mspc
, sync
, GfxBase
);
378 mi
->TotalRows
= mi
->Mspc
->total_rows
;
379 mi
->TotalColorClocks
= mi
->Mspc
->total_colorclocks
;
380 mi
->ViewPositionRange
= mi
->Mspc
->ms_LegalView
;
383 * FIXME: For now we don't have a concept of preferred ModeID.
384 * However, see graphics_driver.c/driver_Setup(), it can be useful.
386 mi
->PreferredModeID
= ID
;
388 if (DIH(handle
)->drv
->composer
)
391 * If we have software screen composition, we know we can compose.
392 * We use MCOMPAT_MIXED here because of changed understanding of what is "monitor".
393 * In AmigaOS(tm) a "monitor" is actually a sync (video mode). Different "monitors"
394 * are actually different modes of the same display (PAL, NTSC, VGA, etc).
395 * In AROS a "monitor" is a single physical display device. Of course we can do
396 * composition only on a single display, but we can compose together different
399 mi
->Compatibility
= MCOMPAT_MIXED
;
403 /* Otherwise query the driver */
404 HIDD_Gfx_ModeProperties(gfxhidd
, hiddmode
, &HIDDProps
, sizeof(HIDDProps
));
406 if (HIDDProps
.CompositionFlags
)
407 mi
->Compatibility
= (HIDDProps
.CompositionFlags
& COMPF_SAME
) ? MCOMPAT_SELF
: MCOMPAT_MIXED
;
409 mi
->Compatibility
= MCOMPAT_NOBODY
;
418 IPTR depth
, stdpixfmt
;
419 STRPTR sync_description
;
421 OOP_GetAttr(pf
, aHidd_PixFmt_Depth
, &depth
);
422 OOP_GetAttr(pf
, aHidd_PixFmt_StdPixFmt
, &stdpixfmt
);
424 OOP_GetAttr(sync
, aHidd_Sync_Description
, (IPTR
*)&sync_description
);
425 ni
= (struct NameInfo
*)qh
;
427 if (sync_description
&& sync_description
[0] &&
428 (IS_REAL_STDPIXFMT(stdpixfmt
) || (stdpixfmt
== vHidd_StdPixFmt_Unknown
)))
430 STRPTR pixfmt_name
= "";
434 case vHidd_StdPixFmt_RGB16
:
435 case vHidd_StdPixFmt_RGB15
:
436 case vHidd_StdPixFmt_RGB24
:
440 case vHidd_StdPixFmt_RGB16_LE
:
441 case vHidd_StdPixFmt_RGB15_LE
:
442 pixfmt_name
= "RGB PC";
445 case vHidd_StdPixFmt_BGR24
:
446 case vHidd_StdPixFmt_BGR16
:
447 case vHidd_StdPixFmt_BGR15
:
451 case vHidd_StdPixFmt_BGR16_LE
:
452 case vHidd_StdPixFmt_BGR15_LE
:
453 pixfmt_name
= "BGR PC";
456 case vHidd_StdPixFmt_ARGB32
:
457 pixfmt_name
= "ARGB";
460 case vHidd_StdPixFmt_BGRA32
:
461 pixfmt_name
= "BGRA";
464 case vHidd_StdPixFmt_RGBA32
:
465 pixfmt_name
= "RGBA";
468 case vHidd_StdPixFmt_0RGB32
:
469 pixfmt_name
= "0RGB";
472 case vHidd_StdPixFmt_BGR032
:
473 pixfmt_name
= "BGR0";
476 case vHidd_StdPixFmt_RGB032
:
477 pixfmt_name
= "RGB0";
481 if (stdpixfmt
!= vHidd_StdPixFmt_Plane
)
482 snprintf(ni
->Name
, DISPLAYNAMELEN
, "%s %2dbit %s",
483 sync_description
, (int)depth
, pixfmt_name
);
485 strncpy(ni
->Name
, sync_description
, DISPLAYNAMELEN
);
492 OOP_GetAttr(sync
, aHidd_Sync_HDisp
, &width
);
493 OOP_GetAttr(sync
, aHidd_Sync_VDisp
, &height
);
494 snprintf(ni
->Name
, DISPLAYNAMELEN
, "AROS: %ldx%ldx%ld", width
, height
, depth
);
500 D(bug("!!! UNKNOWN tagID IN CALL TO GetDisplayInfoData() !!!\n"));
504 D(bug("GDID: %d\n", structsize
));
506 if (size
> structsize
)
508 CopyMem(qh
, buf
, size
);
509 FreeMem(qh
, structsize
);
510 /* NULL-terminate the name in case if it was trimmed */
511 if (tagID
== DTAG_NAME
)
518 } /* GetDisplayInfoData */
520 /****************************************************************************************/
522 static ULONG
check_sizes(ULONG tagID
, ULONG size
)
526 idx
= DTAG_TO_IDX(tagID
);
530 D(bug("!!! INVALID tagID TO GetDisplayInfoData"));
534 return size_checks
[idx
];
537 /* taken from http://en.wikipedia.org/wiki/Hamming_weight */
538 static UBYTE
popcount(IPTR x
) {
540 for (count
=0; x
; count
++)