2 Copyright 1999, Be Incorporated. All Rights Reserved.
3 This file may be used under the terms of the Be Sample Code License.
5 Other authors for NV driver:
7 Rudolf Cornelissen 9/2002-1/2016
10 #define MODULE_BIT 0x00400000
14 #define T_POSITIVE_SYNC (B_POSITIVE_HSYNC | B_POSITIVE_VSYNC)
15 /* mode flags will be setup as status info by PROPOSEMODE! */
17 #define MODE_COUNT (sizeof (mode_list) / sizeof (display_mode))
19 /* Standard VESA modes,
20 * plus panel specific resolution modes which are internally modified during run-time depending on the requirements of the actual
21 * panel connected. The modes as listed here, should timing-wise be as compatible with analog (CRT) monitors as can be... */
22 //fixme: if EDID monitor found create list via common EDID code...
23 static const display_mode mode_list
[] = {
24 /* 4:3 modes; 307.2k pixels */
25 { { 25175, 640, 656, 752, 800, 480, 490, 492, 525, 0}, B_CMAP8
, 640, 480, 0, 0, MODE_FLAGS
}, /* Vesa_Monitor_@60Hz_(640X480X8.Z1) */
26 { { 27500, 640, 672, 768, 864, 480, 488, 494, 530, 0}, B_CMAP8
, 640, 480, 0, 0, MODE_FLAGS
}, /* 640X480X60Hz */
27 { { 30500, 640, 672, 768, 864, 480, 517, 523, 588, 0}, B_CMAP8
, 640, 480, 0, 0, MODE_FLAGS
}, /* SVGA_640X480X60HzNI */
28 { { 31500, 640, 664, 704, 832, 480, 489, 492, 520, 0}, B_CMAP8
, 640, 480, 0, 0, MODE_FLAGS
}, /* Vesa_Monitor_@70-72Hz_(640X480X8.Z1) */
29 { { 31500, 640, 656, 720, 840, 480, 481, 484, 500, 0}, B_CMAP8
, 640, 480, 0, 0, MODE_FLAGS
}, /* Vesa_Monitor_@75Hz_(640X480X8.Z1) */
30 { { 36000, 640, 696, 752, 832, 480, 481, 484, 509, 0}, B_CMAP8
, 640, 480, 0, 0, MODE_FLAGS
}, /* Vesa_Monitor_@85Hz_(640X480X8.Z1) */
31 /* 4:3 modes; 480k pixels */
32 { { 36000, 800, 824, 896, 1024, 600, 601, 603, 625, 0}, B_CMAP8
, 800, 600, 0, 0, MODE_FLAGS
}, /* Vesa_Monitor_@56Hz_(800X600) from Be, Inc. driver + XFree86 */
33 { { 38100, 800, 832, 960, 1088, 600, 602, 606, 620, 0}, B_CMAP8
, 800, 600, 0, 0, MODE_FLAGS
}, /* SVGA_800X600X56HzNI */
34 { { 40000, 800, 840, 968, 1056, 600, 601, 605, 628, T_POSITIVE_SYNC
}, B_CMAP8
, 800, 600, 0, 0, MODE_FLAGS
}, /* Vesa_Monitor_@60Hz_(800X600X8.Z1) + XFree86 */
35 { { 49500, 800, 816, 896, 1056, 600, 601, 604, 625, T_POSITIVE_SYNC
}, B_CMAP8
, 800, 600, 0, 0, MODE_FLAGS
}, /* Vesa_Monitor_@75Hz_(800X600X8.Z1) + XFree86 */
36 { { 50000, 800, 856, 976, 1040, 600, 637, 643, 666, T_POSITIVE_SYNC
}, B_CMAP8
, 800, 600, 0, 0, MODE_FLAGS
}, /* Vesa_Monitor_@70-72Hz_(800X600X8.Z1) + XFree86 */
37 { { 56250, 800, 832, 896, 1048, 600, 601, 604, 631, T_POSITIVE_SYNC
}, B_CMAP8
, 800, 600, 0, 0, MODE_FLAGS
}, /* Vesa_Monitor_@85Hz_(800X600X8.Z1) + XFree86 */
38 /* 4:3 modes; 786.432k pixels */
39 { { 65000, 1024, 1048, 1184, 1344, 768, 771, 777, 806, 0}, B_CMAP8
, 1024, 768, 0, 0, MODE_FLAGS
}, /* Vesa_Monitor_@60Hz_(1024X768X8.Z1) + XFree86 */
40 { { 75000, 1024, 1048, 1184, 1328, 768, 771, 777, 806, 0}, B_CMAP8
, 1024, 768, 0, 0, MODE_FLAGS
}, /* Vesa_Monitor_@70-72Hz_(1024X768X8.Z1) + XFree86 */
41 { { 78750, 1024, 1040, 1136, 1312, 768, 769, 772, 800, T_POSITIVE_SYNC
}, B_CMAP8
, 1024, 768, 0, 0, MODE_FLAGS
}, /* Vesa_Monitor_@75Hz_(1024X768X8.Z1) + XFree86 */
42 { { 94500, 1024, 1072, 1168, 1376, 768, 769, 772, 808, T_POSITIVE_SYNC
}, B_CMAP8
, 1024, 768, 0, 0, MODE_FLAGS
}, /* Vesa_Monitor_@85Hz_(1024X768X8.Z1) + XFree86 */
43 /* 4:3 modes; 995.328k pixels */
44 { { 94200, 1152, 1184, 1280, 1472, 864, 865, 868, 914, T_POSITIVE_SYNC
}, B_CMAP8
, 1152, 864, 0, 0, MODE_FLAGS
}, /* Vesa_Monitor_@70Hz_(1152X864X8.Z1) */
45 { { 97800, 1152, 1216, 1344, 1552, 864, 865, 868, 900, T_POSITIVE_SYNC
}, B_CMAP8
, 1152, 864, 0, 0, MODE_FLAGS
}, /* Vesa_Monitor_@70Hz_(1152X864X8.Z1) */
46 { { 108000, 1152, 1216, 1344, 1600, 864, 865, 868, 900, T_POSITIVE_SYNC
}, B_CMAP8
, 1152, 864, 0, 0, MODE_FLAGS
}, /* Vesa_Monitor_@75Hz_(1152X864X8.Z1) + XFree86 */
47 { { 121500, 1152, 1216, 1344, 1568, 864, 865, 868, 911, T_POSITIVE_SYNC
}, B_CMAP8
, 1152, 864, 0, 0, MODE_FLAGS
}, /* Vesa_Monitor_@85Hz_(1152X864X8.Z1) */
48 /* 5:4 modes; 1.311M pixels */
49 { { 108000, 1280, 1328, 1440, 1688, 1024, 1025, 1028, 1066, T_POSITIVE_SYNC
}, B_CMAP8
, 1280, 1024, 0, 0, MODE_FLAGS
}, /* Vesa_Monitor_@60Hz_(1280X1024) from Be, Inc. driver + XFree86 */
50 { { 135000, 1280, 1296, 1440, 1688, 1024, 1025, 1028, 1066, T_POSITIVE_SYNC
}, B_CMAP8
, 1280, 1024, 0, 0, MODE_FLAGS
}, /* Vesa_Monitor_@75Hz_(1280X1024X8.Z1) + XFree86 */
51 { { 157500, 1280, 1344, 1504, 1728, 1024, 1025, 1028, 1072, T_POSITIVE_SYNC
}, B_CMAP8
, 1280, 1024, 0, 0, MODE_FLAGS
}, /* Vesa_Monitor_@85Hz_(1280X1024X8.Z1) + XFree86 */
52 /* 4:3 panel mode; 1.47M pixels */
53 { { 122600, 1400, 1488, 1640, 1880, 1050, 1051, 1054, 1087, T_POSITIVE_SYNC
}, B_CMAP8
, 1400, 1050, 0, 0, MODE_FLAGS
}, /* Vesa_Monitor_@60Hz_(1400X1050) */
54 /* 4:3 modes; 1.92M pixels */
55 { { 162000, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC
}, B_CMAP8
, 1600, 1200, 0, 0, MODE_FLAGS
}, /* Vesa_Monitor_@60Hz_(1600X1200X8.Z1) + XFree86 */
56 /* identical lines to above one, apart from refreshrate.. */
57 { { 175500, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC
}, B_CMAP8
, 1600, 1200, 0, 0, MODE_FLAGS
}, /* Vesa_Monitor_@65Hz_(1600X1200X8.Z1) + XFree86 */
58 { { 189000, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC
}, B_CMAP8
, 1600, 1200, 0, 0, MODE_FLAGS
}, /* Vesa_Monitor_@70Hz_(1600X1200X8.Z1) + XFree86 */
59 { { 202500, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC
}, B_CMAP8
, 1600, 1200, 0, 0, MODE_FLAGS
}, /* Vesa_Monitor_@75Hz_(1600X1200X8.Z1) + XFree86 */
60 { { 216000, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC
}, B_CMAP8
, 1600, 1200, 0, 0, MODE_FLAGS
}, /* Vesa_Monitor_@80Hz_(1600X1200X8.Z1) */
61 { { 229500, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC
}, B_CMAP8
, 1600, 1200, 0, 0, MODE_FLAGS
}, /* Vesa_Monitor_@85Hz_(1600X1200X8.Z1) + XFree86 */
62 /* end identical lines. */
63 /* 4:3 modes; 2.408M pixels */
64 { { 204750, 1792, 1920, 2120, 2448, 1344, 1345, 1348, 1394, B_POSITIVE_VSYNC
}, B_CMAP8
, 1792, 1344, 0, 0, MODE_FLAGS
}, /* Vesa_Monitor_@60Hz_(1792X1344) from Be, Inc. driver + XFree86 */
65 { { 261000, 1792, 1888, 2104, 2456, 1344, 1345, 1348, 1417, B_POSITIVE_VSYNC
}, B_CMAP8
, 1792, 1344, 0, 0, MODE_FLAGS
}, /* Vesa_Monitor_@75Hz_(1792X1344) from Be, Inc. driver + XFree86 */
66 /* 4:3 modes; 2.584M pixels */
67 { { 218250, 1856, 1952, 2176, 2528, 1392, 1393, 1396, 1439, B_POSITIVE_VSYNC
}, B_CMAP8
, 1856, 1392, 0, 0, MODE_FLAGS
}, /* Vesa_Monitor_@60Hz_(1856X1392) from Be, Inc. driver + XFree86 */
68 { { 288000, 1856, 1984, 2208, 2560, 1392, 1393, 1396, 1500, B_POSITIVE_VSYNC
}, B_CMAP8
, 1856, 1392, 0, 0, MODE_FLAGS
}, /* Vesa_Monitor_@75Hz_(1856X1392) from Be, Inc. driver + XFree86 */
69 /* 4:3 modes; 2.765M pixels */
70 { { 234000, 1920, 2048, 2256, 2600, 1440, 1441, 1444, 1500, B_POSITIVE_VSYNC
}, B_CMAP8
, 1920, 1440, 0, 0, MODE_FLAGS
}, /* Vesa_Monitor_@60Hz_(1920X1440) from Be, Inc. driver + XFree86 */
71 { { 297000, 1920, 2064, 2288, 2640, 1440, 1441, 1444, 1500, B_POSITIVE_VSYNC
}, B_CMAP8
, 1920, 1440, 0, 0, MODE_FLAGS
}, /* Vesa_Monitor_@75Hz_(1920X1440) from Be, Inc. driver + XFree86 */
72 /* 4:3 modes; 3.146M pixels */
73 { { 266950, 2048, 2200, 2424, 2800, 1536, 1537, 1540, 1589, B_POSITIVE_VSYNC
}, B_CMAP8
, 2048, 1536, 0, 0, MODE_FLAGS
}, /* From XFree86 posting @60Hz + XFree86 */
74 /* 16:10 panel mode; 400k pixels */
75 { { 31300, 800, 848, 928, 1008, 500, 501, 504, 518, T_POSITIVE_SYNC
}, B_CMAP8
, 800, 500, 0, 0, MODE_FLAGS
}, /* Vesa_Monitor_@60Hz_(800X500) */
76 /* 16:10 panel mode; 655.36k pixels */
77 { { 52800, 1024, 1072, 1176, 1328, 640, 641, 644, 663, T_POSITIVE_SYNC
}, B_CMAP8
, 1024, 640, 0, 0, MODE_FLAGS
}, /* Vesa_Monitor_@60Hz_(1024X640) */
78 /* 16:10 panel-TV mode; 983.04k pixels */
79 { { 80135, 1280, 1344, 1480, 1680, 768, 769, 772, 795, T_POSITIVE_SYNC
}, B_CMAP8
, 1280, 768, 0, 0, MODE_FLAGS
}, /* Vesa_Monitor_@60Hz_(1280X768) */
80 /* 16:10 panel mode; 1.024M pixels */
81 { { 83500, 1280, 1344, 1480, 1680, 800, 801, 804, 828, T_POSITIVE_SYNC
}, B_CMAP8
, 1280, 800, 0, 0, MODE_FLAGS
}, /* Vesa_Monitor_@60Hz_(1280X800) */
82 /* 16:10 panel mode; 1.296M pixels */
83 { { 106500, 1440, 1520, 1672, 1904, 900, 901, 904, 932, T_POSITIVE_SYNC
}, B_CMAP8
, 1440, 900, 0, 0, MODE_FLAGS
}, /* Vesa_Monitor_@60Hz_(1440X900) */
84 /* 16:10 panel mode; 1.764M pixels */
85 { { 147100, 1680, 1784, 1968, 2256, 1050, 1051, 1054, 1087, T_POSITIVE_SYNC
}, B_CMAP8
, 1680, 1050, 0, 0, MODE_FLAGS
}, /* Vesa_Monitor_@60Hz_(1680X1050) */
86 /* 16:10 panel mode; 2.304M pixels */
87 { { 193160, 1920, 2048, 2256, 2592, 1200, 1201, 1204, 1242, T_POSITIVE_SYNC
}, B_CMAP8
, 1920, 1200, 0, 0, MODE_FLAGS
}, /* Vesa_Monitor_@60Hz_(1920X1200) */
88 //{ { 160000, 1920, 2010, 2060, 2110, 1200, 1202, 1208, 1235, T_POSITIVE_SYNC}, B_CMAP8, 1920, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1920X1200) */
89 /* 16:9 panel mode; 1280x720 (HDTV 1280x720p) */
90 { { 74520, 1280, 1368, 1424, 1656, 720, 724, 730, 750, T_POSITIVE_SYNC
}, B_CMAP8
, 1280, 720, 0, 0, MODE_FLAGS
}, /* Vesa_Monitor_@60Hz_(1280X720) */
91 /* 16:9 panel mode; 1366x768 (HDTV '1280x720p')
92 note: horizontal CRTC timing must be a multiple of 8! (hardware restriction) */
93 { { 85500, 1368, 1440, 1576, 1792, 768, 771, 774, 798, T_POSITIVE_SYNC
}, B_CMAP8
, 1368, 768, 0, 0, MODE_FLAGS
}, /* Vesa_Monitor_@60Hz_(1366X768) */
94 /* 16:9 panel mode; 1920x1080 (HDTV 1920x1080p) */
95 { { 148500, 1920, 2008, 2052, 2200, 1080, 1084, 1089, 1125, T_POSITIVE_SYNC
}, B_CMAP8
, 1920, 1080, 0, 0, MODE_FLAGS
}, /* Vesa_Monitor_@60Hz_(1920X1080) */
99 // transform official mode to internal, multi-screen mode enhanced mode
100 static void Haiku_DetectTranslateMultiMode(display_mode
*mode
)
102 mode
->flags
&= ~DUALHEAD_BITS
;
104 if( mode
->virtual_width
== 2 * mode
->timing
.h_display
) {
105 LOG(4, ("Haiku: horizontal combine mode\n"));
106 if (si
->Haiku_switch_head
)
107 mode
->flags
|= DUALHEAD_SWITCH
;
109 mode
->flags
|= DUALHEAD_ON
;
110 } else if( mode
->virtual_height
== 2 * mode
->timing
.v_display
) {
111 LOG(4, ("Haiku: vertical combine mode not supported\n"));
113 /* unfortunately Haiku's screenprefs panel does not support single head output explicitly, so we'd better
114 activate both heads always to (probably) mimic Radeon driver behaviour (for which this app was adapted) */
116 - this will have a big downside on hardware for which both heads have different resolution cababilities (i.e. Matrox);
117 - also (on laptops) this will shorten battery life a bit of course.. */
118 mode
->flags
|= DUALHEAD_CLONE
;
123 // check and execute tunnel settings command
124 static status_t
Haiku_CheckMultiMonTunnel(display_mode
*mode
, const display_mode
*low
, const display_mode
*high
, bool *isTunneled
)
126 if( (mode
->timing
.flags
& RADEON_MODE_MULTIMON_REQUEST
) != 0 &&
127 (mode
->timing
.flags
& RADEON_MODE_MULTIMON_REPLY
) == 0 )
129 mode
->timing
.flags
&= ~RADEON_MODE_MULTIMON_REQUEST
;
130 mode
->timing
.flags
|= RADEON_MODE_MULTIMON_REPLY
;
132 // still process request, just in case someone set this flag
133 // combination by mistake
139 // check magic params
140 if( mode
->space
!= 0 || low
->space
!= 0 || high
->space
!= 0
141 || low
->virtual_width
!= 0xffff || low
->virtual_height
!= 0xffff
142 || high
->virtual_width
!= 0 || high
->virtual_height
!= 0
143 || mode
->timing
.pixel_clock
!= 0
144 || low
->timing
.pixel_clock
!= 'TKTK' || high
->timing
.pixel_clock
!= 'KTKT' )
152 /* enable Haiku special handling */
153 if (!si
->haiku_prefs_used
)
154 LOG(4, ("PROPOSEMODE: Haiku screenprefs tunnel detected.\n"));
155 si
->haiku_prefs_used
= true;
158 Haiku ScreenPrefs does not issue a SetMode command after changing these settings (per se), but relies on
159 driver switching outputs directly. These settings are not dependant on workspace there, and are not part of
160 the mode in the Radeon driver. In the Matrox and nVidia drivers they are though. So we need SetMode
161 to be issued. (yes: sometimes I switch monitors when I switch workspace.. ;-)
162 Also the RADEON driver saves these settings to a file so it remembers these after reboots. We don't atm.
163 If the mode as proposed by the driver would be saved by the ScreenPrefs panel, we would 'remember' it over
164 reboots though (via app_server settings).. */
166 switch( mode
->h_display_start
) {
168 switch( mode
->v_display_start
) {
170 if (si
->Haiku_switch_head
)
171 mode
->timing
.flags
= 1;
173 mode
->timing
.flags
= 0;
174 LOG(4, ("Haiku: tunnel access target=swap, command=get, value=%u\n", mode
->timing
.flags
));
177 si
->Haiku_switch_head
= mode
->timing
.flags
!= 0;
178 LOG(4, ("Haiku: tunnel access target=swap, command=set, value=%u\n", mode
->timing
.flags
));
179 /* Haiku's screenprefs panel expects us to directly set the mode.. (but it should do that itself) */
180 SET_DISPLAY_MODE(&si
->dm
);
185 case ms_use_laptop_panel
:
186 LOG(4, ("Haiku: tunnel access target=usepanel, command=%s, value=%u\n",
187 (mode
->v_display_start
== 1) ? "set" : "get", mode
->timing
.flags
));
188 // we refuse this setting (makes no sense for us: laptop panel is treated as normal screen)
193 LOG(4, ("Haiku: tunnel access target=tvstandard, command=%s, value=%u\n",
194 (mode
->v_display_start
== 1) ? "set" : "get", mode
->timing
.flags
));
195 // let's forget about this for now..
200 LOG(4, ("Haiku: unhandled tunnel access target=$%x, command=%u, value=%u\n",
201 mode
->h_display_start
, mode
->v_display_start
, mode
->timing
.flags
));
208 Check mode is between low and high limits.
211 B_BAD_VALUE - mode can be made, but outside limits
212 B_ERROR - not possible
215 * BeOS (tested R5.0.3PE) is failing BWindowScreen.SetFrameBuffer() if PROPOSEMODE
216 * returns B_BAD_VALUE. It's called by the OS with target, low and high set to
217 * have the same settings for BWindowScreen!
218 * Which means we should not return B_BAD_VALUE on anything except for deviations on:
219 * display_mode.virtual_width;
220 * display_mode.virtual_height;
221 * display_mode.timing.h_display;
222 * display_mode.timing.v_display;
225 * The target mode should be modified to correspond to the mode as it can be made. */
227 PROPOSE_DISPLAY_MODE(display_mode
*target
, const display_mode
*low
, const display_mode
*high
)
229 status_t status
= B_OK
;
230 float pix_clock_found
, target_aspect
;
233 uint32 max_vclk
, row_bytes
, mem_reservation
;
235 double target_refresh
= ((double)target
->timing
.pixel_clock
* 1000.0)
236 / ((double)target
->timing
.h_total
* (double)target
->timing
.v_total
);
237 bool want_same_width
= target
->timing
.h_display
== target
->virtual_width
;
238 bool want_same_height
= target
->timing
.v_display
== target
->virtual_height
;
239 bool isTunneled
= false;
240 // check whether we got a tunneled settings command
241 result
= Haiku_CheckMultiMonTunnel(target
, low
, high
, &isTunneled
);
245 /* since we (might be) called by the Haiku ScreenPrefs panel, check for special modes and translate
246 them from (for us) non-native modes to native modes (as used in DualheadSetup by Mark Watson).
247 These 'native modes' survive system reboots by the way, at least when set using DualheadSetup. */
249 /* note please: apparantly Haiku Screenprefs does not save the modes as set by the driver, but as originally requested
250 by the ScreenPrefs panel. Modifications done by the driver are therefore not saved.
251 It would be nice if the screenprefs panel in Haiku would save the modified modeflags (after proposemode or setmode),
252 that would also make the driver remember switched heads (now it's a temporary setting). */
254 if (si
->haiku_prefs_used
) {
255 // check how many heads are needed by target mode
256 Haiku_DetectTranslateMultiMode(target
);
259 LOG(1, ("PROPOSEMODE: (ENTER) requested virtual_width %d, virtual_height %d\n",
260 target
->virtual_width
, target
->virtual_height
));
262 /*find a nearby valid timing from that given*/
263 result
= head1_validate_timing(&target
->timing
.h_display
,
264 &target
->timing
.h_sync_start
, &target
->timing
.h_sync_end
,
265 &target
->timing
.h_total
, &target
->timing
.v_display
,
266 &target
->timing
.v_sync_start
, &target
->timing
.v_sync_end
,
267 &target
->timing
.v_total
);
268 if (result
== B_ERROR
) {
269 LOG(4, ("PROPOSEMODE: could not validate timing, aborted.\n"));
273 /* disable aspect checks for a requested TVout mode when mode is TVout capable */
275 || !(BT_check_tvmode(*target
) && (target
->flags
& TV_BITS
))) {
276 /* check if all connected output devices can display the requested mode's aspect.
277 * assuming 16:10 screens can display non-WS modes, but cannot (correctly) display 16:9 modes;
278 * assuming 16:9 screens can display non-WS modes, and can display 16:10 modes. */
279 /* calculate display mode aspect */
280 target_aspect
= (target
->timing
.h_display
/ ((float)target
->timing
.v_display
));
282 * allow 0.10 difference so 5:4 aspect panels will be able to use 4:3 aspect modes! */
283 switch (si
->ps
.monitors
) {
284 case 0: /* no monitor found at all */
285 /* if forcing widescreen type was requested don't block mode */
286 if (target_aspect
> 1.34 && !si
->settings
.force_ws
) {
287 LOG(4, ("PROPOSEMODE: not all output devices can display widescreen modes, aborted.\n"));
291 case CRTC1_TMDS
: /* digital panel on head 1, nothing on head 2 */
292 case CRTC1_VGA
: /* analog connected screen on head 1, nothing on head 2 */
293 if (si
->ps
.crtc1_screen
.aspect
< (target_aspect
- 0.10)) {
294 LOG(4, ("PROPOSEMODE: screen at crtc1 is not widescreen (enough) type, aborted.\n"));
298 case CRTC2_TMDS
: /* nothing on head 1, digital panel on head 2 */
299 case CRTC2_VGA
: /* analog connected screen on head 2, nothing on head 1 */
300 if (si
->ps
.crtc2_screen
.aspect
< (target_aspect
- 0.10)) {
301 LOG(4, ("PROPOSEMODE: screen at crtc2 is not widescreen (enough) type, aborted.\n"));
305 case CRTC1_TMDS
| CRTC2_TMDS
: /* digital panels on both heads */
306 case CRTC1_VGA
| CRTC2_VGA
: /* analog connected screens on both heads */
307 case CRTC1_TMDS
| CRTC2_VGA
: /* digital panel on head 1, analog connected screen on head 2 */
308 case CRTC1_VGA
| CRTC2_TMDS
: /* analog connected screen on head 1, digital panel on head 2 */
309 default: /* more than two screens connected (illegal setup) */
310 if ((si
->ps
.crtc1_screen
.aspect
< (target_aspect
- 0.10)) ||
311 (si
->ps
.crtc2_screen
.aspect
< (target_aspect
- 0.10))) {
312 LOG(4, ("PROPOSEMODE: not all connected screens are widescreen (enough) type, aborted.\n"));
319 /* only limit modelist if user did not explicitly block this via nv.settings
320 (because of errors in monitor's EDID information returned) */
321 if (si
->settings
.check_edid
) {
322 /* check if screen(s) can display the requested resolution (if we have it's EDID info)
324 allowing 2 pixels more for horizontal display for the 1366 mode, since multiples of 8
325 are required for the CRTCs horizontal timing programming) */
326 if (si
->ps
.crtc1_screen
.have_native_edid
) {
327 if ((target
->timing
.h_display
- 2) > si
->ps
.crtc1_screen
.timing
.h_display
328 || target
->timing
.v_display
> si
->ps
.crtc1_screen
.timing
.v_display
) {
329 LOG(4, ("PROPOSEMODE: screen at crtc1 can't display requested resolution, aborted.\n"));
333 if (si
->ps
.crtc2_screen
.have_native_edid
) {
334 if ((target
->timing
.h_display
- 2) > si
->ps
.crtc2_screen
.timing
.h_display
335 || target
->timing
.v_display
> si
->ps
.crtc2_screen
.timing
.v_display
) {
336 LOG(4, ("PROPOSEMODE: screen at crtc2 can't display requested resolution, aborted.\n"));
342 /* validate display vs. virtual */
343 if (target
->timing
.h_display
> target
->virtual_width
|| want_same_width
)
344 target
->virtual_width
= target
->timing
.h_display
;
345 if (target
->timing
.v_display
> target
->virtual_height
|| want_same_height
)
346 target
->virtual_height
= target
->timing
.v_display
;
348 /* nail virtual size and 'subsequently' calculate rowbytes */
349 result
= nv_general_validate_pic_size(target
, &row_bytes
, &acc_mode
);
350 if (result
== B_ERROR
) {
351 LOG(4, ("PROPOSEMODE: could not validate virtual picture size, aborted.\n"));
355 /* check if virtual_width is still within the requested limits */
356 if (target
->virtual_width
< low
->virtual_width
357 || target
->virtual_width
> high
->virtual_width
) {
358 status
= B_BAD_VALUE
;
359 LOG(4, ("PROPOSEMODE: WARNING: virtual_width deviates too much\n"));
362 /* check if timing found is within the requested horizontal limits */
363 if (target
->timing
.h_display
< low
->timing
.h_display
364 || target
->timing
.h_display
> high
->timing
.h_display
365 || target
->timing
.h_sync_start
< low
->timing
.h_sync_start
366 || target
->timing
.h_sync_start
> high
->timing
.h_sync_start
367 || target
->timing
.h_sync_end
< low
->timing
.h_sync_end
368 || target
->timing
.h_sync_end
> high
->timing
.h_sync_end
369 || target
->timing
.h_total
< low
->timing
.h_total
370 || target
->timing
.h_total
> high
->timing
.h_total
) {
371 /* BWindowScreen workaround: we accept everything except h_display deviations */
372 if (target
->timing
.h_display
< low
->timing
.h_display
373 || target
->timing
.h_display
> high
->timing
.h_display
)
374 status
= B_BAD_VALUE
;
376 LOG(4, ("PROPOSEMODE: WARNING: horizontal timing deviates too much\n"));
379 /* check if timing found is within the requested vertical limits */
380 if (target
->timing
.v_display
< low
->timing
.v_display
381 || target
->timing
.v_display
> high
->timing
.v_display
382 || target
->timing
.v_sync_start
< low
->timing
.v_sync_start
383 || target
->timing
.v_sync_start
> high
->timing
.v_sync_start
384 || target
->timing
.v_sync_end
< low
->timing
.v_sync_end
385 || target
->timing
.v_sync_end
> high
->timing
.v_sync_end
386 || target
->timing
.v_total
< low
->timing
.v_total
387 || target
->timing
.v_total
> high
->timing
.v_total
) {
388 /* BWindowScreen workaround: we accept everything except v_display deviations */
389 if (target
->timing
.v_display
< low
->timing
.v_display
390 || target
->timing
.v_display
> high
->timing
.v_display
)
391 status
= B_BAD_VALUE
;
393 LOG(4, ("PROPOSEMODE: WARNING: vertical timing deviates too much\n"));
396 /* adjust pixelclock for possible timing modifications done above */
397 target
->timing
.pixel_clock
= target_refresh
* ((double)target
->timing
.h_total
)
398 * ((double)target
->timing
.v_total
) / 1000.0;
400 /* Now find the nearest valid pixelclock we actually can setup for the target mode,
401 * this also makes sure we don't generate more pixel bandwidth than the device can handle */
402 /* calculate settings, but do not actually test anything (that costs too much time!) */
403 result
= head1_pix_pll_find(*target
, &pix_clock_found
, &m
, &n
, &p
, 0);
404 /* update the target mode */
405 target
->timing
.pixel_clock
= pix_clock_found
* 1000;
407 /* note if we fell outside the limits */
408 if (target
->timing
.pixel_clock
< low
->timing
.pixel_clock
409 || target
->timing
.pixel_clock
> high
->timing
.pixel_clock
) {
410 /* BWindowScreen workaround: we accept deviations <= 1Mhz */
411 if (target
->timing
.pixel_clock
< low
->timing
.pixel_clock
- 1000
412 || target
->timing
.pixel_clock
> high
->timing
.pixel_clock
+ 1000)
413 status
= B_BAD_VALUE
;
415 LOG(4, ("PROPOSEMODE: WARNING: pixelclock deviates too much\n"));
419 /* checkout space needed for hardcursor (if any) */
420 if (si
->settings
.hardcursor
)
421 mem_reservation
= 2048;
423 /* Reserve extra space as a workaround for certain bugs (see DriverInterface.h
424 * for an explanation). */
425 if (si
->ps
.card_arch
< NV40A
)
426 mem_reservation
+= PRE_NV40_OFFSET
;
428 mem_reservation
+= NV40_PLUS_OFFSET
;
430 /* memory requirement for frame buffer */
431 if (row_bytes
* target
->virtual_height
> si
->ps
.memory_size
- mem_reservation
) {
432 target
->virtual_height
= (si
->ps
.memory_size
- mem_reservation
) / row_bytes
;
434 if (target
->virtual_height
< target
->timing
.v_display
) {
435 LOG(4,("PROPOSEMODE: not enough memory for current mode, aborted.\n"));
439 LOG(4,("PROPOSEMODE: validated virtual_width %d, virtual_height %d pixels\n",
440 target
->virtual_width
, target
->virtual_height
));
442 if (target
->virtual_height
< low
->virtual_height
443 || target
->virtual_height
> high
->virtual_height
) {
444 status
= B_BAD_VALUE
;
445 LOG(4, ("PROPOSEMODE: WARNING: virtual_height deviates too much\n"));
448 /* setup status flags */
449 LOG(1, ("PROPOSEMODE: initial modeflags: $%08x\n", target
->flags
));
450 /* preset to singlehead card without TVout, no overlay support and no hardcursor.
451 * also advice system that app_server and acc engine may touch the framebuffer
452 * simultaneously (fixed). */
454 ~(DUALHEAD_CAPABLE
| TV_CAPABLE
| B_SUPPORTS_OVERLAYS
| B_HARDWARE_CURSOR
| B_IO_FB_NA
);
455 /* we always allow parallel access (fixed), the DAC is always in 'enhanced'
456 * mode (fixed), and all modes support DPMS (fixed);
457 * We support scrolling and panning in every mode, so we 'send a signal' to
458 * BWindowScreen.CanControlFrameBuffer() by setting B_SCROLL. */
459 /* BTW: B_PARALLEL_ACCESS in combination with a hardcursor enables
460 * BDirectWindow windowed modes. */
461 target
->flags
|= (B_PARALLEL_ACCESS
| B_8_BIT_DAC
| B_DPMS
| B_SCROLL
);
463 /* determine the 'would be' max. pixelclock for the second DAC for the current videomode if dualhead were activated */
464 switch (target
->space
) {
466 max_vclk
= si
->ps
.max_dac2_clock_8
;
471 max_vclk
= si
->ps
.max_dac2_clock_16
;
475 max_vclk
= si
->ps
.max_dac2_clock_24
;
479 max_vclk
= si
->ps
.max_dac2_clock_32dh
;
483 /* use fail-safe value */
484 max_vclk
= si
->ps
.max_dac2_clock_32dh
;
489 /* set DUALHEAD_CAPABLE if suitable */
490 //fixme: update for independant secondary head use! (reserve fixed memory then)
491 if (si
->ps
.secondary_head
&& target
->timing
.pixel_clock
<= (max_vclk
* 1000)) {
492 switch (target
->flags
& DUALHEAD_BITS
) {
494 case DUALHEAD_SWITCH
:
495 if (si
->ps
.memory_size
- mem_reservation
496 >= row_bytes
* target
->virtual_height
497 && (uint16
)(row_bytes
/ bpp
) >= target
->timing
.h_display
* 2)
498 target
->flags
|= DUALHEAD_CAPABLE
;
501 if (si
->ps
.memory_size
- mem_reservation
502 >= row_bytes
* target
->virtual_height
)
503 target
->flags
|= DUALHEAD_CAPABLE
;
506 if (si
->ps
.memory_size
- mem_reservation
507 >= row_bytes
* target
->virtual_height
* 2)
508 target
->flags
|= DUALHEAD_CAPABLE
;
513 /* if not dualhead capable card clear dualhead flags */
514 if (!(target
->flags
& DUALHEAD_CAPABLE
))
515 target
->flags
&= ~DUALHEAD_BITS
;
517 /* set TV_CAPABLE if suitable: pixelclock is not important (defined by TVstandard) */
518 if (si
->ps
.tvout
&& BT_check_tvmode(*target
))
519 target
->flags
|= TV_CAPABLE
;
521 /* if not TVout capable card clear TVout flags */
522 if (!(target
->flags
& TV_CAPABLE
))
523 target
->flags
&= ~TV_BITS
;
525 /* make sure TV head assignment is sane */
526 if (target
->flags
& TV_BITS
) {
527 if (!si
->ps
.secondary_head
)
528 target
->flags
|= TV_PRIMARY
;
529 else if ((target
->flags
& DUALHEAD_BITS
) == DUALHEAD_OFF
)
530 target
->flags
|= TV_PRIMARY
;
532 target
->flags
&= ~TV_PRIMARY
;
534 /* set HARDWARE_CURSOR mode if suitable */
535 if (si
->settings
.hardcursor
)
536 target
->flags
|= B_HARDWARE_CURSOR
;
538 /* set SUPPORTS_OVERLAYS if suitable */
539 if (si
->ps
.card_type
<= NV40
|| si
->ps
.card_type
== NV45
)
540 target
->flags
|= B_SUPPORTS_OVERLAYS
;
542 LOG(1, ("PROPOSEMODE: validated modeflags: $%08x\n", target
->flags
));
544 /* overrule timing command flags to be (fixed) blank_pedestal = 0.0IRE,
545 * progressive scan (fixed), and sync_on_green not avaible. */
546 target
->timing
.flags
&= ~(B_BLANK_PEDESTAL
| B_TIMING_INTERLACED
| B_SYNC_ON_GREEN
);
547 /* The HSYNC and VSYNC command flags are actually executed by the driver. */
550 LOG(4, ("PROPOSEMODE: completed successfully.\n"));
552 LOG(4, ("PROPOSEMODE: mode can be made, but outside given limits.\n"));
558 Return the number of modes this device will return from GET_MODE_LIST().
559 This is precalculated in create_mode_list (called from InitAccelerant stuff)
562 ACCELERANT_MODE_COUNT(void)
564 LOG(1, ("ACCELERANT_MODE_COUNT: the modelist contains %d modes\n",si
->mode_count
));
565 return si
->mode_count
;
569 /*! Copy the list of guaranteed supported video modes to the location provided.
572 GET_MODE_LIST(display_mode
*dm
)
574 LOG(1, ("GET_MODE_LIST: exporting the modelist created before.\n"));
576 memcpy(dm
, my_mode_list
, si
->mode_count
* sizeof(display_mode
));
581 static void checkAndAddMode(const display_mode
*src
, display_mode
*dst
)
583 uint32 j
, pix_clk_range
;
584 display_mode low
, high
;
585 color_space spaces
[4] = {B_RGB32_LITTLE
, B_RGB16_LITTLE
, B_RGB15_LITTLE
, B_CMAP8
};
587 /* set ranges for acceptable values */
589 /* range is 6.25% of default clock: arbitrarily picked */
590 pix_clk_range
= low
.timing
.pixel_clock
>> 5;
591 low
.timing
.pixel_clock
-= pix_clk_range
;
592 high
.timing
.pixel_clock
+= pix_clk_range
;
593 /* 'some cards need wider virtual widths for certain modes':
594 * Not true. They might need a wider pitch, but this is _not_ reflected in
595 * virtual_width, but in fbc.bytes_per_row. */
596 //So disable next line:
597 //high.virtual_width = 4096;
598 /* do it once for each depth we want to support */
599 for (j
= 0; j
< (sizeof(spaces
) / sizeof(color_space
)); j
++) {
600 /* set target values */
601 dst
[si
->mode_count
] = *src
;
602 /* poke the specific space */
603 dst
[si
->mode_count
].space
= low
.space
= high
.space
= spaces
[j
];
604 /* ask for a compatible mode */
605 /* We have to check for B_OK, because otherwise the pix_clk_range
606 * won't be taken into account!! */
608 //if (PROPOSE_DISPLAY_MODE(dst, &low, &high) != B_ERROR) {
610 if (PROPOSE_DISPLAY_MODE(&dst
[si
->mode_count
], &low
, &high
) == B_OK
) {
611 /* count it, so move on to next mode */
618 /*! Create a list of display_modes to pass back to the caller.
621 create_mode_list(void)
625 const display_mode
*src
;
627 display_mode custom_mode
;
629 /* figure out how big the list could be (4 colorspaces, 3 virtual types per mode), and adjust up to nearest multiple of B_PAGE_SIZE */
630 max_size
= (((MODE_COUNT
* 4 * 3) * sizeof(display_mode
)) + (B_PAGE_SIZE
-1)) & ~(B_PAGE_SIZE
-1);
632 /* create an area to hold the info */
633 si
->mode_area
= my_mode_list_area
= create_area("NV accelerant mode info",
634 (void **)&my_mode_list
, B_ANY_ADDRESS
, max_size
, B_NO_LOCK
,
635 B_READ_AREA
| B_WRITE_AREA
);
636 if (my_mode_list_area
< B_OK
)
637 return my_mode_list_area
;
639 /* walk through our predefined list and see which modes fit this device */
643 for (i
= 0; i
< MODE_COUNT
; i
++) {
645 /* unfortunately Haiku's screenprefs panel does not support single head output explicitly, so we'd better
646 activate both heads always to (probably) mimic Radeon driver behaviour (for which this app was adapted) */
648 - this will have a big downside on hardware for which both heads have different resolution cababilities (i.e. Matrox);
649 - also (on laptops) this will shorten battery life a bit of course.. */
651 custom_mode
.flags
|= DUALHEAD_CLONE
;
652 checkAndAddMode(&custom_mode
, dst
);
653 // double width mode for Haiku ScreenPrefs panel
654 /* note please: These modes should not be added. Instead the mode.flags should be used during setting screen as these will
655 automatically generate the needed other properties of the mode. Besides, virtual size is meant to be used for
656 pan&scan modes (viewports), i.e. for certain games.
657 The currently used method will fail programs that are meant to work pan@scan if the virtual width (or height) are
658 exactly twice the view area. */
660 custom_mode
.virtual_width
*= 2;
661 custom_mode
.flags
|= DUALHEAD_ON
;
662 checkAndAddMode(&custom_mode
, dst
);
663 // we don't support double height modes
664 /* advance to next mode */