2 Copyright 2007-2009 Haiku, Inc. All rights reserved.
3 Distributed under the terms of the MIT license.
9 #include "accelerant.h"
14 #include <create_display_modes.h> // common accelerant header file
18 FindDisplayMode(int width
, int height
, int refreshRate
, uint32 colorDepth
)
20 // Search the mode list for the mode with specified width, height,
21 // refresh rate, and color depth. If argument colorDepth is zero, this
22 // function will search for a mode satisfying the other 3 arguments, and
23 // if more than one matching mode is found, the one with the greatest color
24 // depth will be selected.
26 // If successful, return a pointer to the selected display_mode object;
29 display_mode
* selectedMode
= NULL
;
30 uint32 modeCount
= gInfo
.sharedInfo
->modeCount
;
32 for (uint32 j
= 0; j
< modeCount
; j
++) {
33 display_mode
& mode
= gInfo
.modeList
[j
];
35 if (mode
.timing
.h_display
== width
&& mode
.timing
.v_display
== height
) {
36 int modeRefreshRate
= int(((mode
.timing
.pixel_clock
* 1000.0 /
37 mode
.timing
.h_total
) / mode
.timing
.v_total
) + 0.5);
38 if (modeRefreshRate
== refreshRate
) {
39 if (colorDepth
== 0) {
40 if (selectedMode
== NULL
|| mode
.space
> selectedMode
->space
)
43 if (mode
.space
== colorDepth
)
56 IsThereEnoughFBMemory(const display_mode
* mode
, uint32 bitsPerPixel
)
58 // Test if there is enough Frame Buffer memory for the mode and color depth
59 // specified by the caller, and return true if there is sufficient memory.
61 uint32 maxWidth
= mode
->virtual_width
;
62 if (mode
->timing
.h_display
> maxWidth
)
63 maxWidth
= mode
->timing
.h_display
;
65 uint32 maxHeight
= mode
->virtual_height
;
66 if (mode
->timing
.v_display
> maxHeight
)
67 maxHeight
= mode
->timing
.v_display
;
69 uint32 bytesPerPixel
= (bitsPerPixel
+ 7) / 8;
71 return (maxWidth
* maxHeight
* bytesPerPixel
< gInfo
.sharedInfo
->maxFrameBufferSize
);
77 GetVesaModeNumber(const display_mode
& mode
, uint8 bitsPerPixel
)
79 // Search VESA mode table for a matching mode, and return the VESA mode
80 // number if a match is found; else return 0 if no match is found.
82 SharedInfo
& si
= *gInfo
.sharedInfo
;
84 VesaMode
* vesaModeTable
= (VesaMode
*)((uint8
*)&si
+ si
.vesaModeTableOffset
);
86 for (uint32 j
= 0; j
< si
.vesaModeCount
; j
++) {
87 VesaMode
& vesaMode
= vesaModeTable
[j
];
89 if (vesaMode
.width
== mode
.timing
.h_display
90 && vesaMode
.height
== mode
.timing
.v_display
91 && vesaMode
.bitsPerPixel
== bitsPerPixel
)
95 return 0; // matching VESA mode not found
101 IsModeUsable(const display_mode
* mode
)
103 // Test if the display mode is usable by the current video chip. That is,
104 // does the chip have enough memory for the mode and is the pixel clock
105 // within the chips allowable range, etc.
107 // Return true if the mode is usable.
109 SharedInfo
& si
= *gInfo
.sharedInfo
;
111 uint32 maxPixelClock
;
113 if (!gInfo
.GetColorSpaceParams(mode
->space
, bitsPerPixel
, maxPixelClock
))
116 // Is there enough frame buffer memory to handle the mode?
118 if (!IsThereEnoughFBMemory(mode
, bitsPerPixel
))
121 if (si
.displayType
== MT_VGA
) {
122 // Test if mode is usable for a chip that is connected to a monitor
123 // via an analog VGA connector.
125 if (mode
->timing
.pixel_clock
> maxPixelClock
)
128 // Is the color space supported?
130 bool colorSpaceSupported
= false;
131 for (uint32 j
= 0; j
< si
.colorSpaceCount
; j
++) {
132 if (mode
->space
== uint32(si
.colorSpaces
[j
])) {
133 colorSpaceSupported
= true;
138 if (!colorSpaceSupported
)
141 // Reject modes with a width of 640 and a height < 480 since they do not
142 // work properly with the ATI chipsets.
144 if (mode
->timing
.h_display
== 640 && mode
->timing
.v_display
< 480)
147 // Test if mode is usable for a chip that is connected to a laptop LCD
148 // display or a monitor via a DVI interface.
150 // If chip is a Mach64 Mobility chip exclude 640x350 resolution since
151 // that resolution can not be set without a failure in the VESA set mode
154 if (si
.chipType
== MACH64_MOBILITY
&& mode
->timing
.h_display
== 640
155 && mode
->timing
.v_display
== 350)
158 // Search VESA mode table for matching mode.
160 if (GetVesaModeNumber(*mode
, bitsPerPixel
) == 0)
169 CreateModeList(bool (*checkMode
)(const display_mode
* mode
))
171 SharedInfo
& si
= *gInfo
.sharedInfo
;
173 // Obtain EDID info which is needed for for building the mode list.
174 // However, if a laptop's LCD display is active, bypass getting the EDID
175 // info since it is not needed, and if the external display supports only
176 // resolutions smaller than the size of the laptop LCD display, it would
177 // unnecessarily restrict size of the resolutions that could be set for
178 // laptop LCD display.
180 si
.bHaveEDID
= false;
182 if (si
.displayType
== MT_VGA
&& !si
.bHaveEDID
) {
183 edid1_raw rawEdid
; // raw EDID info to obtain
185 if (ioctl(gInfo
.deviceFileDesc
, ATI_GET_EDID
, &rawEdid
,
186 sizeof(rawEdid
)) == B_OK
) {
187 if (rawEdid
.version
.version
!= 1 || rawEdid
.version
.revision
> 4) {
188 TRACE("CreateModeList(); EDID version %d.%d out of range\n",
189 rawEdid
.version
.version
, rawEdid
.version
.revision
);
191 edid_decode(&si
.edidInfo
, &rawEdid
); // decode & save EDID info
197 #ifdef ENABLE_DEBUG_TRACE
198 edid_dump(&(si
.edidInfo
));
201 TRACE("CreateModeList(); Unable to get EDID info\n");
209 listArea
= create_display_modes("ATI modes",
210 si
.bHaveEDID
? &si
.edidInfo
: NULL
,
211 NULL
, 0, si
.colorSpaces
, si
.colorSpaceCount
,
212 (check_display_mode_hook
)checkMode
, &list
, &count
);
215 return listArea
; // listArea has error code
217 si
.modeArea
= gInfo
.modeListArea
= listArea
;
218 si
.modeCount
= count
;
219 gInfo
.modeList
= list
;
227 ProposeDisplayMode(display_mode
*target
, const display_mode
*low
,
228 const display_mode
*high
)
230 (void)low
; // avoid compiler warning for unused arg
231 (void)high
; // avoid compiler warning for unused arg
233 TRACE("ProposeDisplayMode() %dx%d, pixel clock: %d kHz, space: 0x%X\n",
234 target
->timing
.h_display
, target
->timing
.v_display
,
235 target
->timing
.pixel_clock
, target
->space
);
237 // Search the mode list for the specified mode.
239 uint32 modeCount
= gInfo
.sharedInfo
->modeCount
;
241 for (uint32 j
= 0; j
< modeCount
; j
++) {
242 display_mode
& mode
= gInfo
.modeList
[j
];
244 if (target
->timing
.h_display
== mode
.timing
.h_display
245 && target
->timing
.v_display
== mode
.timing
.v_display
246 && target
->space
== mode
.space
)
247 return B_OK
; // mode found in list
250 return B_BAD_VALUE
; // mode not found in list
255 SetDisplayMode(display_mode
* pMode
)
257 // First validate the mode, then call a function to set the registers.
259 TRACE("SetDisplayMode() begin\n");
261 SharedInfo
& si
= *gInfo
.sharedInfo
;
263 (display_mode
&)mode
= *pMode
;
265 uint32 maxPixelClock
;
266 if ( ! gInfo
.GetColorSpaceParams(mode
.space
, mode
.bitsPerPixel
, maxPixelClock
))
269 if (ProposeDisplayMode(&mode
, pMode
, pMode
) != B_OK
)
272 int bytesPerPixel
= (mode
.bitsPerPixel
+ 7) / 8;
273 mode
.bytesPerRow
= mode
.timing
.h_display
* bytesPerPixel
;
275 // Is there enough frame buffer memory for this mode?
277 if ( ! IsThereEnoughFBMemory(&mode
, mode
.bitsPerPixel
))
280 TRACE("Set display mode: %dx%d virtual size: %dx%d color depth: %d bits/pixel\n",
281 mode
.timing
.h_display
, mode
.timing
.v_display
,
282 mode
.virtual_width
, mode
.virtual_height
, mode
.bitsPerPixel
);
284 if (si
.displayType
== MT_VGA
) {
285 TRACE(" mode timing: %d %d %d %d %d %d %d %d %d\n",
286 mode
.timing
.pixel_clock
,
287 mode
.timing
.h_display
,
288 mode
.timing
.h_sync_start
, mode
.timing
.h_sync_end
,
290 mode
.timing
.v_display
,
291 mode
.timing
.v_sync_start
, mode
.timing
.v_sync_end
,
292 mode
.timing
.v_total
);
294 TRACE(" mode hFreq: %.1f kHz vFreq: %.1f Hz %chSync %cvSync\n",
295 double(mode
.timing
.pixel_clock
) / mode
.timing
.h_total
,
296 ((double(mode
.timing
.pixel_clock
) / mode
.timing
.h_total
) * 1000.0)
297 / mode
.timing
.v_total
,
298 (mode
.timing
.flags
& B_POSITIVE_HSYNC
) ? '+' : '-',
299 (mode
.timing
.flags
& B_POSITIVE_VSYNC
) ? '+' : '-');
302 status_t status
= gInfo
.SetDisplayMode(mode
);
303 if (status
!= B_OK
) {
304 TRACE("SetDisplayMode() failed; status 0x%x\n", status
);
308 si
.displayMode
= mode
;
310 TRACE("SetDisplayMode() done\n");
317 MoveDisplay(uint16 horizontalStart
, uint16 verticalStart
)
319 // Set which pixel of the virtual frame buffer will show up in the
320 // top left corner of the display device. Used for page-flipping
321 // games and virtual desktops.
323 DisplayModeEx
& mode
= gInfo
.sharedInfo
->displayMode
;
325 if (mode
.timing
.h_display
+ horizontalStart
> mode
.virtual_width
326 || mode
.timing
.v_display
+ verticalStart
> mode
.virtual_height
)
329 mode
.h_display_start
= horizontalStart
;
330 mode
.v_display_start
= verticalStart
;
332 gInfo
.AdjustFrame(mode
);
338 AccelerantModeCount(void)
340 // Return the number of display modes in the mode list.
342 return gInfo
.sharedInfo
->modeCount
;
347 GetModeList(display_mode
* dmList
)
349 // Copy the list of supported video modes to the location pointed at
352 memcpy(dmList
, gInfo
.modeList
, gInfo
.sharedInfo
->modeCount
* sizeof(display_mode
));
358 GetDisplayMode(display_mode
* current_mode
)
360 *current_mode
= gInfo
.sharedInfo
->displayMode
; // return current display mode
366 GetFrameBufferConfig(frame_buffer_config
* pFBC
)
368 SharedInfo
& si
= *gInfo
.sharedInfo
;
370 pFBC
->frame_buffer
= (void*)((addr_t
)si
.videoMemAddr
+ si
.frameBufferOffset
);
371 pFBC
->frame_buffer_dma
= (void*)((addr_t
)si
.videoMemPCI
+ si
.frameBufferOffset
);
372 uint32 bytesPerPixel
= (si
.displayMode
.bitsPerPixel
+ 7) / 8;
373 pFBC
->bytes_per_row
= si
.displayMode
.virtual_width
* bytesPerPixel
;
380 GetPixelClockLimits(display_mode
* mode
, uint32
* low
, uint32
* high
)
382 // Return the maximum and minium pixel clock limits for the specified mode.
385 uint32 maxPixelClock
;
387 if ( ! gInfo
.GetColorSpaceParams(mode
->space
, bitsPerPixel
, maxPixelClock
))
391 // lower limit of about 48Hz vertical refresh
392 uint32 totalClocks
= (uint32
)mode
->timing
.h_total
* (uint32
)mode
->timing
.v_total
;
393 uint32 lowClock
= (totalClocks
* 48L) / 1000L;
394 if (lowClock
> maxPixelClock
)
401 *high
= maxPixelClock
;
408 GetTimingConstraints(display_timing_constraints
*constraints
)
410 (void)constraints
; // avoid compiler warning for unused arg
417 GetPreferredDisplayMode(display_mode
* preferredMode
)
419 // If the chip is connected to a laptop LCD panel, find the mode with
420 // matching width and height, 60 Hz refresh rate, and greatest color depth.
422 SharedInfo
& si
= *gInfo
.sharedInfo
;
424 if (si
.displayType
== MT_LAPTOP
) {
425 display_mode
* mode
= FindDisplayMode(si
.panelX
, si
.panelY
, 60, 0);
428 *preferredMode
= *mode
;
438 GetEdidInfo(void* info
, size_t size
, uint32
* _version
)
440 SharedInfo
& si
= *gInfo
.sharedInfo
;
445 if (size
< sizeof(struct edid1_info
))
446 return B_BUFFER_OVERFLOW
;
448 memcpy(info
, &si
.edidInfo
, sizeof(struct edid1_info
));
449 *_version
= EDID_VERSION_1
;