2 Copyright (c) 2002-2004, Thomas Kurschel
5 Part of Radeon accelerant
7 Multi-monitor management
10 #include "radeon_accelerant.h"
12 #include "GlobalData.h"
15 // transform official mode to internal, multi-screen mode enhanced mode
16 void Radeon_DetectMultiMode( virtual_card
*vc
, display_mode
*mode
)
20 mode
->timing
.flags
&= ~RADEON_MODE_MASK
;
22 // combine mode is used if virtual area is twice as visible area
23 // and if scrolling is enabled; if combining is impossible, use
25 if( (mode
->flags
& B_SCROLL
) == 0 )
28 SHOW_FLOW0( 3, "possibly combine mode" );
30 // remove scroll flag - we don't need it anymore
31 mode
->flags
&= ~B_SCROLL
;
33 mode
->timing
.flags
&= ~RADEON_MODE_POSITION_MASK
;
35 if( mode
->virtual_width
== 2 * mode
->timing
.h_display
) {
36 SHOW_FLOW0( 2, "horizontal combine mode" );
37 mode
->timing
.flags
|= RADEON_MODE_POSITION_HORIZONTAL
;
38 mode
->timing
.flags
&= ~RADEON_MODE_MASK
;
39 mode
->timing
.flags
|= RADEON_MODE_COMBINE
;
40 } else if( mode
->virtual_height
== 2 * mode
->timing
.v_display
) {
41 SHOW_FLOW0( 2, "vertical combine mode" );
42 mode
->timing
.flags
|= RADEON_MODE_POSITION_VERTICAL
;
43 mode
->timing
.flags
&= ~RADEON_MODE_MASK
;
44 mode
->timing
.flags
|= RADEON_MODE_COMBINE
;
46 // ups, this isn't really a combine mode - restore flags
47 SHOW_FLOW0( 2, "wasn't really a combine mode" );
48 mode
->timing
.flags
&= ~RADEON_MODE_MASK
;
49 mode
->flags
|= B_SCROLL
;
53 // make sure selected multi-screen mode is valid; adapt it if needed
54 void Radeon_VerifyMultiMode( virtual_card
*vc
, shared_info
*si
, display_mode
*mode
)
56 // if there is no second port or no second monitor connected,
57 // fall back to standard mode
58 int num_usable_crtcs
= vc
->assigned_crtc
[0] && si
->crtc
[0].chosen_displays
!= dd_none
;
60 if( si
->num_crtc
> 1 )
61 num_usable_crtcs
+= vc
->assigned_crtc
[1] && si
->crtc
[1].chosen_displays
!= dd_none
;
63 if( num_usable_crtcs
< 2 ) {
64 SHOW_FLOW0( 2, "only one monitor - disabling any multi-mon mode" );
65 // restore flags if combine mode is selected
66 if( (mode
->timing
.flags
& RADEON_MODE_MASK
) == RADEON_MODE_COMBINE
)
67 mode
->flags
|= B_SCROLL
;
69 mode
->timing
.flags
&= ~RADEON_MODE_MASK
;
70 mode
->timing
.flags
|= RADEON_MODE_STANDARD
;
74 // transform internal, multi-screen enabled display mode
76 void Radeon_HideMultiMode( virtual_card
*vc
, display_mode
*mode
)
80 // restore flags for combine mode
81 if( (mode
->timing
.flags
& RADEON_MODE_MASK
) == RADEON_MODE_COMBINE
)
82 mode
->flags
|= B_SCROLL
;
86 // initialize multi-screen mode dependant variables
87 void Radeon_InitMultiModeVars(
88 accelerator_info
*ai
, display_mode
*mode
)
90 virtual_card
*vc
= ai
->vc
;
91 shared_info
*si
= ai
->si
;
94 // setup single-screen mode
95 vc
->eff_width
= mode
->timing
.h_display
;
96 vc
->eff_height
= mode
->timing
.v_display
;
98 if( vc
->used_crtc
[0] ) {
99 si
->crtc
[0].rel_x
= 0;
100 si
->crtc
[0].rel_y
= 0;
103 if( vc
->used_crtc
[1] ) {
104 si
->crtc
[1].rel_x
= 0;
105 si
->crtc
[1].rel_y
= 0;
108 switch( mode
->timing
.flags
& RADEON_MODE_MASK
) {
109 case RADEON_MODE_COMBINE
:
110 // detect where second screen must be located and
111 // adapt total visible area accordingly
112 if( (mode
->timing
.flags
& RADEON_MODE_POSITION_MASK
) == RADEON_MODE_POSITION_HORIZONTAL
) {
113 vc
->eff_width
= 2 * mode
->timing
.h_display
;
114 x
= mode
->timing
.h_display
;
117 vc
->eff_height
= 2 * mode
->timing
.v_display
;
119 y
= mode
->timing
.v_display
;
122 SHOW_FLOW( 3, "relative position of second screen: %d, %d", x
, y
);
124 // set relative offset
125 if( !vc
->swap_displays
) {
126 si
->crtc
[1].rel_x
= x
;
127 si
->crtc
[1].rel_y
= y
;
129 si
->crtc
[0].rel_x
= x
;
130 si
->crtc
[0].rel_y
= y
;
135 // else, ports are independant but show the same
141 // mapping of internal TV standard code to public TV standard code
142 static const uint32 private2be
[] = {
143 0, 1, 3, 4, 103, 3/* PAL SCART - no public id, so I use PAL BDGHI */, 102 };
145 // check and execute tunnel settings command
146 status_t
Radeon_CheckMultiMonTunnel( virtual_card
*vc
, display_mode
*mode
,
147 const display_mode
*low
, const display_mode
*high
, bool *isTunneled
)
149 if( (mode
->timing
.flags
& RADEON_MODE_MULTIMON_REQUEST
) != 0 &&
150 (mode
->timing
.flags
& RADEON_MODE_MULTIMON_REPLY
) == 0 )
152 mode
->timing
.flags
&= ~RADEON_MODE_MULTIMON_REQUEST
;
153 mode
->timing
.flags
|= RADEON_MODE_MULTIMON_REPLY
;
155 // still process request, just in case someone set this flag
156 // combination by mistake
158 // TBD: disabled to shorten syslog
163 // check magic params
164 if( mode
->space
!= 0 || low
->space
!= 0 || high
->space
!= 0
165 || low
->virtual_width
!= 0xffff || low
->virtual_height
!= 0xffff
166 || high
->virtual_width
!= 0 || high
->virtual_height
!= 0
167 || mode
->timing
.pixel_clock
!= 0
168 || low
->timing
.pixel_clock
!= 'TKTK' || high
->timing
.pixel_clock
!= 'KTKT' )
176 /*SHOW_FLOW( 1, "tunnel access code=%d, command=%d",
177 mode->h_display_start, mode->v_display_start );*/
179 switch( mode
->h_display_start
) {
181 switch( mode
->v_display_start
) {
183 mode
->timing
.flags
= vc
->swap_displays
;
187 vc
->swap_displays
= mode
->timing
.flags
!= 0;
188 vc
->enforce_mode_change
= true;
189 // write settings instantly
190 Radeon_WriteSettings( vc
);
195 case ms_use_laptop_panel
:
196 // we must refuse this setting if there is no laptop panel;
197 // else, the preferences dialog would show this (useless) option
198 if( (vc
->connected_displays
& dd_lvds
) == 0 )
201 switch( mode
->v_display_start
) {
203 mode
->timing
.flags
= vc
->use_laptop_panel
;
204 //SHOW_FLOW( 1, "get use_laptop_panel settings (%d)", mode->timing.flags );
208 vc
->use_laptop_panel
= mode
->timing
.flags
!= 0;
209 //SHOW_FLOW( 1, "set use_laptop_panel settings (%d)", vc->use_laptop_panel );
210 vc
->enforce_mode_change
= true;
211 Radeon_WriteSettings( vc
);
217 switch( mode
->v_display_start
) {
219 mode
->timing
.flags
= private2be
[vc
->tv_standard
];
220 /*SHOW_FLOW( 1, "read tv_standard (internal %d, public %d)",
221 vc->tv_standard, mode->timing.flags );*/
225 switch( mode
->timing
.flags
) {
226 case 0: vc
->tv_standard
= ts_off
; break;
227 case 1: vc
->tv_standard
= ts_ntsc
; break;
228 case 2: break; // ntsc j
229 case 3: vc
->tv_standard
= ts_pal_bdghi
; break;
230 case 4: vc
->tv_standard
= ts_pal_m
; break;
231 case 5: break; // pal n
232 case 6: break; // secam - I reckon not supported by hardware
233 case 101: break; // ntsc 443
234 case 102: vc
->tv_standard
= ts_pal_60
; break;
235 case 103: vc
->tv_standard
= ts_pal_nc
; break;
238 SHOW_FLOW( 1, "set tv_standard (internal %d, public %d)",
239 vc
->tv_standard
, mode
->timing
.flags
);
241 vc
->enforce_mode_change
= true;
242 Radeon_WriteSettings( vc
);
246 uint32 idx
= mode
->timing
.flags
;
248 // we limit it explicetely to NTSC and PAL as all other
249 // modes are not fully implemented
250 if( idx
< sizeof( private2be
) / sizeof( private2be
[0] ) &&
252 mode
->timing
.flags
= private2be
[idx
];
264 // return true if both ports must be programmed
265 bool Radeon_NeedsSecondPort( display_mode
*mode
)
267 switch( mode
->timing
.flags
& RADEON_MODE_MASK
) {
268 case RADEON_MODE_COMBINE
:
276 // return number of ports showing differents parts of frame buffer
277 bool Radeon_DifferentPorts( display_mode
*mode
)
279 switch( mode
->timing
.flags
& RADEON_MODE_MASK
) {
280 case RADEON_MODE_COMBINE
: