2 * Copyright 2007-2010 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT license.
9 #include "accelerant.h"
11 #include <create_display_modes.h> // common accelerant header file
18 IsThereEnoughFBMemory(const display_mode
* mode
, uint32 bitsPerPixel
)
20 // Test if there is enough Frame Buffer memory for the mode and color depth
21 // specified by the caller, and return true if there is sufficient memory.
23 uint32 maxWidth
= mode
->virtual_width
;
24 if (mode
->timing
.h_display
> maxWidth
)
25 maxWidth
= mode
->timing
.h_display
;
27 uint32 maxHeight
= mode
->virtual_height
;
28 if (mode
->timing
.v_display
> maxHeight
)
29 maxHeight
= mode
->timing
.v_display
;
31 uint32 bytesPerPixel
= (bitsPerPixel
+ 7) / 8;
33 return (maxWidth
* maxHeight
* bytesPerPixel
34 < gInfo
.sharedInfo
->maxFrameBufferSize
);
39 IsModeUsable(const display_mode
* mode
)
41 // Test if the display mode is usable by the current video chip. That is,
42 // does the chip have enough memory for the mode and is the pixel clock
43 // within the chips allowable range, etc.
45 // Return true if the mode is usable.
47 SharedInfo
& si
= *gInfo
.sharedInfo
;
50 if (!TDFX_GetColorSpaceParams(mode
->space
, bitsPerPixel
))
53 // Is there enough frame buffer memory to handle the mode?
55 if (!IsThereEnoughFBMemory(mode
, bitsPerPixel
))
58 if (mode
->timing
.pixel_clock
> si
.maxPixelClock
)
61 // Is the color space supported?
63 bool colorSpaceSupported
= false;
64 for (uint32 j
= 0; j
< si
.colorSpaceCount
; j
++) {
65 if (mode
->space
== uint32(si
.colorSpaces
[j
])) {
66 colorSpaceSupported
= true;
71 if (!colorSpaceSupported
)
74 // In clock doubled mode for 3DFX chips, widths must be divisible by 16
77 if ((mode
->timing
.pixel_clock
> si
.maxPixelClock
/ 2)
78 && (mode
->timing
.h_display
% 16) != 0)
81 // Reject modes with a width of 640 and a height < 480 since they do not
82 // work properly with the 3DFX chipsets.
84 if (mode
->timing
.h_display
== 640 && mode
->timing
.v_display
< 480)
92 CreateModeList(bool (*checkMode
)(const display_mode
* mode
))
94 SharedInfo
& si
= *gInfo
.sharedInfo
;
96 // Obtain EDID info which is needed for for building the mode list. If
97 // function TDFX_GetEdidInfo() fails, no attempt is made to read the EDID
98 // info from the video BIOS since that always failed when attempted during
99 // the development of this driver.
101 si
.bHaveEDID
= TDFX_GetEdidInfo(si
.edidInfo
);
104 #ifdef ENABLE_DEBUG_TRACE
105 edid_dump(&(si
.edidInfo
));
108 TRACE("CreateModeList(); Unable to get EDID info\n");
115 listArea
= create_display_modes("3DFX modes",
116 si
.bHaveEDID
? &si
.edidInfo
: NULL
,
117 NULL
, 0, si
.colorSpaces
, si
.colorSpaceCount
,
118 (check_display_mode_hook
)checkMode
, &list
, &count
);
121 return listArea
; // listArea has error code
123 si
.modeArea
= gInfo
.modeListArea
= listArea
;
124 si
.modeCount
= count
;
125 gInfo
.modeList
= list
;
132 ProposeDisplayMode(display_mode
* target
, const display_mode
* low
,
133 const display_mode
* high
)
135 (void)low
; // avoid compiler warning for unused arg
136 (void)high
; // avoid compiler warning for unused arg
138 SharedInfo
& si
= *gInfo
.sharedInfo
;
140 TRACE("ProposeDisplayMode() %dx%d, pixel clock: %d kHz, space: 0x%X\n",
141 target
->timing
.h_display
, target
->timing
.v_display
,
142 target
->timing
.pixel_clock
, target
->space
);
144 // In clock doubled mode for 3DFX chips, widths must be divisible by 16
147 if ((target
->timing
.pixel_clock
> si
.maxPixelClock
/ 2)
148 && (target
->timing
.h_display
% 16) != 0)
151 // Search the mode list for the specified mode.
153 uint32 modeCount
= si
.modeCount
;
155 for (uint32 j
= 0; j
< modeCount
; j
++) {
156 display_mode
& mode
= gInfo
.modeList
[j
];
158 if (target
->timing
.h_display
== mode
.timing
.h_display
159 && target
->timing
.v_display
== mode
.timing
.v_display
160 && target
->space
== mode
.space
)
161 return B_OK
; // mode found in list
164 return B_BAD_VALUE
; // mode not found in list
169 SetDisplayMode(display_mode
* pMode
)
171 // First validate the mode, then call a function to set the registers.
173 TRACE("SetDisplayMode() begin\n");
175 SharedInfo
& si
= *gInfo
.sharedInfo
;
177 (display_mode
&)mode
= *pMode
;
179 if (!TDFX_GetColorSpaceParams(mode
.space
, mode
.bitsPerPixel
))
182 if (ProposeDisplayMode(&mode
, pMode
, pMode
) != B_OK
)
185 mode
.bytesPerPixel
= (mode
.bitsPerPixel
+ 7) / 8;
186 mode
.bytesPerRow
= mode
.timing
.h_display
* mode
.bytesPerPixel
;
188 // Is there enough frame buffer memory for this mode?
190 if ( ! IsThereEnoughFBMemory(&mode
, mode
.bitsPerPixel
))
193 TRACE("Set display mode: %dx%d virtual size: %dx%d "
194 "color depth: %d bits/pixel\n",
195 mode
.timing
.h_display
, mode
.timing
.v_display
,
196 mode
.virtual_width
, mode
.virtual_height
, mode
.bitsPerPixel
);
198 TRACE(" mode timing: %d %d %d %d %d %d %d %d %d\n",
199 mode
.timing
.pixel_clock
,
200 mode
.timing
.h_display
,
201 mode
.timing
.h_sync_start
, mode
.timing
.h_sync_end
,
203 mode
.timing
.v_display
,
204 mode
.timing
.v_sync_start
, mode
.timing
.v_sync_end
,
205 mode
.timing
.v_total
);
207 TRACE(" mode hFreq: %.1f kHz vFreq: %.1f Hz %chSync %cvSync\n",
208 double(mode
.timing
.pixel_clock
) / mode
.timing
.h_total
,
209 ((double(mode
.timing
.pixel_clock
) / mode
.timing
.h_total
) * 1000.0)
210 / mode
.timing
.v_total
,
211 (mode
.timing
.flags
& B_POSITIVE_HSYNC
) ? '+' : '-',
212 (mode
.timing
.flags
& B_POSITIVE_VSYNC
) ? '+' : '-');
214 status_t status
= TDFX_SetDisplayMode(mode
);
215 if (status
!= B_OK
) {
216 TRACE("SetDisplayMode() failed; status 0x%x\n", status
);
220 si
.displayMode
= mode
;
222 TRACE("SetDisplayMode() done\n");
228 MoveDisplay(uint16 horizontalStart
, uint16 verticalStart
)
230 // Set which pixel of the virtual frame buffer will show up in the
231 // top left corner of the display device. Used for page-flipping
232 // games and virtual desktops.
234 DisplayModeEx
& mode
= gInfo
.sharedInfo
->displayMode
;
236 if (mode
.timing
.h_display
+ horizontalStart
> mode
.virtual_width
237 || mode
.timing
.v_display
+ verticalStart
> mode
.virtual_height
)
240 mode
.h_display_start
= horizontalStart
;
241 mode
.v_display_start
= verticalStart
;
243 TDFX_AdjustFrame(mode
);
249 AccelerantModeCount(void)
251 // Return the number of display modes in the mode list.
253 return gInfo
.sharedInfo
->modeCount
;
258 GetModeList(display_mode
* dmList
)
260 // Copy the list of supported video modes to the location pointed at
263 memcpy(dmList
, gInfo
.modeList
,
264 gInfo
.sharedInfo
->modeCount
* sizeof(display_mode
));
270 GetDisplayMode(display_mode
* current_mode
)
272 *current_mode
= gInfo
.sharedInfo
->displayMode
; // return current display mode
278 GetFrameBufferConfig(frame_buffer_config
* pFBC
)
280 SharedInfo
& si
= *gInfo
.sharedInfo
;
282 pFBC
->frame_buffer
= (void*)((addr_t
)si
.videoMemAddr
283 + si
.frameBufferOffset
);
284 pFBC
->frame_buffer_dma
= (void*)((addr_t
)si
.videoMemPCI
285 + si
.frameBufferOffset
);
286 pFBC
->bytes_per_row
= si
.displayMode
.virtual_width
287 * si
.displayMode
.bytesPerPixel
;
294 GetPixelClockLimits(display_mode
* mode
, uint32
* low
, uint32
* high
)
296 // Return the maximum and minium pixel clock limits for the specified mode.
298 SharedInfo
& si
= *gInfo
.sharedInfo
;
301 if (!TDFX_GetColorSpaceParams(mode
->space
, bitsPerPixel
))
305 // lower limit of about 48Hz vertical refresh
306 uint32 totalClocks
= (uint32
)mode
->timing
.h_total
307 * (uint32
)mode
->timing
.v_total
;
308 uint32 lowClock
= (totalClocks
* 48L) / 1000L;
309 if (lowClock
> si
.maxPixelClock
)
316 // In clock doubled mode for 3DFX chips, widths must be divisible by 16
317 // instead of 8. If width is not divisible by 16, limit pixel clock to
318 // half of max pixel clock since divisor is 8 if pixel clock is < half
321 if ((mode
->timing
.h_display
% 16) != 0)
322 *high
= si
.maxPixelClock
/ 2;
324 *high
= si
.maxPixelClock
;
334 GetEdidInfo(void* info
, size_t size
, uint32
* _version
)
336 SharedInfo
& si
= *gInfo
.sharedInfo
;
341 if (size
< sizeof(struct edid1_info
))
342 return B_BUFFER_OVERFLOW
;
344 memcpy(info
, &si
.edidInfo
, sizeof(struct edid1_info
));
345 *_version
= EDID_VERSION_1
;