Copyright 1999, Be Incorporated. All Rights Reserved.
This file may be used under the terms of the Be Sample Code License.
Other authors:
Mark Watson,
Apsed,
Rudolf Cornelissen 11/2002-12/2015
*/
#define MODULE_BIT 0x00200000
#include "acc_std.h"
status_t SET_DISPLAY_MODE(display_mode *mode_to_set)
{
* It's impossible to deviate whatever small amount in a display_mode if the lower
* and upper limits are the same!
* Besides:
* BeOS (tested R5.0.3PE) is failing BWindowScreen::SetFrameBuffer() if PROPOSEMODE
* returns B_BAD_VALUE!
* Which means PROPOSEMODE should not return that on anything except on
* deviations for:
* display_mode.virtual_width;
* display_mode.virtual_height;
* display_mode.timing.h_display;
* display_mode.timing.v_display;
* So:
* We don't use bounds here by making sure bounds and target are the same struct!
* (See the call to PROPOSE_DISPLAY_MODE below) */
display_mode target;
uint8 colour_depth1 = 32;
uint32 startadd,startadd_right;
target = *mode_to_set;
LOG(1, ("SETMODE: (ENTER) initial modeflags: $%08x\n", target.flags));
LOG(1, ("SETMODE: requested target pixelclock %ukHz\n", target.timing.pixel_clock));
LOG(1, ("SETMODE: requested virtual_width %u, virtual_height %u\n",
target.virtual_width, target.virtual_height));
if (PROPOSE_DISPLAY_MODE(&target, &target, &target) == B_ERROR) return B_ERROR;
* note: update in _this_ order only */
si->engine.threeD.mode_changing = true;
si->engine.threeD.newmode = 0xffffffff;
* note: this also cleans up reserved channels for killed 3D clones.. */
si->engine.threeD.clones = 0x00000000;
head1_interrupt_enable(false);
if (si->ps.secondary_head) head2_interrupt_enable(false);
if (si->ps.tvout) BT_stop_tvout();
head1_dpms(false, false, false, true);
if (si->ps.secondary_head) head2_dpms(false, false, false, true);
if (si->ps.tvout) BT_dpms(false);
startadd = (uint8*)si->fbc.frame_buffer - (uint8*)si->framebuffer;
nv_general_validate_pic_size (&target, &si->fbc.bytes_per_row, &si->acc_mode);
if (target.flags & DUALHEAD_BITS)
{
uint8 colour_depth2 = colour_depth1;
display_mode target2 = target;
LOG(1,("SETMODE: setting DUALHEAD mode\n"));
if ((0) && (target2.flags & TV_BITS))
{
target.flags &= ~TV_BITS;
target2.flags &= ~TV_BITS;
LOG(1,("SETMODE: blocking TVout: no TVout cable connected!\n"));
}
if ((target.flags & DUALHEAD_BITS) == DUALHEAD_SWITCH)
nv_general_head_select(true);
else
nv_general_head_select(false);
LOG(8,("SETMODE: target clock %dkHz\n",target.timing.pixel_clock));
if (head1_set_pix_pll(target) == B_ERROR)
LOG(8,("SETMODE: error setting pixel clock (internal DAC)\n"));
LOG(8,("SETMODE: target2 clock %dkHz\n",target2.timing.pixel_clock));
if (head2_set_pix_pll(target2) == B_ERROR)
LOG(8,("SETMODE: error setting pixel clock (DAC2)\n"));
switch(target.space)
{
case B_CMAP8:
colour_depth1 = 8;
head1_mode(BPP8, 1.0);
head1_depth(BPP8);
break;
case B_RGB15_LITTLE:
colour_depth1 = 16;
head1_mode(BPP15, 1.0);
head1_depth(BPP15);
break;
case B_RGB16_LITTLE:
colour_depth1 = 16;
head1_mode(BPP16, 1.0);
head1_depth(BPP16);
break;
case B_RGB32_LITTLE:
colour_depth1 = 32;
head1_mode(BPP32, 1.0);
head1_depth(BPP32);
break;
}
switch(target2.space)
{
case B_CMAP8:
colour_depth2 = 8;
head2_mode(BPP8, 1.0);
head2_depth(BPP8);
break;
case B_RGB15_LITTLE:
colour_depth2 = 16;
head2_mode(BPP15, 1.0);
head2_depth(BPP15);
break;
case B_RGB16_LITTLE:
colour_depth2 = 16;
head2_mode(BPP16, 1.0);
head2_depth(BPP16);
break;
case B_RGB32_LITTLE:
colour_depth2 = 32;
head2_mode(BPP32, 1.0);
head2_depth(BPP32);
break;
}
si->interlaced_tv_mode = false;
head1_set_display_pitch ();
head2_set_display_pitch ();
startadd_right = startadd + (target.timing.h_display * (colour_depth1 >> 3));
switch (target.flags & DUALHEAD_BITS)
{
case DUALHEAD_ON:
case DUALHEAD_SWITCH:
head1_set_display_start(startadd,colour_depth1);
head2_set_display_start(startadd_right,colour_depth2);
break;
case DUALHEAD_CLONE:
head1_set_display_start(startadd,colour_depth1);
head2_set_display_start(startadd,colour_depth2);
break;
}
head1_set_timing(target);
head2_set_timing(target2);
if (si->ps.tvout && (target2.flags & TV_BITS)) BT_setmode(target2);
}
else
{
int colour_mode = BPP32;
if (si->ps.secondary_head)
{
nv_general_head_select(false);
}
switch(target.space)
{
case B_CMAP8: colour_depth1 = 8; colour_mode = BPP8; break;
case B_RGB15_LITTLE: colour_depth1 = 16; colour_mode = BPP15; break;
case B_RGB16_LITTLE: colour_depth1 = 16; colour_mode = BPP16; break;
case B_RGB32_LITTLE: colour_depth1 = 32; colour_mode = BPP32; break;
default:
LOG(8,("SETMODE: Invalid singlehead colour depth 0x%08x\n", target.space));
return B_ERROR;
}
if (head1_set_pix_pll(target) == B_ERROR)
LOG(8,("CRTC: error setting pixel clock (internal DAC)\n"));
head1_depth(colour_mode);
head1_mode(colour_mode,1.0);
head1_set_display_pitch();
head1_set_display_start(startadd,colour_depth1);
head1_set_timing(target);
if (si->ps.tvout && (target.flags & TV_BITS)) BT_setmode(target);
}
si->dm = target;
nv_crtc_update_fifo();
if (si->ps.secondary_head) nv_crtc2_update_fifo();
* Maybe later we can forget about non-DMA mode (depends on 3D acceleration
* attempts). */
if (!si->settings.block_acc) {
if (!si->settings.dma_acc)
nv_acc_init();
else
nv_acc_init_dma();
}
nv_bes_init();
si->engine.threeD.mem_low = si->fbc.bytes_per_row * si->dm.virtual_height;
if (si->settings.hardcursor) si->engine.threeD.mem_low += 2048;
si->engine.threeD.mem_high = si->ps.memory_size - 1;
* DriverInterface.h for an explanation). */
if (si->ps.card_arch < NV40A)
si->engine.threeD.mem_high -= PRE_NV40_OFFSET;
else
si->engine.threeD.mem_high -= NV40_PLUS_OFFSET;
si->engine.threeD.mem_high -= (MAXBUFFERS * 1024 * 1024 * 2);
SET_DPMS_MODE(si->dpms_flags);
head1_interrupt_enable(true);
si->engine.threeD.mode_changing = false;
nv_set_cas_latency();
LOG(1,("SETMODE: booted since %f mS\n", system_time()/1000.0));
return B_OK;
}
Set which pixel of the virtual frame buffer will show up in the
top left corner of the display device. Used for page-flipping
games and virtual desktops.
*/
status_t MOVE_DISPLAY(uint16 h_display_start, uint16 v_display_start) {
uint8 colour_depth;
uint32 startadd,startadd_right;
LOG(4,("MOVE_DISPLAY: h %d, v %d\n", h_display_start, v_display_start));
* No stepping granularity needed! */
switch(si->dm.space)
{
case B_CMAP8:
colour_depth=8;
break;
case B_RGB15_LITTLE:
case B_RGB16_LITTLE:
colour_depth=16;
break;
case B_RGB24_LITTLE:
colour_depth=24;
break;
case B_RGB32_LITTLE:
colour_depth=32;
break;
default:
return B_ERROR;
}
switch (si->dm.flags & DUALHEAD_BITS)
{
case DUALHEAD_ON:
case DUALHEAD_SWITCH:
if (((si->dm.timing.h_display * 2) + h_display_start) > si->dm.virtual_width)
return B_ERROR;
break;
default:
if ((si->dm.timing.h_display + h_display_start) > si->dm.virtual_width)
return B_ERROR;
break;
}
if ((si->dm.timing.v_display + v_display_start) > si->dm.virtual_height)
return B_ERROR;
si->dm.h_display_start = h_display_start;
si->dm.v_display_start = v_display_start;
startadd = v_display_start * si->fbc.bytes_per_row;
startadd += h_display_start * (colour_depth >> 3);
startadd += (uint8*)si->fbc.frame_buffer - (uint8*)si->framebuffer;
startadd_right = startadd + si->dm.timing.h_display * (colour_depth >> 3);
head1_interrupt_enable(false);
if (si->ps.secondary_head) head2_interrupt_enable(false);
switch (si->dm.flags & DUALHEAD_BITS)
{
case DUALHEAD_ON:
case DUALHEAD_SWITCH:
head1_set_display_start(startadd,colour_depth);
head2_set_display_start(startadd_right,colour_depth);
break;
case DUALHEAD_OFF:
head1_set_display_start(startadd,colour_depth);
break;
case DUALHEAD_CLONE:
head1_set_display_start(startadd,colour_depth);
head2_set_display_start(startadd,colour_depth);
break;
}
head1_interrupt_enable(true);
return B_OK;
}
void SET_INDEXED_COLORS(uint count, uint8 first, uint8 *color_data, uint32 flags) {
int i;
uint8 *r,*g,*b;
if (si->dm.space != B_CMAP8) return;
r=si->color_data;
g=r+256;
b=g+256;
i=first;
while (count--)
{
r[i]=*color_data++;
g[i]=*color_data++;
b[i]=*color_data++;
i++;
}
head1_palette(r,g,b);
if (si->dm.flags & DUALHEAD_BITS) head2_palette(r,g,b);
}
status_t SET_DPMS_MODE(uint32 dpms_flags)
{
bool display, h1h, h1v, h2h, h2v, do_p1, do_p2;
head1_interrupt_enable(false);
if (si->ps.secondary_head) head2_interrupt_enable(false);
LOG(4,("SET_DPMS_MODE: $%08x\n", dpms_flags));
si->dpms_flags = dpms_flags;
do_p1 = do_p2 = true;
display = h1h = h1v = h2h = h2v = true;
switch(dpms_flags)
{
case B_DPMS_ON:
break;
case B_DPMS_STAND_BY:
display = h1h = h2h = false;
break;
case B_DPMS_SUSPEND:
display = h1v = h2v = false;
break;
case B_DPMS_OFF:
display = h1h = h1v = h2h = h2v = false;
break;
default:
LOG(8,("SET: Invalid DPMS settings $%08x\n", dpms_flags));
head1_interrupt_enable(true);
return B_ERROR;
}
if (si->dm.flags & TV_BITS)
{
* actually assigned as being the primary head at powerup:
* so non dualhead-mode-dependant, and not 'fixed' CRTC1! */
if (si->dm.flags & TV_PRIMARY)
{
LOG(4,("SET_DPMS_MODE: tuning primary head DPMS settings for TVout compatibility\n"));
if ((si->dm.flags & DUALHEAD_BITS) != DUALHEAD_SWITCH)
{
if (!(si->settings.vga_on_tv))
{
* this specific sync setting is required: Vsync is used to keep TVout
* synchronized to the CRTC 'vertically' (otherwise 'rolling' occurs).
* This leaves Hsync only for shutting off the VGA screen. */
h1h = false;
h1v = true;
do_p1 = false;
}
else
{
* applied this way: Vsync is needed for stopping TVout successfully when
* a (new) modeswitch occurs.
* (see routine BT_stop_tvout() in nv_brooktreetv.c) */
* applying 'normal' DPMS here and forcing Vsync on in the above mentioned
* routine seems to not always be enough: sometimes image generation will
* not resume in that case. */
h1h = display;
h1v = true;
}
}
else
{
if (!(si->settings.vga_on_tv))
{
h2h = false;
h2v = true;
do_p2 = false;
}
else
{
h2h = display;
h2v = true;
}
}
}
else
{
LOG(4,("SET_DPMS_MODE: tuning secondary head DPMS settings for TVout compatibility\n"));
if ((si->dm.flags & DUALHEAD_BITS) != DUALHEAD_SWITCH)
{
if (!(si->settings.vga_on_tv))
{
h2h = false;
h2v = true;
do_p2 = false;
}
else
{
h2h = display;
h2v = true;
}
}
else
{
if (!(si->settings.vga_on_tv))
{
h1h = false;
h1v = true;
do_p1 = false;
}
else
{
h1h = display;
h1v = true;
}
}
}
}
head1_dpms(display, h1h, h1v, do_p1);
if ((si->ps.secondary_head) && (si->dm.flags & DUALHEAD_BITS))
head2_dpms(display, h2h, h2v, do_p2);
if (si->dm.flags & TV_BITS)
BT_dpms(display);
head1_interrupt_enable(true);
return B_OK;
}
uint32 DPMS_CAPABILITIES(void)
{
return (B_DPMS_ON | B_DPMS_STAND_BY | B_DPMS_SUSPEND | B_DPMS_OFF);
}
uint32 DPMS_MODE(void)
{
return si->dpms_flags;
}