BPicture: Fix archive constructor.
[haiku.git] / src / add-ons / accelerants / via / ProposeDisplayMode.c
blobba17365635c7d0a381a0007186bf894083679650
1 /*
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:
6 Mark Watson,
7 Rudolf Cornelissen 9/2002-11/2005
8 */
10 #define MODULE_BIT 0x00400000
12 #include "acc_std.h"
14 #define T_POSITIVE_SYNC (B_POSITIVE_HSYNC | B_POSITIVE_VSYNC)
15 /* mode flags will be setup as status info by PROPOSEMODE! */
16 #define MODE_FLAGS 0
17 #define MODE_COUNT (sizeof (mode_list) / sizeof (display_mode))
19 /*some monitors only handle a fixed set of modes*/
20 #include "valid_mode_list"
22 /* Standard VESA modes,
23 * plus panel specific resolution modes which are internally modified during run-time depending on the requirements of the actual
24 * panel connected. The modes as listed here, should timing-wise be as compatible with analog (CRT) monitors as can be... */
25 static const display_mode mode_list[] = {
26 /* 4:3 modes; 307.2k pixels */
27 { { 25175, 640, 656, 752, 800, 480, 490, 492, 525, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(640X480X8.Z1) */
28 { { 27500, 640, 672, 768, 864, 480, 488, 494, 530, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* 640X480X60Hz */
29 { { 30500, 640, 672, 768, 864, 480, 517, 523, 588, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* SVGA_640X480X60HzNI */
30 { { 31500, 640, 664, 704, 832, 480, 489, 492, 520, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@70-72Hz_(640X480X8.Z1) */
31 { { 31500, 640, 656, 720, 840, 480, 481, 484, 500, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@75Hz_(640X480X8.Z1) */
32 { { 36000, 640, 696, 752, 832, 480, 481, 484, 509, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@85Hz_(640X480X8.Z1) */
33 /* 4:3 modes; 480k pixels */
34 { { 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 */
35 { { 38100, 800, 832, 960, 1088, 600, 602, 606, 620, 0}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS}, /* SVGA_800X600X56HzNI */
36 { { 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 */
37 { { 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 */
38 { { 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 */
39 { { 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 */
40 /* 4:3 modes; 786.432k pixels */
41 { { 65000, 1024, 1048, 1184, 1344, 768, 771, 777, 806, 0}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1024X768X8.Z1) + XFree86 */
42 { { 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 */
43 { { 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 */
44 { { 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 */
45 /* 4:3 modes; 995.328k pixels */
46 { { 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) */
47 { { 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) */
48 { { 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 */
49 { { 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) */
50 /* 5:4 modes; 1.311M pixels */
51 { { 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 */
52 { { 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 */
53 { { 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 */
54 /* 4:3 panel mode; 1.47M pixels */
55 { { 122600, 1400, 1488, 1640, 1880, 1050, 1051, 1054, 1087, T_POSITIVE_SYNC}, B_CMAP8, 1400, 1050, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1400X1050) */
56 /* 4:3 modes; 1.92M pixels */
57 { { 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 */
58 /* identical lines to above one, apart from refreshrate.. */
59 { { 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 */
60 { { 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 */
61 { { 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 */
62 { { 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) */
63 { { 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 */
64 /* end identical lines. */
65 /* 4:3 modes; 2.408M pixels */
66 { { 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 */
67 { { 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 */
68 /* 4:3 modes; 2.584M pixels */
69 { { 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 */
70 { { 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 */
71 /* 4:3 modes; 2.765M pixels */
72 { { 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 */
73 { { 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 */
74 /* 4:3 modes; 3.146M pixels */
75 { { 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 */
76 /* 16:10 panel mode; 400k pixels */
77 { { 31300, 800, 848, 928, 1008, 500, 501, 504, 518, T_POSITIVE_SYNC}, B_CMAP8, 800, 500, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(800X500) */
78 /* 16:10 panel mode; 655.36k pixels */
79 { { 52800, 1024, 1072, 1176, 1328, 640, 641, 644, 663, T_POSITIVE_SYNC}, B_CMAP8, 1024, 640, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1024X640) */
80 /* 16:10 panel-TV mode; 983.04k pixels */
81 { { 80135, 1280, 1344, 1480, 1680, 768, 769, 772, 795, T_POSITIVE_SYNC}, B_CMAP8, 1280, 768, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1280X768) */
82 /* 16:10 panel mode; 1.024M pixels */
83 { { 83500, 1280, 1344, 1480, 1680, 800, 801, 804, 828, T_POSITIVE_SYNC}, B_CMAP8, 1280, 800, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1280X800) */
84 /* 16:10 panel mode; 1.296M pixels */
85 { { 106500, 1440, 1520, 1672, 1904, 900, 901, 904, 932, T_POSITIVE_SYNC}, B_CMAP8, 1440, 900, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1440X900) */
86 /* 16:10 panel mode; 1.764M pixels */
87 { { 147100, 1680, 1784, 1968, 2256, 1050, 1051, 1054, 1087, T_POSITIVE_SYNC}, B_CMAP8, 1680, 1050, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1680X1050) */
88 /* 16:10 panel mode; 2.304M pixels */
89 { { 193200, 1920, 2048, 2256, 2592, 1200, 1201, 1204, 1242, T_POSITIVE_SYNC}, B_CMAP8, 1920, 1200, 0, 0, MODE_FLAGS}, /* Vesa_Monitor_@60Hz_(1920X1200) */
93 Check mode is between low and high limits
94 returns:
95 B_OK - found one
96 B_BAD_VALUE - mode can be made, but outside limits
97 B_ERROR - not possible
99 /* BOUNDS WARNING:
100 * BeOS (tested R5.0.3PE) is failing BWindowScreen.SetFrameBuffer() if PROPOSEMODE
101 * returns B_BAD_VALUE. It's called by the OS with target, low and high set to
102 * have the same settings for BWindowScreen!
103 * Which means we should not return B_BAD_VALUE on anything except for deviations on:
104 * display_mode.virtual_width;
105 * display_mode.virtual_height;
106 * display_mode.timing.h_display;
107 * display_mode.timing.v_display;
109 /* Note:
110 * The target mode should be modified to correspond to the mode as it can be made. */
111 status_t PROPOSE_DISPLAY_MODE(display_mode *target, const display_mode *low, const display_mode *high)
113 status_t status = B_OK;
114 float pix_clock_found, target_aspect;
115 uint8 m,n,p, bpp;
116 status_t result;
117 uint32 max_vclk, row_bytes, pointer_reservation;
118 bool acc_mode;
119 double target_refresh = ((double)target->timing.pixel_clock * 1000.0) /
121 (double)target->timing.h_total *
122 (double)target->timing.v_total
124 bool
125 want_same_width = target->timing.h_display == target->virtual_width,
126 want_same_height = target->timing.v_display == target->virtual_height;
128 LOG(1, ("PROPOSEMODE: (ENTER) requested virtual_width %d, virtual_height %d\n",
129 target->virtual_width, target->virtual_height));
131 /*check valid list:
132 if (VALID_REQUIRED is set)
134 if (find modes with same size)
136 pick one with nearest pixel clock
138 else
140 pick next largest with nearest pixel clock and modify visible portion as far as possible
144 #ifdef VALID_MODE_REQUIRED
146 int i;
147 int closest_mode_ptr;
148 uint32 closest_mode_clock;
150 LOG(1, ("PROPOSEMODE: valid mode required!\n"));
152 closest_mode_ptr = 0xbad;
153 closest_mode_clock = 0;
154 for (i=0;i<VALID_MODES;i++)
156 /*check size is ok and clock is better than any found before*/
158 target->timing.h_display==valid_mode_list[i].h_display &&
159 target->timing.v_display==valid_mode_list[i].v_display
162 if (
163 abs(valid_mode_list[i].pixel_clock-target->timing.pixel_clock)<
164 abs(closest_mode_clock-target->timing.pixel_clock)
167 closest_mode_clock=valid_mode_list[i].pixel_clock;
168 closest_mode_ptr=i;
173 if (closest_mode_ptr==0xbad)/*if no modes of correct size*/
175 LOG(4, ("PROPOSEMODE: no valid mode found, aborted.\n"));
176 return B_ERROR;
178 else
180 target->timing=valid_mode_list[closest_mode_ptr];
181 target_refresh = ((double)target->timing.pixel_clock * 1000.0) / /*I require this refresh*/
182 ((double)target->timing.h_total * (double)target->timing.v_total);
185 #endif
187 /*find a nearby valid timing from that given*/
188 result = head1_validate_timing
190 &target->timing.h_display, &target->timing.h_sync_start, &target->timing.h_sync_end, &target->timing.h_total,
191 &target->timing.v_display, &target->timing.v_sync_start, &target->timing.v_sync_end, &target->timing.v_total
193 if (result == B_ERROR)
195 LOG(4, ("PROPOSEMODE: could not validate timing, aborted.\n"));
196 return result;
199 /* check if all connected output devices can display the requested mode's aspect: */
200 /* calculate display mode aspect */
201 target_aspect = (target->timing.h_display / ((float)target->timing.v_display));
202 /* NOTE:
203 * allow 0.10 difference so 5:4 aspect panels will be able to use 4:3 aspect modes! */
204 switch (si->ps.monitors)
206 case 0x01: /* digital panel on head 1, nothing on head 2 */
207 if (si->ps.panel1_aspect < (target_aspect - 0.10))
209 LOG(4, ("PROPOSEMODE: connected panel1 is not widescreen type, aborted.\n"));
210 return B_ERROR;
212 break;
213 case 0x10: /* nothing on head 1, digital panel on head 2 */
214 if (si->ps.panel2_aspect < (target_aspect - 0.10))
216 LOG(4, ("PROPOSEMODE: connected panel2 is not widescreen type, aborted.\n"));
217 return B_ERROR;
219 break;
220 case 0x11: /* digital panels on both heads */
221 if ((si->ps.panel1_aspect < (target_aspect - 0.10)) ||
222 (si->ps.panel2_aspect < (target_aspect - 0.10)))
224 LOG(4, ("PROPOSEMODE: not all connected panels are widescreen type, aborted.\n"));
225 return B_ERROR;
227 break;
228 default: /* at least one analog monitor is connected, or nothing detected at all */
229 if (target_aspect > 1.34)
231 LOG(4, ("PROPOSEMODE: not all output devices can display widescreen modes, aborted.\n"));
232 return B_ERROR;
234 break;
237 /* only export widescreen panel-TV modes when an exact resolution match exists,
238 * to prevent the modelist from becoming too crowded */
239 if (target_aspect > 1.61)
241 status_t panel_TV_stat = B_ERROR;
243 if (si->ps.tmds1_active)
245 if ((target->timing.h_display == si->ps.p1_timing.h_display) &&
246 (target->timing.v_display == si->ps.p1_timing.v_display))
248 panel_TV_stat = B_OK;
251 if (si->ps.tmds2_active)
253 if ((target->timing.h_display == si->ps.p2_timing.h_display) &&
254 (target->timing.v_display == si->ps.p2_timing.v_display))
256 panel_TV_stat = B_OK;
259 if (panel_TV_stat != B_OK)
261 LOG(4, ("PROPOSEMODE: WS panel_TV mode requested but no such TV here, aborted.\n"));
262 return B_ERROR;
266 /* check if panel(s) can display the requested resolution (if connected) */
267 if (si->ps.tmds1_active)
269 if ((target->timing.h_display > si->ps.p1_timing.h_display) ||
270 (target->timing.v_display > si->ps.p1_timing.v_display))
272 LOG(4, ("PROPOSEMODE: panel1 can't display requested resolution, aborted.\n"));
273 return B_ERROR;
276 if (si->ps.tmds2_active)
278 if ((target->timing.h_display > si->ps.p2_timing.h_display) ||
279 (target->timing.v_display > si->ps.p2_timing.v_display))
281 LOG(4, ("PROPOSEMODE: panel2 can't display requested resolution, aborted.\n"));
282 return B_ERROR;
286 /* validate display vs. virtual */
287 if ((target->timing.h_display > target->virtual_width) || want_same_width)
288 target->virtual_width = target->timing.h_display;
289 if ((target->timing.v_display > target->virtual_height) || want_same_height)
290 target->virtual_height = target->timing.v_display;
292 /* nail virtual size and 'subsequently' calculate rowbytes */
293 result = eng_general_validate_pic_size (target, &row_bytes, &acc_mode);
294 if (result == B_ERROR)
296 LOG(4, ("PROPOSEMODE: could not validate virtual picture size, aborted.\n"));
297 return result;
300 /*check if virtual_width is still within the requested limits*/
301 if ((target->virtual_width < low->virtual_width) ||
302 (target->virtual_width > high->virtual_width))
304 status = B_BAD_VALUE;
305 LOG(4, ("PROPOSEMODE: WARNING: virtual_width deviates too much\n"));
308 /*check if timing found is within the requested horizontal limits*/
309 if ((target->timing.h_display < low->timing.h_display) ||
310 (target->timing.h_display > high->timing.h_display) ||
311 (target->timing.h_sync_start < low->timing.h_sync_start) ||
312 (target->timing.h_sync_start > high->timing.h_sync_start) ||
313 (target->timing.h_sync_end < low->timing.h_sync_end) ||
314 (target->timing.h_sync_end > high->timing.h_sync_end) ||
315 (target->timing.h_total < low->timing.h_total) ||
316 (target->timing.h_total > high->timing.h_total))
318 /* BWindowScreen workaround: we accept everything except h_display deviations */
319 if ((target->timing.h_display < low->timing.h_display) ||
320 (target->timing.h_display > high->timing.h_display))
322 status = B_BAD_VALUE;
324 LOG(4, ("PROPOSEMODE: WARNING: horizontal timing deviates too much\n"));
327 /*check if timing found is within the requested vertical limits*/
328 if (
329 (target->timing.v_display < low->timing.v_display) ||
330 (target->timing.v_display > high->timing.v_display) ||
331 (target->timing.v_sync_start < low->timing.v_sync_start) ||
332 (target->timing.v_sync_start > high->timing.v_sync_start) ||
333 (target->timing.v_sync_end < low->timing.v_sync_end) ||
334 (target->timing.v_sync_end > high->timing.v_sync_end) ||
335 (target->timing.v_total < low->timing.v_total) ||
336 (target->timing.v_total > high->timing.v_total)
339 /* BWindowScreen workaround: we accept everything except v_display deviations */
340 if ((target->timing.v_display < low->timing.v_display) ||
341 (target->timing.v_display > high->timing.v_display))
343 status = B_BAD_VALUE;
345 LOG(4, ("PROPOSEMODE: WARNING: vertical timing deviates too much\n"));
348 /* adjust pixelclock for possible timing modifications done above */
349 target->timing.pixel_clock = target_refresh * ((double)target->timing.h_total) * ((double)target->timing.v_total) / 1000.0;
351 /* Now find the nearest valid pixelclock we actually can setup for the target mode,
352 * this also makes sure we don't generate more pixel bandwidth than the device can handle */
353 /* calculate settings, but do not actually test anything (that costs too much time!) */
354 result = head1_pix_pll_find(*target,&pix_clock_found,&m,&n,&p,0);
355 /* update the target mode */
356 target->timing.pixel_clock = (pix_clock_found * 1000);
358 /* note if we fell outside the limits */
359 if ((target->timing.pixel_clock < low->timing.pixel_clock) ||
360 (target->timing.pixel_clock > high->timing.pixel_clock)
363 /* BWindowScreen workaround: we accept deviations <= 1Mhz */
364 if ((target->timing.pixel_clock < (low->timing.pixel_clock - 1000)) ||
365 (target->timing.pixel_clock > (high->timing.pixel_clock + 1000)))
367 status = B_BAD_VALUE;
369 LOG(4, ("PROPOSEMODE: WARNING: pixelclock deviates too much\n"));
372 /* checkout space needed for hardcursor (if any) */
373 pointer_reservation = 0;
374 if (si->settings.hardcursor) pointer_reservation = 2048;
375 /* memory requirement for frame buffer */
376 if ((row_bytes * target->virtual_height) >
377 (si->ps.memory_size - pointer_reservation))
379 target->virtual_height =
380 (si->ps.memory_size - pointer_reservation) / row_bytes;
382 if (target->virtual_height < target->timing.v_display)
384 LOG(4,("PROPOSEMODE: not enough memory for current mode, aborted.\n"));
385 return B_ERROR;
387 LOG(4,("PROPOSEMODE: validated virtual_width %d, virtual_height %d pixels\n",
388 target->virtual_width, target->virtual_height));
390 if ((target->virtual_height < low->virtual_height) ||
391 (target->virtual_height > high->virtual_height))
393 status = B_BAD_VALUE;
394 LOG(4, ("PROPOSEMODE: WARNING: virtual_height deviates too much\n"));
397 /* setup status flags */
398 LOG(1, ("PROPOSEMODE: initial modeflags: $%08x\n", target->flags));
399 /* preset to singlehead card without TVout, no overlay support and no hardcursor.
400 * also advice system that app_server and acc engine may touch the framebuffer
401 * simultaneously (fixed). */
402 target->flags &=
403 ~(DUALHEAD_CAPABLE | TV_CAPABLE | B_SUPPORTS_OVERLAYS | B_HARDWARE_CURSOR | B_IO_FB_NA);
404 /* we always allow parallel access (fixed), the DAC is always in 'enhanced'
405 * mode (fixed), and all modes support DPMS (fixed);
406 * We support scrolling and panning in every mode, so we 'send a signal' to
407 * BWindowScreen.CanControlFrameBuffer() by setting B_SCROLL. */
408 /* BTW: B_PARALLEL_ACCESS in combination with a hardcursor enables
409 * BDirectWindow windowed modes. */
410 target->flags |= (B_PARALLEL_ACCESS | B_8_BIT_DAC | B_DPMS | B_SCROLL);
412 /* determine the 'would be' max. pixelclock for the second DAC for the current videomode if dualhead were activated */
413 switch (target->space)
415 case B_CMAP8:
416 max_vclk = si->ps.max_dac2_clock_8;
417 bpp = 1;
418 break;
419 case B_RGB15_LITTLE:
420 case B_RGB16_LITTLE:
421 max_vclk = si->ps.max_dac2_clock_16;
422 bpp = 2;
423 break;
424 case B_RGB24_LITTLE:
425 max_vclk = si->ps.max_dac2_clock_24;
426 bpp = 3;
427 break;
428 case B_RGB32_LITTLE:
429 max_vclk = si->ps.max_dac2_clock_32dh;
430 bpp = 4;
431 break;
432 default:
433 /* use fail-safe value */
434 max_vclk = si->ps.max_dac2_clock_32dh;
435 bpp = 4;
436 break;
439 /* set DUALHEAD_CAPABLE if suitable */
440 //fixme: update for independant secondary head use! (reserve fixed memory then)
441 if (si->ps.secondary_head && (target->timing.pixel_clock <= (max_vclk * 1000)))
443 switch (target->flags & DUALHEAD_BITS)
445 case DUALHEAD_ON:
446 case DUALHEAD_SWITCH:
447 if (((si->ps.memory_size - pointer_reservation) >=
448 (row_bytes * target->virtual_height)) &&
449 ((uint16)(row_bytes / bpp) >= (target->timing.h_display * 2)))
451 target->flags |= DUALHEAD_CAPABLE;
453 break;
454 case DUALHEAD_CLONE:
455 if ((si->ps.memory_size - pointer_reservation) >=
456 (row_bytes * target->virtual_height))
458 target->flags |= DUALHEAD_CAPABLE;
460 break;
461 case DUALHEAD_OFF:
462 if ((si->ps.memory_size - pointer_reservation) >=
463 (row_bytes * target->virtual_height * 2))
465 target->flags |= DUALHEAD_CAPABLE;
467 break;
471 /* set TV_CAPABLE if suitable: pixelclock is not important (defined by TVstandard) */
472 //fixme: modify for G100 and G200 TVout later on...
473 if (target->flags & DUALHEAD_CAPABLE)
475 if (si->ps.tvout &&
476 (target->timing.h_display <= 1024) &&
477 (target->timing.v_display <= 768))
479 target->flags |= TV_CAPABLE;
483 /* set HARDWARE_CURSOR mode if suitable */
484 if (si->settings.hardcursor)
485 target->flags |= B_HARDWARE_CURSOR;
487 /* set SUPPORTS_OVERLAYS */
488 target->flags |= B_SUPPORTS_OVERLAYS;
490 LOG(1, ("PROPOSEMODE: validated status modeflags: $%08x\n", target->flags));
492 /* overrule timing command flags to be (fixed) blank_pedestal = 0.0IRE,
493 * progressive scan (fixed), and sync_on_green not avaible. */
494 target->timing.flags &= ~(B_BLANK_PEDESTAL | B_TIMING_INTERLACED | B_SYNC_ON_GREEN);
495 /* The HSYNC and VSYNC command flags are actually executed by the driver. */
497 if (status == B_OK) LOG(4, ("PROPOSEMODE: completed successfully.\n"));
498 else LOG(4, ("PROPOSEMODE: mode can be made, but outside given limits.\n"));
499 return status;
502 /* Return the number of modes this device will return from GET_MODE_LIST().
503 This is precalculated in create_mode_list (called from InitAccelerant stuff)
505 uint32 ACCELERANT_MODE_COUNT(void)
507 LOG(1, ("ACCELERANT_MODE_COUNT: the modelist contains %d modes\n",si->mode_count));
509 return si->mode_count;
512 /* Copy the list of guaranteed supported video modes to the location provided.*/
513 status_t GET_MODE_LIST(display_mode *dm)
515 LOG(1, ("GET_MODE_LIST: exporting the modelist created before.\n"));
517 memcpy(dm, my_mode_list, si->mode_count * sizeof(display_mode));
518 return B_OK;
521 /* Create a list of display_modes to pass back to the caller.*/
522 status_t create_mode_list(void)
524 size_t max_size;
525 uint32
526 i, j,
527 pix_clk_range;
528 const display_mode
529 *src;
530 display_mode
531 *dst,
532 low,
533 high;
535 color_space spaces[4] = {B_RGB32_LITTLE,B_RGB16_LITTLE,B_RGB15_LITTLE,B_CMAP8};
537 /* figure out how big the list could be, and adjust up to nearest multiple of B_PAGE_SIZE */
538 max_size = (((MODE_COUNT * 4) * sizeof(display_mode)) + (B_PAGE_SIZE-1)) & ~(B_PAGE_SIZE-1);
539 /* create an area to hold the info */
540 si->mode_area = my_mode_list_area =
541 create_area("NV accelerant mode info", (void **)&my_mode_list, B_ANY_ADDRESS, max_size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
542 if (my_mode_list_area < B_OK) return my_mode_list_area;
544 /* walk through our predefined list and see which modes fit this device */
545 src = mode_list;
546 dst = my_mode_list;
547 si->mode_count = 0;
548 for (i = 0; i < MODE_COUNT; i++)
550 /* set ranges for acceptable values */
551 low = high = *src;
552 /* range is 6.25% of default clock: arbitrarily picked */
553 pix_clk_range = low.timing.pixel_clock >> 5;
554 low.timing.pixel_clock -= pix_clk_range;
555 high.timing.pixel_clock += pix_clk_range;
556 /* 'some cards need wider virtual widths for certain modes':
557 * Not true. They might need a wider pitch, but this is _not_ reflected in
558 * virtual_width, but in fbc.bytes_per_row. */
559 //So disable next line:
560 //high.virtual_width = 4096;
561 /* do it once for each depth we want to support */
562 for (j = 0; j < (sizeof(spaces) / sizeof(color_space)); j++)
564 /* set target values */
565 *dst = *src;
566 /* poke the specific space */
567 dst->space = low.space = high.space = spaces[j];
568 /* ask for a compatible mode */
569 /* We have to check for B_OK, because otherwise the pix_clk_range
570 * won't be taken into account!! */
571 //So don't do this:
572 //if (PROPOSE_DISPLAY_MODE(dst, &low, &high) != B_ERROR) {
573 //Instead, do this:
574 if (PROPOSE_DISPLAY_MODE(dst, &low, &high) == B_OK) {
575 /* count it, and move on to next mode */
576 dst++;
577 si->mode_count++;
580 /* advance to next mode */
581 src++;
584 return B_OK;