1 /* 2 Copyright (c) 2002-2004, Thomas Kurschel 3 4 5 Part of Radeon accelerant 6 7 Hardware access routines for overlays 8 */ 9 10 #include "GlobalData.h" 11 #include "radeon_interface.h" 12 #include "mmio.h" 13 #include "overlay_regs.h" 14 #include "pll_regs.h" 15 #include "capture_regs.h" 16 #include "utils.h" 17 #include "pll_access.h" 18 #include <math.h> 19 #include <string.h> 20 #include "CP.h" 21 22 23 void Radeon_TempHideOverlay( accelerator_info *ai ); 24 25 // standard (linear) gamma 26 static struct { 27 uint16 reg; 28 bool r200_or_above; 29 uint32 slope; 30 uint32 offset; 31 } std_gamma[] = { 32 { RADEON_OV0_GAMMA_0_F, false, 0x100, 0x0000 }, 33 { RADEON_OV0_GAMMA_10_1F, false, 0x100, 0x0020 }, 34 { RADEON_OV0_GAMMA_20_3F, false, 0x100, 0x0040 }, 35 { RADEON_OV0_GAMMA_40_7F, false, 0x100, 0x0080 }, 36 { RADEON_OV0_GAMMA_80_BF, true, 0x100, 0x0100 }, 37 { RADEON_OV0_GAMMA_C0_FF, true, 0x100, 0x0100 }, 38 { RADEON_OV0_GAMMA_100_13F, true, 0x100, 0x0200 }, 39 { RADEON_OV0_GAMMA_140_17F, true, 0x100, 0x0200 }, 40 { RADEON_OV0_GAMMA_180_1BF, true, 0x100, 0x0300 }, 41 { RADEON_OV0_GAMMA_1C0_1FF, true, 0x100, 0x0300 }, 42 { RADEON_OV0_GAMMA_200_23F, true, 0x100, 0x0400 }, 43 { RADEON_OV0_GAMMA_240_27F, true, 0x100, 0x0400 }, 44 { RADEON_OV0_GAMMA_280_2BF, true, 0x100, 0x0500 }, 45 { RADEON_OV0_GAMMA_2C0_2FF, true, 0x100, 0x0500 }, 46 { RADEON_OV0_GAMMA_300_33F, true, 0x100, 0x0600 }, 47 { RADEON_OV0_GAMMA_340_37F, true, 0x100, 0x0600 }, 48 { RADEON_OV0_GAMMA_380_3BF, false, 0x100, 0x0700 }, 49 { RADEON_OV0_GAMMA_3C0_3FF, false, 0x100, 0x0700 } 50 }; 51 52 53 // setup overlay unit before first use 54 void Radeon_InitOverlay( 55 accelerator_info *ai, int crtc_idx ) 56 { 57 vuint8 *regs = ai->regs; 58 shared_info *si = ai->si; 59 uint i; 60 uint32 ecp_div; 61 62 SHOW_FLOW0( 0, "" ); 63 64 // make sure we really write this value as the "toggle" bit 65 // contained in it (which is zero initially) is edge-sensitive! 66 // for capturing, we need to select "software" video port 67 si->overlay_mgr.auto_flip_reg = RADEON_OV0_VID_PORT_SELECT_SOFTWARE; 68 69 OUTREG( regs, RADEON_OV0_SCALE_CNTL, RADEON_SCALER_SOFT_RESET ); 70 OUTREG( regs, RADEON_OV0_AUTO_FLIP_CNTRL, si->overlay_mgr.auto_flip_reg ); 71 OUTREG( regs, RADEON_OV0_FILTER_CNTL, // use fixed filter coefficients 72 RADEON_OV0_HC_COEF_ON_HORZ_Y | 73 RADEON_OV0_HC_COEF_ON_HORZ_UV | 74 RADEON_OV0_HC_COEF_ON_VERT_Y | 75 RADEON_OV0_HC_COEF_ON_VERT_UV ); 76 OUTREG( regs, RADEON_OV0_KEY_CNTL, RADEON_GRAPHIC_KEY_FN_EQ | 77 RADEON_VIDEO_KEY_FN_FALSE | 78 RADEON_CMP_MIX_OR ); 79 OUTREG( regs, RADEON_OV0_TEST, 0 ); 80 // OUTREG( regs, RADEON_FCP_CNTL, RADEON_FCP_CNTL_GND ); // disable capture clock 81 // OUTREG( regs, RADEON_CAP0_TRIG_CNTL, 0 ); // disable capturing 82 OUTREG( regs, RADEON_OV0_REG_LOAD_CNTL, 0 ); 83 // tell deinterlacer to always show recent field 84 OUTREG( regs, RADEON_OV0_DEINTERLACE_PATTERN, 85 0xaaaaa | (9 << RADEON_OV0_DEINT_PAT_LEN_M1_SHIFT) ); 86 87 // set gamma 88 for( i = 0; i < sizeof( std_gamma ) / sizeof( std_gamma[0] ); ++i ) { 89 if( !std_gamma[i].r200_or_above || si->asic >= rt_r200 ) { 90 OUTREG( regs, std_gamma[i].reg, 91 (std_gamma[i].slope << 16) | std_gamma[i].offset ); 92 } 93 } 94 95 // overlay unit can only handle up to 175 MHz, if pixel clock is higher, 96 // only every second pixel is handled 97 if( si->crtc[crtc_idx].mode.timing.pixel_clock < 175000 ) 98 ecp_div = 0; 99 else 100 ecp_div = 1; 101 102 Radeon_OUTPLLP( regs, si->asic, RADEON_VCLK_ECP_CNTL, 103 ecp_div << RADEON_ECP_DIV_SHIFT, ~RADEON_ECP_DIV_MASK ); 104 105 si->active_overlay.crtc_idx = si->pending_overlay.crtc_idx; 106 107 // invalidate active colour space 108 si->active_overlay.ob.space = -1; 109 110 // invalidate position/scaling 111 si->active_overlay.ob.width = -1; 112 } 113 114 // colour space transformation matrix 115 typedef struct space_transform 116 { 117 float RefLuma; // scaling of luma to use full RGB range 118 float RefRCb; // b/u -> r 119 float RefRY; // g/y -> r 120 float RefRCr; // r/v -> r 121 float RefGCb; 122 float RefGY; 123 float RefGCr; 124 float RefBCb; 125 float RefBY; 126 float RefBCr; 127 } space_transform; 128 129 130 // Parameters for ITU-R BT.601 and ITU-R BT.709 colour spaces 131 space_transform trans_yuv[2] = 132 { 133 { 1.1678, 0.0, 1, 1.6007, -0.3929, 1, -0.8154, 2.0232, 1, 0.0 }, /* BT.601 */ 134 { 1.1678, 0.0, 1, 1.7980, -0.2139, 1, -0.5345, 2.1186, 1, 0.0 } /* BT.709 */ 135 }; 136 137 138 // RGB is a pass through 139 space_transform trans_rgb = 140 { 1, 0, 0, 1, 0, 1, 0, 1, 0, 0 }; 141 142 143 // set overlay colour space transformation matrix 144 static void Radeon_SetTransform( 145 accelerator_info *ai, 146 float bright, 147 float cont, 148 float sat, 149 float hue, 150 float red_intensity, 151 float green_intensity, 152 float blue_intensity, 153 uint ref) 154 { 155 vuint8 *regs = ai->regs; 156 shared_info *si = ai->si; 157 float OvHueSin, OvHueCos; 158 float CAdjOff; 159 float CAdjRY, CAdjGY, CAdjBY; 160 float CAdjRCb, CAdjRCr; 161 float CAdjGCb, CAdjGCr; 162 float CAdjBCb, CAdjBCr; 163 float RedAdj,GreenAdj,BlueAdj; 164 float OvROff, OvGOff, OvBOff; 165 float OvRY, OvGY, OvBY; 166 float OvRCb, OvRCr; 167 float OvGCb, OvGCr; 168 float OvBCb, OvBCr; 169 float Loff; 170 float Coff; 171 172 uint32 dwOvROff, dwOvGOff, dwOvBOff; 173 uint32 dwOvRY, dwOvGY, dwOvBY; 174 uint32 dwOvRCb, dwOvRCr; 175 uint32 dwOvGCb, dwOvGCr; 176 uint32 dwOvBCb, dwOvBCr; 177 178 space_transform *trans; 179 180 SHOW_FLOW0( 0, "" ); 181 182 // get proper conversion formula 183 switch( si->pending_overlay.ob.space ) { 184 case B_YCbCr422: 185 case B_YUV12: 186 Loff = 16 * 4; // internal representation is 10 Bits 187 Coff = 128 * 4; 188 189 if (ref >= 2) 190 ref = 0; 191 192 trans = &trans_yuv[ref]; 193 break; 194 195 case B_RGB15: 196 case B_RGB16: 197 case B_RGB32: 198 default: 199 Loff = 0; 200 Coff = 0; 201 trans = &trans_rgb; 202 } 203 204 OvHueSin = sin(hue); 205 OvHueCos = cos(hue); 206 207 // get matrix values to convert overlay colour space to RGB 208 // applying colour adjustment, saturation and luma scaling 209 // (saturation doesn't work with RGB input, perhaps it did with some 210 // maths; this is left to the reader :) 211 CAdjRY = cont * trans->RefLuma * trans->RefRY; 212 CAdjGY = cont * trans->RefLuma * trans->RefGY; 213 CAdjBY = cont * trans->RefLuma * trans->RefBY; 214 215 CAdjRCb = sat * -OvHueSin * trans->RefRCr; 216 CAdjRCr = sat * OvHueCos * trans->RefRCr; 217 CAdjGCb = sat * (OvHueCos * trans->RefGCb - OvHueSin * trans->RefGCr); 218 CAdjGCr = sat * (OvHueSin * trans->RefGCb + OvHueCos * trans->RefGCr); 219 CAdjBCb = sat * OvHueCos * trans->RefBCb; 220 CAdjBCr = sat * OvHueSin * trans->RefBCb; 221 222 // adjust black level 223 CAdjOff = cont * trans[ref].RefLuma * bright * 1023.0; 224 RedAdj = cont * trans[ref].RefLuma * red_intensity * 1023.0; 225 GreenAdj = cont * trans[ref].RefLuma * green_intensity * 1023.0; 226 BlueAdj = cont * trans[ref].RefLuma * blue_intensity * 1023.0; 227 228 OvRY = CAdjRY; 229 OvGY = CAdjGY; 230 OvBY = CAdjBY; 231 OvRCb = CAdjRCb; 232 OvRCr = CAdjRCr; 233 OvGCb = CAdjGCb; 234 OvGCr = CAdjGCr; 235 OvBCb = CAdjBCb; 236 OvBCr = CAdjBCr; 237 // apply offsets 238 OvROff = RedAdj + CAdjOff - CAdjRY * Loff - (OvRCb + OvRCr) * Coff; 239 OvGOff = GreenAdj + CAdjOff - CAdjGY * Loff - (OvGCb + OvGCr) * Coff; 240 OvBOff = BlueAdj + CAdjOff - CAdjBY * Loff - (OvBCb + OvBCr) * Coff; 241 242 dwOvROff = ((int32)(OvROff * 2.0)) & 0x1fff; 243 dwOvGOff = ((int32)(OvGOff * 2.0)) & 0x1fff; 244 dwOvBOff = ((int32)(OvBOff * 2.0)) & 0x1fff; 245 246 dwOvRY = (((int32)(OvRY * 2048.0))&0x7fff)<<17; 247 dwOvGY = (((int32)(OvGY * 2048.0))&0x7fff)<<17; 248 dwOvBY = (((int32)(OvBY * 2048.0))&0x7fff)<<17; 249 dwOvRCb = (((int32)(OvRCb * 2048.0))&0x7fff)<<1; 250 dwOvRCr = (((int32)(OvRCr * 2048.0))&0x7fff)<<17; 251 dwOvGCb = (((int32)(OvGCb * 2048.0))&0x7fff)<<1; 252 dwOvGCr = (((int32)(OvGCr * 2048.0))&0x7fff)<<17; 253 dwOvBCb = (((int32)(OvBCb * 2048.0))&0x7fff)<<1; 254 dwOvBCr = (((int32)(OvBCr * 2048.0))&0x7fff)<<17; 255 256 OUTREG( regs, RADEON_OV0_LIN_TRANS_A, dwOvRCb | dwOvRY ); 257 OUTREG( regs, RADEON_OV0_LIN_TRANS_B, dwOvROff | dwOvRCr ); 258 OUTREG( regs, RADEON_OV0_LIN_TRANS_C, dwOvGCb | dwOvGY ); 259 OUTREG( regs, RADEON_OV0_LIN_TRANS_D, dwOvGOff | dwOvGCr ); 260 OUTREG( regs, RADEON_OV0_LIN_TRANS_E, dwOvBCb | dwOvBY ); 261 OUTREG( regs, RADEON_OV0_LIN_TRANS_F, dwOvBOff | dwOvBCr ); 262 263 si->active_overlay.ob.space = si->pending_overlay.ob.space; 264 } 265 266 267 // convert Be colour key to rgb value 268 static uint32 colourKey2RGB32( 269 uint32 space, uint8 red, uint8 green, uint8 blue ) 270 { 271 uint32 res; 272 273 SHOW_FLOW0( 3, "" ); 274 275 // the way Be defines colour keys may be convinient to some driver developers, 276 // but it's not well defined - took me some time to find out the format used 277 // and still I have no idea how alpha is defined; Rudolf told me that alpha is 278 // never used 279 switch( space ) { 280 case B_RGB15: 281 res = 282 ((uint32)(red >> 0) << (16+3)) | 283 ((uint32)(green >> 0) << (8+3)) | 284 ((blue >> 0) << 3); 285 break; 286 case B_RGB16: 287 res = 288 ((uint32)(red >> 0) << (16+3)) | 289 ((uint32)(green >> 0) << (8+2)) | 290 ((blue >> 0) << 3); 291 break; 292 case B_RGB32: 293 case B_CMAP8: 294 res = ((uint32)(red) << 16) | ((uint32)(green) << 8) | blue; 295 break; 296 default: 297 res = 0; 298 } 299 300 SHOW_FLOW( 3, "key=%lx", res ); 301 return res; 302 } 303 304 305 // set colour key of overlay 306 static void Radeon_SetColourKey( 307 accelerator_info *ai, const overlay_window *ow ) 308 { 309 virtual_card *vc = ai->vc; 310 vuint8 *regs = ai->regs; 311 uint32 rgb32, mask32, min32, max32; 312 313 /*SHOW_FLOW( 0, "value=%02x %02x %02x, mask=%02x %02x %02x", 314 ow->red.value, ow->green.value, ow->blue.value, 315 ow->red.mask, ow->green.mask, ow->blue.mask );*/ 316 317 // Radeons don't support value and mask as colour key but colour range 318 rgb32 = colourKey2RGB32( vc->mode.space, 319 ow->red.value, ow->green.value, ow->blue.value ); 320 mask32 = colourKey2RGB32( vc->mode.space, 321 ow->red.mask, ow->green.mask, ow->blue.mask ); 322 323 // ~mask32 are all unimportant (usually low order) bits 324 // oring this to the colour should give us the highest valid colour value 325 // (add would be more precise but may lead to overflows) 326 min32 = rgb32; 327 max32 = rgb32 | ~mask32; 328 329 OUTREG( regs, RADEON_OV0_GRAPHICS_KEY_CLR_LOW, min32 ); 330 OUTREG( regs, RADEON_OV0_GRAPHICS_KEY_CLR_HIGH, max32 ); 331 OUTREG( regs, RADEON_OV0_KEY_CNTL, 332 RADEON_GRAPHIC_KEY_FN_EQ | 333 RADEON_VIDEO_KEY_FN_FALSE | 334 RADEON_CMP_MIX_OR ); 335 } 336 337 typedef struct { 338 uint max_scale; // maximum src_width/dest_width, 339 // i.e. source increment per screen pixel 340 uint8 group_size; // size of one filter group in pixels 341 uint8 p1_step_by, p23_step_by; // > 0: log(source pixel increment)+1, 2-tap filter 342 // = 0: source pixel increment = 1, 4-tap filter 343 } hscale_factor; 344 345 #define count_of( a ) (sizeof( a ) / sizeof( a[0] )) 346 347 // scaling/filter tables depending on overlay colour space: 348 // magnifying pixels is no problem, but minifying can lead to overload, 349 // so we have to skip pixels and/or use 2-tap filters 350 static hscale_factor scale_RGB16[] = { 351 { (2 << 12), 2, 1, 1 }, 352 { (4 << 12), 2, 2, 2 }, 353 { (8 << 12), 2, 3, 3 }, 354 { (16 << 12), 2, 4, 4 }, 355 { (32 << 12), 2, 5, 5 } 356 }; 357 358 static hscale_factor scale_RGB32[] = { 359 { (2 << 12) / 3, 2, 0, 0 }, 360 { (4 << 12) / 3, 4, 1, 1 }, 361 { (8 << 12) / 3, 4, 2, 2 }, 362 { (4 << 12), 4, 2, 3 }, 363 { (16 << 12) / 3, 4, 3, 3 }, 364 { (8 << 12), 4, 3, 4 }, 365 { (32 << 12) / 3, 4, 4, 4 }, 366 { (16 << 12), 4, 5, 5 } 367 }; 368 369 static hscale_factor scale_YUV[] = { 370 { (16 << 12) / 16, 2, 0, 0 }, 371 { (16 << 12) / 12, 2, 0, 1 }, // mode 4, 1, 0 (as used by YUV12) is impossible 372 { (16 << 12) / 8, 4, 1, 1 }, 373 { (16 << 12) / 6, 4, 1, 2 }, 374 { (16 << 12) / 4, 4, 2, 2 }, 375 { (16 << 12) / 3, 4, 2, 3 }, 376 { (16 << 12) / 2, 4, 3, 3 }, 377 { (16 << 12) / 1, 4, 4, 4 } 378 }; 379 380 static hscale_factor scale_YUV12[] = { 381 { (16 << 12) / 16, 2, 0, 0 }, 382 { (16 << 12) / 12, 4, 1, 0 }, 383 { (16 << 12) / 12, 2, 0, 1 }, 384 { (16 << 12) / 8, 4, 1, 1 }, 385 { (16 << 12) / 6, 4, 1, 2 }, 386 { (16 << 12) / 4, 4, 2, 2 }, 387 { (16 << 12) / 3, 4, 2, 3 }, 388 { (16 << 12) / 2, 4, 3, 3 }, 389 { (int)((16 << 12) / 1.5), 4, 3, 4 }, 390 { (int)((16 << 12) / 1.0), 4, 4, 4 }, 391 { (int)((16 << 12) / 0.75), 4, 4, 5 }, 392 { (int)((16 << 12) / 0.5), 4, 5, 5 } 393 }; 394 395 #define min3( a, b, c ) (min( (a), min( (b), (c) ))) 396 397 static hscale_factor scale_YUV9[] = { 398 { min3( (16 << 12) / 12, (3 << 12) * 1, (2 << 12) * 4 * 1 ), 2, 0, 0 }, 399 { min3( (16 << 12) / 8, (3 << 12) * 1, (2 << 12) * 4 * 1 ), 4, 1, 0 }, 400 { min3( (16 << 12) / 10, (3 << 12) * 1, (2 << 12) * 4 * 1 ), 2, 0, 1 }, 401 { min3( (16 << 12) / 6, (3 << 12) * 1, (2 << 12) * 4 * 1 ), 4, 1, 1 }, 402 { min3( (16 << 12) / 5, (3 << 12) * 1, (2 << 12) * 4 * 2 ), 4, 1, 2 }, 403 { min3( (16 << 12) / 3, (3 << 12) * 2, (2 << 12) * 4 * 2 ), 4, 2, 2 }, 404 { min3( (int)((16 << 12) / 2.5), (3 << 12) * 1, (2 << 12) * 4 * 4 ), 4, 2, 3 }, // probably, it should be (3 << 12) * 2 405 { min3( (int)((16 << 12) / 1.5), (3 << 12) * 4, (2 << 12) * 4 * 4 ), 4, 3, 3 }, 406 { min3( (int)((16 << 12) / 0.75), (3 << 12) * 8, (2 << 12) * 4 * 8 ), 4, 4, 4 }, 407 { min3( (int)((16 << 12) / 0.625), (3 << 12) * 8, (2 << 12) * 4 * 16 ), 4, 4, 5 }, 408 { min3( (int)((16 << 12) / 0.375), (3 << 12) * 16, (2 << 12) * 4 * 16 ), 4, 5, 5 } 409 }; 410 411 412 // parameters of an overlay colour space 413 typedef struct { 414 uint8 bpp_shift; // log2( bytes per pixel (main plain) ) 415 uint8 bpuv_shift; // log2( bytes per pixel (uv-plane) ); 416 // if there is one plane only: bpp=bpuv 417 uint8 num_planes; // number of planes 418 uint8 h_uv_sub_sample_shift; // log2( horizontal pixels per uv pair ) 419 uint8 v_uv_sub_sample_shift; // log2( vertical pixels per uv pair ) 420 hscale_factor *factors; // scaling/filter table 421 uint8 num_factors; 422 } space_params; 423 424 static space_params space_params_table[16] = { 425 { 0, 0, 0, 0, 0, NULL, 0 }, // reserved 426 { 0, 0, 0, 0, 0, NULL, 0 }, // reserved 427 { 0, 0, 0, 0, 0, NULL, 0 }, // reserved 428 { 1, 1, 1, 0, 0, scale_RGB16, count_of( scale_RGB16 ) }, // RGB15 429 { 1, 1, 1, 0, 0, scale_RGB16, count_of( scale_RGB16 ) }, // RGB16 430 { 0, 0, 0, 0, 0, NULL, 0 }, // reserved 431 { 2, 2, 1, 0, 0, scale_RGB32, count_of( scale_RGB32 ) }, // RGB32 432 { 0, 0, 0, 0, 0, NULL, 0 }, // reserved 433 { 0, 0, 0, 0, 0, NULL, 0 }, // reserved 434 { 0, 0, 3, 2, 2, scale_YUV9, count_of( scale_YUV9 ) }, // YUV9 435 { 0, 0, 3, 1, 1, scale_YUV12, count_of( scale_YUV12 ) }, // YUV12, three-plane 436 { 1, 1, 1, 1, 0, scale_YUV, count_of( scale_YUV ) }, // VYUY422 437 { 1, 1, 1, 1, 0, scale_YUV, count_of( scale_YUV ) }, // YVYU422 438 { 0, 1, 2, 1, 1, scale_YUV12, count_of( scale_YUV12 ) }, // YUV12, two-plane 439 { 0, 1, 2, 1, 1, NULL, 0 }, // ??? 440 { 0, 0, 0, 0, 0, NULL, 0 } // reserved 441 }; 442 443 // get appropriate scaling/filter parameters 444 static hscale_factor *getHScaleFactor( 445 space_params *params, 446 uint32 src_left, uint32 src_right, uint32 *h_inc ) 447 { 448 uint words_per_p1_line, words_per_p23_line, max_words_per_line; 449 bool p1_4tap_allowed, p23_4tap_allowed; 450 uint i; 451 uint num_factors; 452 hscale_factor *factors; 453 454 SHOW_FLOW0( 3, "" ); 455 456 // check whether fifo is large enough to feed vertical 4-tap-filter 457 458 words_per_p1_line = 459 ceilShiftDiv( (src_right - 1) << params->bpp_shift, 4 ) - 460 ((src_left << params->bpp_shift) >> 4) + 1; 461 words_per_p23_line = 462 ceilShiftDiv( (src_right - 1) << params->bpuv_shift, 4 ) - 463 ((src_left << params->bpuv_shift) >> 4) + 1; 464 465 // overlay buffer for one line; this value is probably 466 // higher on newer Radeons (or smaller on older Radeons?) 467 max_words_per_line = 96; 468 469 switch( params->num_planes ) { 470 case 3: 471 p1_4tap_allowed = words_per_p1_line < max_words_per_line / 2; 472 p23_4tap_allowed = words_per_p23_line < max_words_per_line / 4; 473 break; 474 case 2: 475 p1_4tap_allowed = words_per_p1_line < max_words_per_line / 2; 476 p23_4tap_allowed = words_per_p23_line < max_words_per_line / 2; 477 break; 478 case 1: 479 default: 480 p1_4tap_allowed = p23_4tap_allowed = words_per_p1_line < max_words_per_line; 481 break; 482 } 483 484 SHOW_FLOW( 3, "p1_4tap_allowed=%d, p23_4t_allowed=%d", 485 (int)p1_4tap_allowed, (int)p23_4tap_allowed ); 486 487 // search for proper scaling/filter entry 488 factors = params->factors; 489 num_factors = params->num_factors; 490 491 if( factors == NULL || num_factors == 0 ) 492 return NULL; 493 494 for( i = 0; i < num_factors; ++i, ++factors ) { 495 if( *h_inc <= factors->max_scale && 496 (factors->p1_step_by > 0 || p1_4tap_allowed) && 497 (factors->p23_step_by > 0 || p23_4tap_allowed)) 498 break; 499 } 500 501 if( i == num_factors ) { 502 // overlay is asked to be scaled down more than allowed, 503 // so use least scaling factor supported 504 --factors; 505 *h_inc = factors->max_scale; 506 } 507 508 SHOW_FLOW( 3, "group_size=%d, p1_step_by=%d, p23_step_by=%d", 509 factors->group_size, factors->p1_step_by, factors->p23_step_by ); 510 511 return factors; 512 } 513 514 515 #define I2FF( a, shift ) ((uint32)((a) * (1 << (shift)))) 516 517 518 // show overlay on screen 519 static status_t Radeon_ShowOverlay( 520 accelerator_info *ai, int crtc_idx ) 521 { 522 virtual_card *vc = ai->vc; 523 shared_info *si = ai->si; 524 vuint8 *regs = ai->regs; 525 overlay_info *overlay = &si->pending_overlay; 526 overlay_buffer_node *node = overlay->on; 527 crtc_info *crtc = &si->crtc[crtc_idx]; 528 529 uint32 ecp_div; 530 uint32 v_inc, h_inc; 531 uint32 src_v_inc, src_h_inc; 532 uint32 src_left, src_top, src_right, src_bottom; 533 int32 dest_left, dest_top, dest_right, dest_bottom; 534 uint32 offset; 535 uint32 tmp; 536 uint32 p1_h_accum_init, p23_h_accum_init, p1_v_accum_init, p23_v_accum_init; 537 uint32 p1_active_lines, p23_active_lines; 538 hscale_factor *factors; 539 space_params *params; 540 541 uint32 p1_h_inc, p23_h_inc; 542 uint32 p1_x_start, p1_x_end; 543 uint32 p23_x_start, p23_x_end; 544 545 /*uint32 buffer[20*2]; 546 uint idx = 0;*/ 547 548 SHOW_FLOW0( 0, "" ); 549 550 Radeon_SetColourKey( ai, &overlay->ow ); 551 552 // overlay unit can only handle up to 175 MHz; if pixel clock is higher, 553 // only every second pixel is handled 554 // (this devider is gets written into PLL by InitOverlay, 555 // so we don't need to do it ourself) 556 if( crtc->mode.timing.pixel_clock < 175000 ) 557 ecp_div = 0; 558 else 559 ecp_div = 1; 560 561 562 // scaling is independant of clipping, get this first 563 { 564 uint32 src_width, src_height; 565 566 src_width = overlay->ov.width; 567 src_height = overlay->ov.height; 568 569 // this is for graphics card 570 v_inc = (src_height << 20) / overlay->ow.height; 571 h_inc = (src_width << (12 + ecp_div)) / overlay->ow.width; 572 573 574 // this is for us 575 src_v_inc = (src_height << 16) / overlay->ow.height; 576 src_h_inc = (src_width << 16) / overlay->ow.width; 577 } 578 579 // calculate unclipped position/size 580 // TBD: I assume that overlay_window.offset_xyz is only a hint where 581 // no overlay is visible; another interpretation were to zoom 582 // the overlay so it fits into remaining space 583 src_left = (overlay->ov.h_start << 16) + overlay->ow.offset_left * src_h_inc; 584 src_top = (overlay->ov.v_start << 16) + overlay->ow.offset_top * src_v_inc; 585 src_right = ((overlay->ov.h_start + overlay->ov.width) << 16) - 586 overlay->ow.offset_right * src_h_inc; 587 src_bottom = ((overlay->ov.v_start + overlay->ov.height) << 16) - 588 overlay->ow.offset_top * src_v_inc; 589 dest_left = overlay->ow.h_start + overlay->ow.offset_left; 590 dest_top = overlay->ow.v_start + overlay->ow.offset_top; 591 dest_right = overlay->ow.h_start + overlay->ow.width - overlay->ow.offset_right; 592 dest_bottom = overlay->ow.v_start + overlay->ow.height - overlay->ow.offset_bottom; 593 594 SHOW_FLOW( 3, "ow: h=%d, v=%d, width=%d, height=%d", 595 overlay->ow.h_start, overlay->ow.v_start, 596 overlay->ow.width, overlay->ow.height ); 597 598 SHOW_FLOW( 3, "offset_left=%d, offset_right=%d, offset_top=%d, offset_bottom=%d", 599 overlay->ow.offset_left, overlay->ow.offset_right, 600 overlay->ow.offset_top, overlay->ow.offset_bottom ); 601 602 603 // apply virtual screen 604 dest_left -= vc->mode.h_display_start + crtc->rel_x; 605 dest_top -= vc->mode.v_display_start + crtc->rel_y; 606 dest_right -= vc->mode.h_display_start + crtc->rel_x; 607 dest_bottom -= vc->mode.v_display_start + crtc->rel_y; 608 609 610 // clip to visible area 611 if( dest_left < 0 ) { 612 src_left += -dest_left * src_h_inc; 613 dest_left = 0; 614 } 615 if( dest_top < 0 ) { 616 src_top += -dest_top * src_v_inc; 617 dest_top = 0; 618 } 619 620 SHOW_FLOW( 3, "mode: w=%d, h=%d", 621 crtc->mode.timing.h_display, crtc->mode.timing.v_display ); 622 623 if( dest_right > crtc->mode.timing.h_display ) 624 dest_right = crtc->mode.timing.h_display; 625 if( dest_bottom > crtc->mode.timing.v_display ) 626 dest_bottom = crtc->mode.timing.v_display; 627 628 SHOW_FLOW( 3, "src=(%d, %d, %d, %d)", 629 src_left, src_top, src_right, src_bottom ); 630 SHOW_FLOW( 3, "dest=(%d, %d, %d, %d)", 631 dest_left, dest_top, dest_right, dest_bottom ); 632 633 634 // especially with multi-screen modes the overlay may not be on screen at all 635 if( dest_left >= dest_right || dest_top >= dest_bottom || 636 src_left >= src_right || src_top >= src_bottom ) 637 { 638 Radeon_TempHideOverlay( ai ); 639 goto done; 640 } 641 642 643 // let's calculate all those nice register values 644 SHOW_FLOW( 3, "ati_space=%d", node->ati_space ); 645 params = &space_params_table[node->ati_space]; 646 647 // choose proper scaler 648 { 649 factors = getHScaleFactor( params, src_left >> 16, src_right >> 16, &h_inc ); 650 if( factors == NULL ) 651 return B_ERROR; 652 653 p1_h_inc = factors->p1_step_by > 0 ? 654 h_inc >> (factors->p1_step_by - 1) : h_inc; 655 p23_h_inc = 656 (factors->p23_step_by > 0 ? h_inc >> (factors->p23_step_by - 1) : h_inc) 657 >> params->h_uv_sub_sample_shift; 658 659 SHOW_FLOW( 3, "p1_h_inc=%x, p23_h_inc=%x", p1_h_inc, p23_h_inc ); 660 } 661 662 // get register value for start/end position of overlay image (pixel-precise only) 663 { 664 uint32 p1_step_size, p23_step_size; 665 uint32 p1_left, p1_right, p1_width; 666 uint32 p23_left, p23_right, p23_width; 667 668 p1_left = src_left >> 16; 669 p1_right = src_right >> 16; 670 p1_width = p1_right - p1_left; 671 672 p1_step_size = factors->p1_step_by > 0 ? (1 << (factors->p1_step_by - 1)) : 1; 673 p1_x_start = p1_left % (16 >> params->bpp_shift); 674 p1_x_end = ((p1_x_start + p1_width - 1) / p1_step_size) * p1_step_size; 675 676 SHOW_FLOW( 3, "p1_x_start=%d, p1_x_end=%d", p1_x_start, p1_x_end ); 677 678 p23_left = (src_left >> 16) >> params->h_uv_sub_sample_shift; 679 p23_right = (src_right >> 16) >> params->h_uv_sub_sample_shift; 680 p23_width = p23_right - p23_left; 681 682 p23_step_size = factors->p23_step_by > 0 ? (1 << (factors->p23_step_by - 1)) : 1; 683 // if resolution of Y and U/V differs but YUV are stored in one 684 // plane then UV alignment depends on Y data, therefore the hack 685 // (you are welcome to replace this with some cleaner code ;) 686 p23_x_start = p23_left % 687 ((16 >> params->bpuv_shift) / 688 (node->ati_space == 11 || node->ati_space == 12 ? 2 : 1)); 689 p23_x_end = (int)((p23_x_start + p23_width - 1) / p23_step_size) * p23_step_size; 690 691 SHOW_FLOW( 3, "p23_x_start=%d, p23_x_end=%d", p23_x_start, p23_x_end ); 692 693 // get memory location of first word to be read by scaler 694 // (save relative offset for fast update) 695 si->active_overlay.rel_offset = (src_top >> 16) * node->buffer.bytes_per_row + 696 ((p1_left << params->bpp_shift) & ~0xf); 697 offset = node->mem_offset + si->active_overlay.rel_offset; 698 699 SHOW_FLOW( 3, "rel_offset=%x", si->active_overlay.rel_offset ); 700 } 701 702 // get active lines for scaler 703 // (we could add additional blank lines for DVD letter box mode, 704 // but this is not supported by API; additionally, this only makes 705 // sense if want to put subtitles onto the black border, which is 706 // supported neither) 707 { 708 uint16 int_top, int_bottom; 709 710 int_top = src_top >> 16; 711 int_bottom = (src_bottom >> 16); 712 713 p1_active_lines = int_bottom - int_top - 1; 714 p23_active_lines = 715 ceilShiftDiv( int_bottom - 1, params->v_uv_sub_sample_shift ) - 716 (int_top >> params->v_uv_sub_sample_shift); 717 718 SHOW_FLOW( 3, "p1_active_lines=%d, p23_active_lines=%d", 719 p1_active_lines, p23_active_lines ); 720 } 721 722 // if picture is stretched for flat panel, we need to scale all 723 // vertical values accordingly 724 // TBD: there is no description at all concerning this, so v_accum_init may 725 // need to be initialized based on original value 726 { 727 if( (crtc->active_displays & (dd_lvds | dd_dvi)) != 0 ) { 728 uint64 v_ratio; 729 730 // convert 32.32 format to 16.16 format; else we 731 // cannot multiply two fixed point values without 732 // overflow 733 v_ratio = si->flatpanels[crtc->flatpanel_port].v_ratio >> (FIX_SHIFT - 16); 734 735 v_inc = (v_inc * v_ratio) >> 16; 736 } 737 738 SHOW_FLOW( 3, "v_inc=%x", v_inc ); 739 } 740 741 // get initial horizontal scaler values, taking care of precharge 742 // don't ask questions about formulas - take them as is 743 // (TBD: home-brewed sub-pixel source clipping may be wrong, 744 // especially for uv-planes) 745 { 746 uint32 p23_group_size; 747 748 tmp = ((src_left & 0xffff) >> 11) + ( 749 ( 750 I2FF( p1_x_start % factors->group_size, 12 ) + 751 I2FF( 2.5, 12 ) + 752 p1_h_inc / 2 + 753 I2FF( 0.5, 12-5 ) // rounding 754 ) >> (12 - 5)); // scaled by 1 << 5 755 756 SHOW_FLOW( 3, "p1_h_accum_init=%x", tmp ); 757 758 p1_h_accum_init = 759 ((tmp << 15) & RADEON_OV0_P1_H_ACCUM_INIT_MASK) | 760 ((tmp << 23) & RADEON_OV0_P1_PRESHIFT_MASK); 761 762 763 p23_group_size = 2; 764 765 tmp = ((src_left & 0xffff) >> 11) + ( 766 ( 767 I2FF( p23_x_start % p23_group_size, 12 ) + 768 I2FF( 2.5, 12 ) + 769 p23_h_inc / 2 + 770 I2FF( 0.5, 12-5 ) // rounding 771 ) >> (12 - 5)); // scaled by 1 << 5 772 773 SHOW_FLOW( 3, "p23_h_accum_init=%x", tmp ); 774 775 p23_h_accum_init = 776 ((tmp << 15) & RADEON_OV0_P23_H_ACCUM_INIT_MASK) | 777 ((tmp << 23) & RADEON_OV0_P23_PRESHIFT_MASK); 778 } 779 780 // get initial vertical scaler values, taking care of precharge 781 { 782 uint extra_full_line; 783 784 extra_full_line = factors->p1_step_by == 0 ? 1 : 0; 785 786 tmp = ((src_top & 0x0000ffff) >> 11) + ( 787 (min( 788 I2FF( 1.5, 20 ) + I2FF( extra_full_line, 20 ) + v_inc / 2, 789 I2FF( 2.5, 20 ) + 2 * I2FF( extra_full_line, 20 ) 790 ) + I2FF( 0.5, 20-5 )) // rounding 791 >> (20 - 5)); // scaled by 1 << 5 792 793 SHOW_FLOW( 3, "p1_v_accum_init=%x", tmp ); 794 795 p1_v_accum_init = 796 ((tmp << 15) & RADEON_OV0_P1_V_ACCUM_INIT_MASK) | 0x00000001; 797 798 799 extra_full_line = factors->p23_step_by == 0 ? 1 : 0; 800 801 if( params->v_uv_sub_sample_shift > 0 ) { 802 tmp = ((src_top & 0x0000ffff) >> 11) + ( 803 (min( 804 I2FF( 1.5, 20 ) + 805 I2FF( extra_full_line, 20 ) + 806 ((v_inc / 2) >> params->v_uv_sub_sample_shift), 807 I2FF( 2.5, 20 ) + 808 2 * I2FF( extra_full_line, 20 ) 809 ) + I2FF( 0.5, 20-5 )) // rounding 810 >> (20 - 5)); // scaled by 1 << 5 811 } else { 812 tmp = ((src_top & 0x0000ffff) >> 11) + ( 813 ( 814 I2FF( 2.5, 20 ) + 815 2 * I2FF( extra_full_line, 20 ) + 816 I2FF( 0.5, 20-5 ) // rounding 817 ) >> (20 - 5)); // scaled by 1 << 5 818 } 819 820 SHOW_FLOW( 3, "p23_v_accum_init=%x", tmp ); 821 822 p23_v_accum_init = 823 ((tmp << 15) & RADEON_OV0_P23_V_ACCUM_INIT_MASK) | 0x00000001; 824 } 825 826 // show me what you've got! 827 // we could lock double buffering of overlay unit during update 828 // (new values are copied during vertical blank, so if we've updated 829 // only some of them, you get a whole frame of mismatched values) 830 // but during tests I couldn't get the artifacts go away, so 831 // we use the dangerous way which has the pro to not require any 832 // waiting 833 834 // let's try to lock overlay unit 835 // we had to wait now until the lock takes effect, but this is 836 // impossible with CCE; perhaps we have to convert this code to 837 // direct register access; did that - let's see what happens... 838 OUTREG( regs, RADEON_OV0_REG_LOAD_CNTL, RADEON_REG_LD_CTL_LOCK ); 839 840 // wait until register access is locked 841 while( (INREG( regs, RADEON_OV0_REG_LOAD_CNTL) 842 & RADEON_REG_LD_CTL_LOCK_READBACK) == 0 ) 843 ; 844 845 OUTREG( regs, RADEON_OV0_VID_BUF0_BASE_ADRS, offset ); 846 OUTREG( regs, RADEON_OV0_VID_BUF_PITCH0_VALUE, node->buffer.bytes_per_row ); 847 OUTREG( regs, RADEON_OV0_H_INC, p1_h_inc | (p23_h_inc << 16) ); 848 OUTREG( regs, RADEON_OV0_STEP_BY, factors->p1_step_by | (factors->p23_step_by << 8) ); 849 OUTREG( regs, RADEON_OV0_V_INC, v_inc ); 850 851 OUTREG( regs, 852 crtc->crtc_idx == 0 ? RADEON_OV0_Y_X_START : RADEON_OV1_Y_X_START, 853 (dest_left) | (dest_top << 16) ); 854 OUTREG( regs, 855 crtc->crtc_idx == 0 ? RADEON_OV0_Y_X_END : RADEON_OV1_Y_X_END, 856 (dest_right - 1) | ((dest_bottom - 1) << 16) ); 857 858 OUTREG( regs, RADEON_OV0_P1_BLANK_LINES_AT_TOP, 859 RADEON_P1_BLNK_LN_AT_TOP_M1_MASK | (p1_active_lines << 16) ); 860 OUTREG( regs, RADEON_OV0_P1_X_START_END, p1_x_end | (p1_x_start << 16) ); 861 OUTREG( regs, RADEON_OV0_P1_H_ACCUM_INIT, p1_h_accum_init ); 862 OUTREG( regs, RADEON_OV0_P1_V_ACCUM_INIT, p1_v_accum_init ); 863 864 OUTREG( regs, RADEON_OV0_P23_BLANK_LINES_AT_TOP, 865 RADEON_P23_BLNK_LN_AT_TOP_M1_MASK | (p23_active_lines << 16) ); 866 OUTREG( regs, RADEON_OV0_P2_X_START_END, 867 p23_x_end | (p23_x_start << 16) ); 868 OUTREG( regs, RADEON_OV0_P3_X_START_END, 869 p23_x_end | (p23_x_start << 16) ); 870 OUTREG( regs, RADEON_OV0_P23_H_ACCUM_INIT, p23_h_accum_init ); 871 OUTREG( regs, RADEON_OV0_P23_V_ACCUM_INIT, p23_v_accum_init ); 872 873 OUTREG( regs, RADEON_OV0_TEST, node->test_reg ); 874 OUTREG( regs, RADEON_OV0_SCALE_CNTL, 875 RADEON_SCALER_ENABLE | 876 RADEON_SCALER_DOUBLE_BUFFER | 877 (node->ati_space << 8) | 878 /*RADEON_SCALER_ADAPTIVE_DEINT |*/ 879 (crtc->crtc_idx == 0 ? 0 : RADEON_SCALER_CRTC_SEL )); 880 881 si->overlay_mgr.auto_flip_reg ^= RADEON_OV0_SOFT_EOF_TOGGLE; 882 883 OUTREG( regs, RADEON_OV0_AUTO_FLIP_CNTRL, 884 si->overlay_mgr.auto_flip_reg ); 885 886 OUTREG( regs, RADEON_OV0_REG_LOAD_CNTL, 0 ); 887 888 done: 889 ai->si->active_overlay.on = ai->si->pending_overlay.on; 890 ai->si->active_overlay.ow = ai->si->pending_overlay.ow; 891 ai->si->active_overlay.ov = ai->si->pending_overlay.ov; 892 ai->si->active_overlay.ob = ai->si->pending_overlay.ob; 893 ai->si->active_overlay.h_display_start = vc->mode.h_display_start; 894 ai->si->active_overlay.v_display_start = vc->mode.v_display_start; 895 896 return B_OK; 897 } 898 899 900 // hide overlay, but not permanently 901 void Radeon_TempHideOverlay( 902 accelerator_info *ai ) 903 { 904 SHOW_FLOW0( 3, "" ); 905 906 OUTREG( ai->regs, RADEON_OV0_SCALE_CNTL, 0 ); 907 } 908 909 910 // hide overlay (can be called even if there is none visible) 911 void Radeon_HideOverlay( 912 accelerator_info *ai ) 913 { 914 shared_info *si = ai->si; 915 916 Radeon_TempHideOverlay( ai ); 917 918 // remember that there is no overlay to be shown 919 si->active_overlay.on = NULL; 920 si->active_overlay.prev_on = NULL; 921 si->pending_overlay.on = NULL; 922 923 // invalidate active head so it will be setup again once 924 // a new overlay is shown 925 si->active_overlay.crtc_idx = -1; 926 } 927 928 929 // show new overlay buffer with same parameters as last one 930 static void Radeon_ReplaceOverlayBuffer( 931 accelerator_info *ai ) 932 { 933 #if 0 934 shared_info *si = ai->si; 935 vuint8 *regs = ai->regs; 936 uint32 offset; 937 int /*old_buf, */new_buf; 938 939 offset = si->pending_overlay.on->mem_offset + si->active_overlay.rel_offset; 940 941 /*old_buf = si->overlay_mgr.auto_flip_reg & RADEON_OV0_SOFT_BUF_NUM_MASK; 942 new_buf = old_buf == 0 ? 3 : 0; 943 si->overlay_mgr.auto_flip_reg &= ~RADEON_OV0_SOFT_BUF_NUM_MASK; 944 si->overlay_mgr.auto_flip_reg |= new_buf;*/ 945 new_buf = 0; 946 947 // lock overlay registers 948 /* OUTREG( regs, RADEON_OV0_REG_LOAD_CNTL, RADEON_REG_LD_CTL_LOCK ); 949 950 // wait until register access is locked 951 while( (INREG( regs, RADEON_OV0_REG_LOAD_CNTL) 952 & RADEON_REG_LD_CTL_LOCK_READBACK) == 0 ) 953 ;*/ 954 955 // setup new buffer 956 /*OUTREG( regs, 957 new_buf == 0 ? RADEON_OV0_VID_BUF_PITCH0_VALUE : RADEON_OV0_VID_BUF_PITCH1_VALUE, 958 si->pending_overlay.on->buffer.bytes_per_row );*/ 959 OUTREG( regs, 960 new_buf == 0 ? RADEON_OV0_VID_BUF0_BASE_ADRS : RADEON_OV0_VID_BUF3_BASE_ADRS, 961 offset | (new_buf == 0 ? 0 : RADEON_VIF_BUF0_PITCH_SEL)); 962 963 // make changes visible 964 si->overlay_mgr.auto_flip_reg ^= RADEON_OV0_SOFT_EOF_TOGGLE; 965 966 OUTREG( regs, RADEON_OV0_AUTO_FLIP_CNTRL, si->overlay_mgr.auto_flip_reg ); 967 968 // unlock overlay registers 969 // OUTREG( regs, RADEON_OV0_REG_LOAD_CNTL, 0 ); 970 971 ai->si->active_overlay.on = ai->si->pending_overlay.on; 972 #else 973 shared_info *si = ai->si; 974 uint32 offset; 975 976 START_IB(); 977 978 offset = si->pending_overlay.on->mem_offset + si->active_overlay.rel_offset; 979 980 WRITE_IB_REG( RADEON_OV0_VID_BUF0_BASE_ADRS, offset); 981 982 si->overlay_mgr.auto_flip_reg ^= RADEON_OV0_SOFT_EOF_TOGGLE; 983 WRITE_IB_REG( RADEON_OV0_AUTO_FLIP_CNTRL, si->overlay_mgr.auto_flip_reg ); 984 985 SUBMIT_IB(); 986 987 ai->si->active_overlay.on = ai->si->pending_overlay.on; 988 #endif 989 } 990 991 992 // get number of pixels of overlay shown on virtual port 993 static int getIntersectArea( 994 accelerator_info *ai, overlay_window *ow, crtc_info *crtc ) 995 { 996 virtual_card *vc = ai->vc; 997 int left, top, right, bottom; 998 999 left = ow->h_start - (vc->mode.h_display_start + crtc->rel_x); 1000 top = ow->v_start - (vc->mode.v_display_start + crtc->rel_y); 1001 right = left + ow->width; 1002 bottom = top + ow->height; 1003 1004 if( left < 0 ) 1005 left = 0; 1006 if( top < 0 ) 1007 top = 0; 1008 if( right > crtc->mode.timing.h_display ) 1009 right = crtc->mode.timing.h_display; 1010 if( bottom > crtc->mode.timing.v_display ) 1011 bottom = crtc->mode.timing.v_display; 1012 1013 if( right < left || bottom < top ) 1014 return 0; 1015 1016 return (right - left) * (bottom - top); 1017 } 1018 1019 1020 // update overlay, to be called whenever something in terms of 1021 // overlay have or can have been changed 1022 status_t Radeon_UpdateOverlay( 1023 accelerator_info *ai ) 1024 { 1025 virtual_card *vc = ai->vc; 1026 shared_info *si = ai->si; 1027 int crtc_idx; 1028 1029 float brightness = 0.0f; 1030 float contrast = 1.0f; 1031 float saturation = 1.0f; 1032 float hue = 0.0f; 1033 int32 ref = 0; 1034 1035 SHOW_FLOW0( 3, "" ); 1036 1037 // don't mess around with overlay of someone else 1038 if( !vc->uses_overlay ) 1039 return B_OK; 1040 1041 // make sure there really is an overlay 1042 if( si->pending_overlay.on == NULL ) 1043 return B_OK; 1044 1045 // verify that the overlay is still valid 1046 if( (uint32)si->pending_overlay.ot != si->overlay_mgr.token ) 1047 return B_BAD_VALUE; 1048 1049 if( vc->different_heads > 1 ) { 1050 int area0, area1; 1051 1052 // determine on which port most of the overlay is shown 1053 area0 = getIntersectArea( ai, &si->pending_overlay.ow, &si->crtc[0] ); 1054 area1 = getIntersectArea( ai, &si->pending_overlay.ow, &si->crtc[0] ); 1055 1056 SHOW_FLOW( 3, "area0=%d, area1=%d", area0, area1 ); 1057 1058 if( area0 >= area1 ) 1059 crtc_idx = 0; 1060 else 1061 crtc_idx = 1; 1062 1063 } else if( vc->independant_heads > 1 ) { 1064 // both ports show the same, use "swap displays" to decide 1065 // where to show the overlay (to be improved as this flag isn't 1066 // really designed for that) 1067 if( vc->swap_displays ) 1068 crtc_idx = 1; 1069 else 1070 crtc_idx = 0; 1071 1072 } else { 1073 1074 // one crtc used only - pick the one that we use 1075 crtc_idx = vc->used_crtc[0] ? 0 : 1; 1076 } 1077 1078 si->pending_overlay.crtc_idx = crtc_idx; 1079 1080 // only update registers that have been changed to minimize work 1081 if( si->active_overlay.crtc_idx != si->pending_overlay.crtc_idx ) { 1082 Radeon_InitOverlay( ai, crtc_idx ); 1083 } 1084 1085 if( si->active_overlay.ob.space != si->pending_overlay.ob.space ) { 1086 Radeon_SetTransform( ai, brightness, contrast, saturation, hue, 0, 0, 0, ref ); 1087 } 1088 1089 if( memcmp( &si->active_overlay.ow, &si->pending_overlay.ow, sizeof( si->active_overlay.ow )) != 0 || 1090 memcmp( &si->active_overlay.ov, &si->pending_overlay.ov, sizeof( si->active_overlay.ov )) != 0 || 1091 si->active_overlay.h_display_start != vc->mode.h_display_start || 1092 si->active_overlay.v_display_start != vc->mode.v_display_start || 1093 si->active_overlay.ob.width != si->pending_overlay.ob.width || 1094 si->active_overlay.ob.height != si->pending_overlay.ob.height || 1095 si->active_overlay.ob.bytes_per_row != si->pending_overlay.ob.bytes_per_row ) 1096 Radeon_ShowOverlay( ai, crtc_idx ); 1097 1098 else if( si->active_overlay.on != si->pending_overlay.on ) 1099 Radeon_ReplaceOverlayBuffer( ai ); 1100 1101 SHOW_FLOW0( 3, "success" ); 1102 1103 return B_OK; 1104 } 1105