Copyright 1999, Be Incorporated. All Rights Reserved.
This file may be used under the terms of the Be Sample Code License.
Other authors for NV driver:
Mark Watson,
Rudolf Cornelissen 9/2002-1/2016
*/
#define MODULE_BIT 0x00400000
#include "acc_std.h"
#define T_POSITIVE_SYNC (B_POSITIVE_HSYNC | B_POSITIVE_VSYNC)
#define MODE_FLAGS 0
#define MODE_COUNT (sizeof (mode_list) / sizeof (display_mode))
* plus panel specific resolution modes which are internally modified during run-time depending on the requirements of the actual
* panel connected. The modes as listed here, should timing-wise be as compatible with analog (CRT) monitors as can be... */
static const display_mode mode_list[] = {
{ { 25175, 640, 656, 752, 800, 480, 490, 492, 525, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS},
{ { 27500, 640, 672, 768, 864, 480, 488, 494, 530, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS},
{ { 30500, 640, 672, 768, 864, 480, 517, 523, 588, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS},
{ { 31500, 640, 664, 704, 832, 480, 489, 492, 520, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS},
{ { 31500, 640, 656, 720, 840, 480, 481, 484, 500, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS},
{ { 36000, 640, 696, 752, 832, 480, 481, 484, 509, 0}, B_CMAP8, 640, 480, 0, 0, MODE_FLAGS},
{ { 36000, 800, 824, 896, 1024, 600, 601, 603, 625, 0}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS},
{ { 38100, 800, 832, 960, 1088, 600, 602, 606, 620, 0}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS},
{ { 40000, 800, 840, 968, 1056, 600, 601, 605, 628, T_POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS},
{ { 49500, 800, 816, 896, 1056, 600, 601, 604, 625, T_POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS},
{ { 50000, 800, 856, 976, 1040, 600, 637, 643, 666, T_POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS},
{ { 56250, 800, 832, 896, 1048, 600, 601, 604, 631, T_POSITIVE_SYNC}, B_CMAP8, 800, 600, 0, 0, MODE_FLAGS},
{ { 65000, 1024, 1048, 1184, 1344, 768, 771, 777, 806, 0}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS},
{ { 75000, 1024, 1048, 1184, 1328, 768, 771, 777, 806, 0}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS},
{ { 78750, 1024, 1040, 1136, 1312, 768, 769, 772, 800, T_POSITIVE_SYNC}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS},
{ { 94500, 1024, 1072, 1168, 1376, 768, 769, 772, 808, T_POSITIVE_SYNC}, B_CMAP8, 1024, 768, 0, 0, MODE_FLAGS},
{ { 94200, 1152, 1184, 1280, 1472, 864, 865, 868, 914, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS},
{ { 97800, 1152, 1216, 1344, 1552, 864, 865, 868, 900, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS},
{ { 108000, 1152, 1216, 1344, 1600, 864, 865, 868, 900, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS},
{ { 121500, 1152, 1216, 1344, 1568, 864, 865, 868, 911, T_POSITIVE_SYNC}, B_CMAP8, 1152, 864, 0, 0, MODE_FLAGS},
{ { 108000, 1280, 1328, 1440, 1688, 1024, 1025, 1028, 1066, T_POSITIVE_SYNC}, B_CMAP8, 1280, 1024, 0, 0, MODE_FLAGS},
{ { 135000, 1280, 1296, 1440, 1688, 1024, 1025, 1028, 1066, T_POSITIVE_SYNC}, B_CMAP8, 1280, 1024, 0, 0, MODE_FLAGS},
{ { 157500, 1280, 1344, 1504, 1728, 1024, 1025, 1028, 1072, T_POSITIVE_SYNC}, B_CMAP8, 1280, 1024, 0, 0, MODE_FLAGS},
{ { 122600, 1400, 1488, 1640, 1880, 1050, 1051, 1054, 1087, T_POSITIVE_SYNC}, B_CMAP8, 1400, 1050, 0, 0, MODE_FLAGS},
{ { 162000, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS},
{ { 175500, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS},
{ { 189000, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS},
{ { 202500, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS},
{ { 216000, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS},
{ { 229500, 1600, 1664, 1856, 2160, 1200, 1201, 1204, 1250, T_POSITIVE_SYNC}, B_CMAP8, 1600, 1200, 0, 0, MODE_FLAGS},
{ { 204750, 1792, 1920, 2120, 2448, 1344, 1345, 1348, 1394, B_POSITIVE_VSYNC}, B_CMAP8, 1792, 1344, 0, 0, MODE_FLAGS},
{ { 261000, 1792, 1888, 2104, 2456, 1344, 1345, 1348, 1417, B_POSITIVE_VSYNC}, B_CMAP8, 1792, 1344, 0, 0, MODE_FLAGS},
{ { 218250, 1856, 1952, 2176, 2528, 1392, 1393, 1396, 1439, B_POSITIVE_VSYNC}, B_CMAP8, 1856, 1392, 0, 0, MODE_FLAGS},
{ { 288000, 1856, 1984, 2208, 2560, 1392, 1393, 1396, 1500, B_POSITIVE_VSYNC}, B_CMAP8, 1856, 1392, 0, 0, MODE_FLAGS},
{ { 234000, 1920, 2048, 2256, 2600, 1440, 1441, 1444, 1500, B_POSITIVE_VSYNC}, B_CMAP8, 1920, 1440, 0, 0, MODE_FLAGS},
{ { 297000, 1920, 2064, 2288, 2640, 1440, 1441, 1444, 1500, B_POSITIVE_VSYNC}, B_CMAP8, 1920, 1440, 0, 0, MODE_FLAGS},
{ { 266950, 2048, 2200, 2424, 2800, 1536, 1537, 1540, 1589, B_POSITIVE_VSYNC}, B_CMAP8, 2048, 1536, 0, 0, MODE_FLAGS},
{ { 31300, 800, 848, 928, 1008, 500, 501, 504, 518, T_POSITIVE_SYNC}, B_CMAP8, 800, 500, 0, 0, MODE_FLAGS},
{ { 52800, 1024, 1072, 1176, 1328, 640, 641, 644, 663, T_POSITIVE_SYNC}, B_CMAP8, 1024, 640, 0, 0, MODE_FLAGS},
{ { 80135, 1280, 1344, 1480, 1680, 768, 769, 772, 795, T_POSITIVE_SYNC}, B_CMAP8, 1280, 768, 0, 0, MODE_FLAGS},
{ { 83500, 1280, 1344, 1480, 1680, 800, 801, 804, 828, T_POSITIVE_SYNC}, B_CMAP8, 1280, 800, 0, 0, MODE_FLAGS},
{ { 106500, 1440, 1520, 1672, 1904, 900, 901, 904, 932, T_POSITIVE_SYNC}, B_CMAP8, 1440, 900, 0, 0, MODE_FLAGS},
{ { 147100, 1680, 1784, 1968, 2256, 1050, 1051, 1054, 1087, T_POSITIVE_SYNC}, B_CMAP8, 1680, 1050, 0, 0, MODE_FLAGS},
{ { 193160, 1920, 2048, 2256, 2592, 1200, 1201, 1204, 1242, T_POSITIVE_SYNC}, B_CMAP8, 1920, 1200, 0, 0, MODE_FLAGS},
{ { 74520, 1280, 1368, 1424, 1656, 720, 724, 730, 750, T_POSITIVE_SYNC}, B_CMAP8, 1280, 720, 0, 0, MODE_FLAGS},
note: horizontal CRTC timing must be a multiple of 8! (hardware restriction) */
{ { 85500, 1368, 1440, 1576, 1792, 768, 771, 774, 798, T_POSITIVE_SYNC}, B_CMAP8, 1368, 768, 0, 0, MODE_FLAGS},
{ { 148500, 1920, 2008, 2052, 2200, 1080, 1084, 1089, 1125, T_POSITIVE_SYNC}, B_CMAP8, 1920, 1080, 0, 0, MODE_FLAGS},
};
static void Haiku_DetectTranslateMultiMode(display_mode *mode)
{
mode->flags &= ~DUALHEAD_BITS;
if( mode->virtual_width == 2 * mode->timing.h_display ) {
LOG(4, ("Haiku: horizontal combine mode\n"));
if (si->Haiku_switch_head)
mode->flags |= DUALHEAD_SWITCH;
else
mode->flags |= DUALHEAD_ON;
} else if( mode->virtual_height == 2 * mode->timing.v_display ) {
LOG(4, ("Haiku: vertical combine mode not supported\n"));
} else {
activate both heads always to (probably) mimic Radeon driver behaviour (for which this app was adapted) */
- this will have a big downside on hardware for which both heads have different resolution cababilities (i.e. Matrox);
- also (on laptops) this will shorten battery life a bit of course.. */
mode->flags |= DUALHEAD_CLONE;
}
}
static status_t Haiku_CheckMultiMonTunnel(display_mode *mode, const display_mode *low, const display_mode *high, bool *isTunneled )
{
if( (mode->timing.flags & RADEON_MODE_MULTIMON_REQUEST) != 0 &&
(mode->timing.flags & RADEON_MODE_MULTIMON_REPLY) == 0 )
{
mode->timing.flags &= ~RADEON_MODE_MULTIMON_REQUEST;
mode->timing.flags |= RADEON_MODE_MULTIMON_REPLY;
*isTunneled = true;
return B_OK;
}
if( mode->space != 0 || low->space != 0 || high->space != 0
|| low->virtual_width != 0xffff || low->virtual_height != 0xffff
|| high->virtual_width != 0 || high->virtual_height != 0
|| mode->timing.pixel_clock != 0
|| low->timing.pixel_clock != 'TKTK' || high->timing.pixel_clock != 'KTKT' )
{
*isTunneled = false;
return B_OK;
}
*isTunneled = true;
if (!si->haiku_prefs_used)
LOG(4, ("PROPOSEMODE: Haiku screenprefs tunnel detected.\n"));
si->haiku_prefs_used = true;
Haiku ScreenPrefs does not issue a SetMode command after changing these settings (per se), but relies on
driver switching outputs directly. These settings are not dependant on workspace there, and are not part of
the mode in the Radeon driver. In the Matrox and nVidia drivers they are though. So we need SetMode
to be issued. (yes: sometimes I switch monitors when I switch workspace.. ;-)
Also the RADEON driver saves these settings to a file so it remembers these after reboots. We don't atm.
If the mode as proposed by the driver would be saved by the ScreenPrefs panel, we would 'remember' it over
reboots though (via app_server settings).. */
switch( mode->h_display_start ) {
case ms_swap:
switch( mode->v_display_start ) {
case 0:
if (si->Haiku_switch_head)
mode->timing.flags = 1;
else
mode->timing.flags = 0;
LOG(4, ("Haiku: tunnel access target=swap, command=get, value=%u\n", mode->timing.flags));
return B_OK;
case 1:
si->Haiku_switch_head = mode->timing.flags != 0;
LOG(4, ("Haiku: tunnel access target=swap, command=set, value=%u\n", mode->timing.flags));
SET_DISPLAY_MODE(&si->dm);
return B_OK;
}
break;
case ms_use_laptop_panel:
LOG(4, ("Haiku: tunnel access target=usepanel, command=%s, value=%u\n",
(mode->v_display_start == 1) ? "set" : "get", mode->timing.flags));
return B_ERROR;
break;
case ms_tv_standard:
LOG(4, ("Haiku: tunnel access target=tvstandard, command=%s, value=%u\n",
(mode->v_display_start == 1) ? "set" : "get", mode->timing.flags));
return B_ERROR;
break;
}
LOG(4, ("Haiku: unhandled tunnel access target=$%x, command=%u, value=%u\n",
mode->h_display_start, mode->v_display_start, mode->timing.flags));
return B_ERROR;
}
Check mode is between low and high limits.
Returns:
B_OK - found one
B_BAD_VALUE - mode can be made, but outside limits
B_ERROR - not possible
*/
* BeOS (tested R5.0.3PE) is failing BWindowScreen.SetFrameBuffer() if PROPOSEMODE
* returns B_BAD_VALUE. It's called by the OS with target, low and high set to
* have the same settings for BWindowScreen!
* Which means we should not return B_BAD_VALUE on anything except for deviations on:
* display_mode.virtual_width;
* display_mode.virtual_height;
* display_mode.timing.h_display;
* display_mode.timing.v_display;
*/
* The target mode should be modified to correspond to the mode as it can be made. */
status_t
PROPOSE_DISPLAY_MODE(display_mode *target, const display_mode *low, const display_mode *high)
{
status_t status = B_OK;
float pix_clock_found, target_aspect;
uint8 m,n,p, bpp;
status_t result;
uint32 max_vclk, row_bytes, mem_reservation;
bool acc_mode;
double target_refresh = ((double)target->timing.pixel_clock * 1000.0)
/ ((double)target->timing.h_total * (double)target->timing.v_total);
bool want_same_width = target->timing.h_display == target->virtual_width;
bool want_same_height = target->timing.v_display == target->virtual_height;
bool isTunneled = false;
result = Haiku_CheckMultiMonTunnel(target, low, high, &isTunneled);
if (isTunneled)
return result;
them from (for us) non-native modes to native modes (as used in DualheadSetup by Mark Watson).
These 'native modes' survive system reboots by the way, at least when set using DualheadSetup. */
by the ScreenPrefs panel. Modifications done by the driver are therefore not saved.
It would be nice if the screenprefs panel in Haiku would save the modified modeflags (after proposemode or setmode),
that would also make the driver remember switched heads (now it's a temporary setting). */
if (si->haiku_prefs_used) {
Haiku_DetectTranslateMultiMode(target);
}
LOG(1, ("PROPOSEMODE: (ENTER) requested virtual_width %d, virtual_height %d\n",
target->virtual_width, target->virtual_height));
result = head1_validate_timing(&target->timing.h_display,
&target->timing.h_sync_start, &target->timing.h_sync_end,
&target->timing.h_total, &target->timing.v_display,
&target->timing.v_sync_start, &target->timing.v_sync_end,
&target->timing.v_total);
if (result == B_ERROR) {
LOG(4, ("PROPOSEMODE: could not validate timing, aborted.\n"));
return result;
}
if (!si->ps.tvout
|| !(BT_check_tvmode(*target) && (target->flags & TV_BITS))) {
* assuming 16:10 screens can display non-WS modes, but cannot (correctly) display 16:9 modes;
* assuming 16:9 screens can display non-WS modes, and can display 16:10 modes. */
target_aspect = (target->timing.h_display / ((float)target->timing.v_display));
* allow 0.10 difference so 5:4 aspect panels will be able to use 4:3 aspect modes! */
switch (si->ps.monitors) {
case 0:
if (target_aspect > 1.34 && !si->settings.force_ws) {
LOG(4, ("PROPOSEMODE: not all output devices can display widescreen modes, aborted.\n"));
return B_ERROR;
}
break;
case CRTC1_TMDS:
case CRTC1_VGA:
if (si->ps.crtc1_screen.aspect < (target_aspect - 0.10)) {
LOG(4, ("PROPOSEMODE: screen at crtc1 is not widescreen (enough) type, aborted.\n"));
return B_ERROR;
}
break;
case CRTC2_TMDS:
case CRTC2_VGA:
if (si->ps.crtc2_screen.aspect < (target_aspect - 0.10)) {
LOG(4, ("PROPOSEMODE: screen at crtc2 is not widescreen (enough) type, aborted.\n"));
return B_ERROR;
}
break;
case CRTC1_TMDS | CRTC2_TMDS:
case CRTC1_VGA | CRTC2_VGA:
case CRTC1_TMDS | CRTC2_VGA:
case CRTC1_VGA | CRTC2_TMDS:
default:
if ((si->ps.crtc1_screen.aspect < (target_aspect - 0.10)) ||
(si->ps.crtc2_screen.aspect < (target_aspect - 0.10))) {
LOG(4, ("PROPOSEMODE: not all connected screens are widescreen (enough) type, aborted.\n"));
return B_ERROR;
}
break;
}
}
(because of errors in monitor's EDID information returned) */
if (si->settings.check_edid) {
note:
allowing 2 pixels more for horizontal display for the 1366 mode, since multiples of 8
are required for the CRTCs horizontal timing programming) */
if (si->ps.crtc1_screen.have_native_edid) {
if ((target->timing.h_display - 2) > si->ps.crtc1_screen.timing.h_display
|| target->timing.v_display > si->ps.crtc1_screen.timing.v_display) {
LOG(4, ("PROPOSEMODE: screen at crtc1 can't display requested resolution, aborted.\n"));
return B_ERROR;
}
}
if (si->ps.crtc2_screen.have_native_edid) {
if ((target->timing.h_display - 2) > si->ps.crtc2_screen.timing.h_display
|| target->timing.v_display > si->ps.crtc2_screen.timing.v_display) {
LOG(4, ("PROPOSEMODE: screen at crtc2 can't display requested resolution, aborted.\n"));
return B_ERROR;
}
}
}
if (target->timing.h_display > target->virtual_width || want_same_width)
target->virtual_width = target->timing.h_display;
if (target->timing.v_display > target->virtual_height || want_same_height)
target->virtual_height = target->timing.v_display;
result = nv_general_validate_pic_size(target, &row_bytes, &acc_mode);
if (result == B_ERROR) {
LOG(4, ("PROPOSEMODE: could not validate virtual picture size, aborted.\n"));
return result;
}
if (target->virtual_width < low->virtual_width
|| target->virtual_width > high->virtual_width) {
status = B_BAD_VALUE;
LOG(4, ("PROPOSEMODE: WARNING: virtual_width deviates too much\n"));
}
if (target->timing.h_display < low->timing.h_display
|| target->timing.h_display > high->timing.h_display
|| target->timing.h_sync_start < low->timing.h_sync_start
|| target->timing.h_sync_start > high->timing.h_sync_start
|| target->timing.h_sync_end < low->timing.h_sync_end
|| target->timing.h_sync_end > high->timing.h_sync_end
|| target->timing.h_total < low->timing.h_total
|| target->timing.h_total > high->timing.h_total) {
if (target->timing.h_display < low->timing.h_display
|| target->timing.h_display > high->timing.h_display)
status = B_BAD_VALUE;
LOG(4, ("PROPOSEMODE: WARNING: horizontal timing deviates too much\n"));
}
if (target->timing.v_display < low->timing.v_display
|| target->timing.v_display > high->timing.v_display
|| target->timing.v_sync_start < low->timing.v_sync_start
|| target->timing.v_sync_start > high->timing.v_sync_start
|| target->timing.v_sync_end < low->timing.v_sync_end
|| target->timing.v_sync_end > high->timing.v_sync_end
|| target->timing.v_total < low->timing.v_total
|| target->timing.v_total > high->timing.v_total) {
if (target->timing.v_display < low->timing.v_display
|| target->timing.v_display > high->timing.v_display)
status = B_BAD_VALUE;
LOG(4, ("PROPOSEMODE: WARNING: vertical timing deviates too much\n"));
}
target->timing.pixel_clock = target_refresh * ((double)target->timing.h_total)
* ((double)target->timing.v_total) / 1000.0;
* this also makes sure we don't generate more pixel bandwidth than the device can handle */
result = head1_pix_pll_find(*target, &pix_clock_found, &m, &n, &p, 0);
target->timing.pixel_clock = pix_clock_found * 1000;
if (target->timing.pixel_clock < low->timing.pixel_clock
|| target->timing.pixel_clock > high->timing.pixel_clock) {
if (target->timing.pixel_clock < low->timing.pixel_clock - 1000
|| target->timing.pixel_clock > high->timing.pixel_clock + 1000)
status = B_BAD_VALUE;
LOG(4, ("PROPOSEMODE: WARNING: pixelclock deviates too much\n"));
}
mem_reservation = 0;
if (si->settings.hardcursor)
mem_reservation = 2048;
* for an explanation). */
if (si->ps.card_arch < NV40A)
mem_reservation += PRE_NV40_OFFSET;
else
mem_reservation += NV40_PLUS_OFFSET;
if (row_bytes * target->virtual_height > si->ps.memory_size - mem_reservation) {
target->virtual_height = (si->ps.memory_size - mem_reservation) / row_bytes;
}
if (target->virtual_height < target->timing.v_display) {
LOG(4,("PROPOSEMODE: not enough memory for current mode, aborted.\n"));
return B_ERROR;
}
LOG(4,("PROPOSEMODE: validated virtual_width %d, virtual_height %d pixels\n",
target->virtual_width, target->virtual_height));
if (target->virtual_height < low->virtual_height
|| target->virtual_height > high->virtual_height) {
status = B_BAD_VALUE;
LOG(4, ("PROPOSEMODE: WARNING: virtual_height deviates too much\n"));
}
LOG(1, ("PROPOSEMODE: initial modeflags: $%08x\n", target->flags));
* also advice system that app_server and acc engine may touch the framebuffer
* simultaneously (fixed). */
target->flags &=
~(DUALHEAD_CAPABLE | TV_CAPABLE | B_SUPPORTS_OVERLAYS | B_HARDWARE_CURSOR | B_IO_FB_NA);
* mode (fixed), and all modes support DPMS (fixed);
* We support scrolling and panning in every mode, so we 'send a signal' to
* BWindowScreen.CanControlFrameBuffer() by setting B_SCROLL. */
* BDirectWindow windowed modes. */
target->flags |= (B_PARALLEL_ACCESS | B_8_BIT_DAC | B_DPMS | B_SCROLL);
switch (target->space) {
case B_CMAP8:
max_vclk = si->ps.max_dac2_clock_8;
bpp = 1;
break;
case B_RGB15_LITTLE:
case B_RGB16_LITTLE:
max_vclk = si->ps.max_dac2_clock_16;
bpp = 2;
break;
case B_RGB24_LITTLE:
max_vclk = si->ps.max_dac2_clock_24;
bpp = 3;
break;
case B_RGB32_LITTLE:
max_vclk = si->ps.max_dac2_clock_32dh;
bpp = 4;
break;
default:
max_vclk = si->ps.max_dac2_clock_32dh;
bpp = 4;
break;
}
if (si->ps.secondary_head && target->timing.pixel_clock <= (max_vclk * 1000)) {
switch (target->flags & DUALHEAD_BITS) {
case DUALHEAD_ON:
case DUALHEAD_SWITCH:
if (si->ps.memory_size - mem_reservation
>= row_bytes * target->virtual_height
&& (uint16)(row_bytes / bpp) >= target->timing.h_display * 2)
target->flags |= DUALHEAD_CAPABLE;
break;
case DUALHEAD_CLONE:
if (si->ps.memory_size - mem_reservation
>= row_bytes * target->virtual_height)
target->flags |= DUALHEAD_CAPABLE;
break;
case DUALHEAD_OFF:
if (si->ps.memory_size - mem_reservation
>= row_bytes * target->virtual_height * 2)
target->flags |= DUALHEAD_CAPABLE;
break;
}
}
if (!(target->flags & DUALHEAD_CAPABLE))
target->flags &= ~DUALHEAD_BITS;
if (si->ps.tvout && BT_check_tvmode(*target))
target->flags |= TV_CAPABLE;
if (!(target->flags & TV_CAPABLE))
target->flags &= ~TV_BITS;
if (target->flags & TV_BITS) {
if (!si->ps.secondary_head)
target->flags |= TV_PRIMARY;
else if ((target->flags & DUALHEAD_BITS) == DUALHEAD_OFF)
target->flags |= TV_PRIMARY;
} else
target->flags &= ~TV_PRIMARY;
if (si->settings.hardcursor)
target->flags |= B_HARDWARE_CURSOR;
if (si->ps.card_type <= NV40 || si->ps.card_type == NV45)
target->flags |= B_SUPPORTS_OVERLAYS;
LOG(1, ("PROPOSEMODE: validated modeflags: $%08x\n", target->flags));
* progressive scan (fixed), and sync_on_green not avaible. */
target->timing.flags &= ~(B_BLANK_PEDESTAL | B_TIMING_INTERLACED | B_SYNC_ON_GREEN);
if (status == B_OK)
LOG(4, ("PROPOSEMODE: completed successfully.\n"));
else
LOG(4, ("PROPOSEMODE: mode can be made, but outside given limits.\n"));
return status;
}
Return the number of modes this device will return from GET_MODE_LIST().
This is precalculated in create_mode_list (called from InitAccelerant stuff)
*/
uint32
ACCELERANT_MODE_COUNT(void)
{
LOG(1, ("ACCELERANT_MODE_COUNT: the modelist contains %d modes\n",si->mode_count));
return si->mode_count;
}
*/
status_t
GET_MODE_LIST(display_mode *dm)
{
LOG(1, ("GET_MODE_LIST: exporting the modelist created before.\n"));
memcpy(dm, my_mode_list, si->mode_count * sizeof(display_mode));
return B_OK;
}
static void checkAndAddMode(const display_mode *src, display_mode *dst)
{
uint32 j, pix_clk_range;
display_mode low, high;
color_space spaces[4] = {B_RGB32_LITTLE, B_RGB16_LITTLE, B_RGB15_LITTLE, B_CMAP8};
low = high = *src;
pix_clk_range = low.timing.pixel_clock >> 5;
low.timing.pixel_clock -= pix_clk_range;
high.timing.pixel_clock += pix_clk_range;
* Not true. They might need a wider pitch, but this is _not_ reflected in
* virtual_width, but in fbc.bytes_per_row. */
for (j = 0; j < (sizeof(spaces) / sizeof(color_space)); j++) {
dst[si->mode_count] = *src;
dst[si->mode_count].space = low.space = high.space = spaces[j];
* won't be taken into account!! */
if (PROPOSE_DISPLAY_MODE(&dst[si->mode_count], &low, &high) == B_OK) {
si->mode_count++;
}
}
}
*/
status_t
create_mode_list(void)
{
size_t max_size;
uint32 i;
const display_mode *src;
display_mode *dst;
display_mode custom_mode;
max_size = (((MODE_COUNT * 4 * 3) * sizeof(display_mode)) + (B_PAGE_SIZE-1)) & ~(B_PAGE_SIZE-1);
si->mode_area = my_mode_list_area = create_area("NV accelerant mode info",
(void **)&my_mode_list, B_ANY_ADDRESS, max_size, B_NO_LOCK,
B_READ_AREA | B_WRITE_AREA | B_CLONEABLE_AREA);
if (my_mode_list_area < B_OK)
return my_mode_list_area;
src = mode_list;
dst = my_mode_list;
si->mode_count = 0;
for (i = 0; i < MODE_COUNT; i++) {
activate both heads always to (probably) mimic Radeon driver behaviour (for which this app was adapted) */
- this will have a big downside on hardware for which both heads have different resolution cababilities (i.e. Matrox);
- also (on laptops) this will shorten battery life a bit of course.. */
custom_mode = *src;
custom_mode.flags |= DUALHEAD_CLONE;
checkAndAddMode(&custom_mode, dst);
automatically generate the needed other properties of the mode. Besides, virtual size is meant to be used for
pan&scan modes (viewports), i.e. for certain games.
The currently used method will fail programs that are meant to work pan@scan if the virtual width (or height) are
exactly twice the view area. */
custom_mode = *src;
custom_mode.virtual_width *= 2;
custom_mode.flags |= DUALHEAD_ON;
checkAndAddMode(&custom_mode, dst);
src++;
}
return B_OK;
}