tcp: Add APICall trace entry and move TRACEs into locked parts.
[haiku.git] / src / add-ons / accelerants / nvidia_gpgpu / SetDisplayMode.c
blobe5c5830870203309ff5d402aaef650bd367522a8
2 /*
3 Copyright 1999, Be Incorporated. All Rights Reserved.
4 This file may be used under the terms of the Be Sample Code License.
6 Other authors:
7 Mark Watson,
8 Apsed,
9 Rudolf Cornelissen 11/2002-6/2008
12 #define MODULE_BIT 0x00200000
14 #include "acc_std.h"
16 /* First validate the mode, then call lots of bit banging stuff to set the mode(s)! */
17 status_t SET_DISPLAY_MODE(display_mode *mode_to_set)
19 /* BOUNDS WARNING:
20 * It's impossible to deviate whatever small amount in a display_mode if the lower
21 * and upper limits are the same!
22 * Besides:
23 * BeOS (tested R5.0.3PE) is failing BWindowScreen::SetFrameBuffer() if PROPOSEMODE
24 * returns B_BAD_VALUE!
25 * Which means PROPOSEMODE should not return that on anything except on
26 * deviations for:
27 * display_mode.virtual_width;
28 * display_mode.virtual_height;
29 * display_mode.timing.h_display;
30 * display_mode.timing.v_display;
31 * So:
32 * We don't use bounds here by making sure bounds and target are the same struct!
33 * (See the call to PROPOSE_DISPLAY_MODE below) */
34 display_mode /*bounds,*/ target;
36 uint8 colour_depth1 = 32;
37 uint32 startadd,startadd_right;
38 // bool crt1, crt2, cross;
40 /* Adjust mode to valid one and fail if invalid */
41 target /*= bounds*/ = *mode_to_set;
42 /* show the mode bits */
43 LOG(1, ("SETMODE: (ENTER) initial modeflags: $%08x\n", target.flags));
44 LOG(1, ("SETMODE: requested target pixelclock %dkHz\n", target.timing.pixel_clock));
45 LOG(1, ("SETMODE: requested virtual_width %d, virtual_height %d\n",
46 target.virtual_width, target.virtual_height));
48 /* See BOUNDS WARNING above... */
49 if (PROPOSE_DISPLAY_MODE(&target, &target, &target) == B_ERROR) return B_ERROR;
51 /* make sure a possible 3D add-on will block rendering and re-initialize itself.
52 * note: update in _this_ order only */
53 /* SET_DISPLAY_MODE will reset this flag when it's done. */
54 si->engine.threeD.mode_changing = true;
55 /* every 3D add-on will reset this bit-flag when it's done. */
56 si->engine.threeD.newmode = 0xffffffff;
57 /* every 3D clone needs to reclaim a slot.
58 * note: this also cleans up reserved channels for killed 3D clones.. */
59 si->engine.threeD.clones = 0x00000000;
61 /* disable interrupts using the kernel driver */
62 // head1_interrupt_enable(false);
63 // if (si->ps.secondary_head) head2_interrupt_enable(false);
65 /* turn off screen(s) */
66 // head1_dpms(false, false, false, true);
67 // if (si->ps.secondary_head) head2_dpms(false, false, false, true);
69 /*where in framebuffer the screen is (should this be dependant on previous MOVEDISPLAY?)*/
70 startadd = (uint8*)si->fbc.frame_buffer - (uint8*)si->framebuffer;
72 /* calculate and set new mode bytes_per_row */
73 nv_general_validate_pic_size (&target, &si->fbc.bytes_per_row, &si->acc_mode);
75 /*Perform the very long mode switch!*/
76 if (target.flags & DUALHEAD_BITS) /*if some dualhead mode*/
78 uint8 colour_depth2 = colour_depth1;
80 /* init display mode for secondary head */
81 display_mode target2 = target;
83 LOG(1,("SETMODE: setting DUALHEAD mode\n"));
85 /* detect which connectors have a CRT connected */
86 //fixme: 'hot-plugging' for analog monitors removed: remove code as well;
87 //or make it work with digital panels connected as well.
88 // crt1 = nv_dac_crt_connected();
89 // crt2 = nv_dac2_crt_connected();
90 /* connect outputs 'straight-through' */
91 // if (crt1)
92 // {
93 /* connector1 is used as primary output */
94 // cross = false;
95 // }
96 // else
97 // {
98 // if (crt2)
99 /* connector2 is used as primary output */
100 // cross = true;
101 // else
102 /* no CRT detected: assume connector1 is used as primary output */
103 // cross = false;
104 // }
105 /* set output connectors assignment if possible */
106 // if ((target.flags & DUALHEAD_BITS) == DUALHEAD_SWITCH)
107 /* invert output assignment in switch mode */
108 // nv_general_head_select(true);
109 // else
110 // nv_general_head_select(false);
112 /* set the pixel clock PLL(s) */
113 LOG(8,("SETMODE: target clock %dkHz\n",target.timing.pixel_clock));
114 // if (head1_set_pix_pll(target) == B_ERROR)
115 // LOG(8,("SETMODE: error setting pixel clock (internal DAC)\n"));
117 LOG(8,("SETMODE: target2 clock %dkHz\n",target2.timing.pixel_clock));
118 // if (head2_set_pix_pll(target2) == B_ERROR)
119 // LOG(8,("SETMODE: error setting pixel clock (DAC2)\n"));
121 /*set the colour depth for CRTC1 and the DAC */
122 switch(target.space)
124 case B_CMAP8:
125 colour_depth1 = 8;
126 // head1_mode(BPP8, 1.0);
127 // head1_depth(BPP8);
128 break;
129 case B_RGB15_LITTLE:
130 colour_depth1 = 16;
131 // head1_mode(BPP15, 1.0);
132 // head1_depth(BPP15);
133 break;
134 case B_RGB16_LITTLE:
135 colour_depth1 = 16;
136 // head1_mode(BPP16, 1.0);
137 // head1_depth(BPP16);
138 break;
139 case B_RGB32_LITTLE:
140 colour_depth1 = 32;
141 // head1_mode(BPP32, 1.0);
142 // head1_depth(BPP32);
143 break;
145 /*set the colour depth for CRTC2 and DAC2 */
146 switch(target2.space)
148 case B_CMAP8:
149 colour_depth2 = 8;
150 // head2_mode(BPP8, 1.0);
151 // head2_depth(BPP8);
152 break;
153 case B_RGB15_LITTLE:
154 colour_depth2 = 16;
155 // head2_mode(BPP15, 1.0);
156 // head2_depth(BPP15);
157 break;
158 case B_RGB16_LITTLE:
159 colour_depth2 = 16;
160 // head2_mode(BPP16, 1.0);
161 // head2_depth(BPP16);
162 break;
163 case B_RGB32_LITTLE:
164 colour_depth2 = 32;
165 // head2_mode(BPP32, 1.0);
166 // head2_depth(BPP32);
167 break;
170 /*set the display(s) pitches*/
171 // head1_set_display_pitch ();
172 //fixme: seperate for real dualhead modes:
173 //we need a secondary si->fbc!
174 // head2_set_display_pitch ();
176 /*work out where the "right" screen starts*/
177 startadd_right = startadd + (target.timing.h_display * (colour_depth1 >> 3));
179 /* Tell card what memory to display */
180 switch (target.flags & DUALHEAD_BITS)
182 case DUALHEAD_ON:
183 case DUALHEAD_SWITCH:
184 // head1_set_display_start(startadd,colour_depth1);
185 // head2_set_display_start(startadd_right,colour_depth2);
186 break;
187 case DUALHEAD_CLONE:
188 // head1_set_display_start(startadd,colour_depth1);
189 // head2_set_display_start(startadd,colour_depth2);
190 break;
193 /* set the timing */
194 // head1_set_timing(target);
195 // head2_set_timing(target2);
197 else /* single head mode */
199 int colour_mode = BPP32;
201 /* connect output */
202 if (si->ps.secondary_head)
204 /* detect which connectors have a CRT connected */
205 //fixme: 'hot-plugging' for analog monitors removed: remove code as well;
206 //or make it work with digital panels connected as well.
207 // crt1 = nv_dac_crt_connected();
208 // crt2 = nv_dac2_crt_connected();
209 /* connect outputs 'straight-through' */
210 // if (crt1)
211 // {
212 /* connector1 is used as primary output */
213 // cross = false;
214 // }
215 // else
216 // {
217 // if (crt2)
218 /* connector2 is used as primary output */
219 // cross = true;
220 // else
221 /* no CRT detected: assume connector1 is used as primary output */
222 // cross = false;
223 // }
224 /* set output connectors assignment if possible */
225 nv_general_head_select(false);
228 switch(target.space)
230 case B_CMAP8: colour_depth1 = 8; colour_mode = BPP8; break;
231 case B_RGB15_LITTLE: colour_depth1 = 16; colour_mode = BPP15; break;
232 case B_RGB16_LITTLE: colour_depth1 = 16; colour_mode = BPP16; break;
233 case B_RGB32_LITTLE: colour_depth1 = 32; colour_mode = BPP32; break;
234 default:
235 LOG(8,("SETMODE: Invalid singlehead colour depth 0x%08x\n", target.space));
236 return B_ERROR;
239 /* set the pixel clock PLL */
240 // if (head1_set_pix_pll(target) == B_ERROR)
241 // LOG(8,("CRTC: error setting pixel clock (internal DAC)\n"));
243 /* set the colour depth for CRTC1 and the DAC */
244 /* first set the colordepth */
245 // head1_depth(colour_mode);
246 /* then(!) program the PAL (<8bit colordepth does not support 8bit PAL) */
247 // head1_mode(colour_mode,1.0);
249 /* set the display pitch */
250 // head1_set_display_pitch();
252 /* tell the card what memory to display */
253 // head1_set_display_start(startadd,colour_depth1);
255 /* set the timing */
256 // head1_set_timing(target);
258 //fixme: shut-off the videoPLL if it exists...
261 /* update driver's mode store */
262 si->dm = target;
264 /* update FIFO data fetching according to mode */
265 // nv_crtc_update_fifo();
266 // if (si->ps.secondary_head) nv_crtc2_update_fifo();
268 /* set up acceleration for this mode */
269 /* note:
270 * Maybe later we can forget about non-DMA mode (depends on 3D acceleration
271 * attempts). */
272 //no acc support for G8x yet!
273 if (si->ps.card_arch < NV50A)
275 nv_acc_init_dma();
277 /* set up overlay unit for this mode */
278 // nv_bes_init();
280 /* note freemem range */
281 /* first free adress follows hardcursor and workspace */
282 si->engine.threeD.mem_low = si->fbc.bytes_per_row * si->dm.virtual_height;
283 if (si->settings.hardcursor) si->engine.threeD.mem_low += 2048;
284 /* last free adress is end-of-ram minus max space needed for overlay bitmaps */
285 //fixme possible:
286 //if overlay buffers are allocated subtract buffersize from mem_high;
287 //only allocate overlay buffers if 3D is not in use. (block overlay during 3D)
288 si->engine.threeD.mem_high = si->ps.memory_size - 1;
289 /* Keep some extra distance as a workaround for certain bugs (see
290 * DriverInterface.h for an explanation). */
291 si->engine.threeD.mem_high -= NV40_PLUS_OFFSET;
293 /* restore screen(s) output state(s) */
294 // SET_DPMS_MODE(si->dpms_flags);
296 /* enable interrupts using the kernel driver */
297 //fixme:
298 //add head2 once we use one driver instance 'per head' (instead of 'per card')
299 // head1_interrupt_enable(true);
301 /* make sure a possible 3D add-on will re-initialize itself by signalling ready */
302 si->engine.threeD.mode_changing = false;
304 /* optimize memory-access if needed */
305 // head1_mem_priority(colour_depth1);
307 /* Tune RAM CAS-latency if needed. Must be done *here*! */
308 // nv_set_cas_latency();
310 LOG(1,("SETMODE: booted since %f mS\n", system_time()/1000.0));
312 return B_OK;
316 Set which pixel of the virtual frame buffer will show up in the
317 top left corner of the display device. Used for page-flipping
318 games and virtual desktops.
320 status_t MOVE_DISPLAY(uint16 h_display_start, uint16 v_display_start) {
321 uint8 colour_depth;
322 uint32 startadd,startadd_right;
324 LOG(4,("MOVE_DISPLAY: h %d, v %d\n", h_display_start, v_display_start));
326 /* nVidia cards support pixelprecise panning on both heads in all modes:
327 * No stepping granularity needed! */
329 /* determine bits used for the colordepth */
330 switch(si->dm.space)
332 case B_CMAP8:
333 colour_depth=8;
334 break;
335 case B_RGB15_LITTLE:
336 case B_RGB16_LITTLE:
337 colour_depth=16;
338 break;
339 case B_RGB24_LITTLE:
340 colour_depth=24;
341 break;
342 case B_RGB32_LITTLE:
343 colour_depth=32;
344 break;
345 default:
346 return B_ERROR;
349 /* do not run past end of display */
350 switch (si->dm.flags & DUALHEAD_BITS)
352 case DUALHEAD_ON:
353 case DUALHEAD_SWITCH:
354 if (((si->dm.timing.h_display * 2) + h_display_start) > si->dm.virtual_width)
355 return B_ERROR;
356 break;
357 default:
358 if ((si->dm.timing.h_display + h_display_start) > si->dm.virtual_width)
359 return B_ERROR;
360 break;
362 if ((si->dm.timing.v_display + v_display_start) > si->dm.virtual_height)
363 return B_ERROR;
365 /* everybody remember where we parked... */
366 si->dm.h_display_start = h_display_start;
367 si->dm.v_display_start = v_display_start;
369 /* actually set the registers */
370 //fixme: seperate both heads: we need a secondary si->fbc!
371 startadd = v_display_start * si->fbc.bytes_per_row;
372 startadd += h_display_start * (colour_depth >> 3);
373 startadd += (uint8*)si->fbc.frame_buffer - (uint8*)si->framebuffer;
374 startadd_right = startadd + si->dm.timing.h_display * (colour_depth >> 3);
376 /* disable interrupts using the kernel driver */
377 head1_interrupt_enable(false);
378 if (si->ps.secondary_head) head2_interrupt_enable(false);
380 switch (si->dm.flags & DUALHEAD_BITS)
382 case DUALHEAD_ON:
383 case DUALHEAD_SWITCH:
384 head1_set_display_start(startadd,colour_depth);
385 head2_set_display_start(startadd_right,colour_depth);
386 break;
387 case DUALHEAD_OFF:
388 head1_set_display_start(startadd,colour_depth);
389 break;
390 case DUALHEAD_CLONE:
391 head1_set_display_start(startadd,colour_depth);
392 head2_set_display_start(startadd,colour_depth);
393 break;
396 //fixme:
397 //add head2 once we use one driver instance 'per head' (instead of 'per card')
398 head1_interrupt_enable(true);
400 return B_OK;
403 /* Set the indexed color palette */
404 void SET_INDEXED_COLORS(uint count, uint8 first, uint8 *color_data, uint32 flags) {
405 int i;
406 uint8 *r,*g,*b;
408 /* Protect gamma correction when not in CMAP8 */
409 if (si->dm.space != B_CMAP8) return;
411 r=si->color_data;
412 g=r+256;
413 b=g+256;
415 i=first;
416 while (count--)
418 r[i]=*color_data++;
419 g[i]=*color_data++;
420 b[i]=*color_data++;
421 i++;
423 head1_palette(r,g,b);
424 if (si->dm.flags & DUALHEAD_BITS) head2_palette(r,g,b);
427 /* Put the display into one of the Display Power Management modes. */
428 status_t SET_DPMS_MODE(uint32 dpms_flags)
430 bool display, h1h, h1v, h2h, h2v, do_p1, do_p2;
432 /* disable interrupts using the kernel driver */
433 head1_interrupt_enable(false);
434 if (si->ps.secondary_head) head2_interrupt_enable(false);
436 LOG(4,("SET_DPMS_MODE: $%08x\n", dpms_flags));
438 /* note current DPMS state for our reference */
439 si->dpms_flags = dpms_flags;
441 /* preset: DPMS for panels should be executed */
442 do_p1 = do_p2 = true;
444 /* determine signals to send to head(s) */
445 display = h1h = h1v = h2h = h2v = true;
446 switch(dpms_flags)
448 case B_DPMS_ON: /* H: on, V: on, display on */
449 break;
450 case B_DPMS_STAND_BY:
451 display = h1h = h2h = false;
452 break;
453 case B_DPMS_SUSPEND:
454 display = h1v = h2v = false;
455 break;
456 case B_DPMS_OFF: /* H: off, V: off, display off */
457 display = h1h = h1v = h2h = h2v = false;
458 break;
459 default:
460 LOG(8,("SET: Invalid DPMS settings $%08x\n", dpms_flags));
461 //fixme:
462 //add head2 once we use one driver instance 'per head' (instead of 'per card')
463 head1_interrupt_enable(true);
465 return B_ERROR;
468 /* issue actual DPMS commands as far as applicable */
469 head1_dpms(display, h1h, h1v, do_p1);
470 if ((si->ps.secondary_head) && (si->dm.flags & DUALHEAD_BITS))
471 head2_dpms(display, h2h, h2v, do_p2);
473 //fixme:
474 //add head2 once we use one driver instance 'per head' (instead of 'per card')
475 head1_interrupt_enable(true);
477 return B_OK;
480 /* Report device DPMS capabilities */
481 uint32 DPMS_CAPABILITIES(void)
483 return (B_DPMS_ON | B_DPMS_STAND_BY | B_DPMS_SUSPEND | B_DPMS_OFF);
486 /* Return the current DPMS mode */
487 uint32 DPMS_MODE(void)
489 return si->dpms_flags;