📄 overlay.c
字号:
/* Copyright (c) 2002, Thomas Kurschel Part of Radeon accelerant Hardware access routines for overlays*/#include "GlobalData.h"#include "radeon_interface.h"#include "../shared/mmio.h"#include "../regs/overlay_regs.h"#include "../regs/pll_regs.h"#include "../regs/capture_regs.h"#include "../common/utils.h"#include "../shared/pll_access.h"#include <math.h>#include <string.h>#include "CP.h"void Radeon_TempHideOverlay( accelerator_info *ai );// standard (linear) gammastatic struct { uint16 reg; bool r200_or_above; uint32 slope; uint32 offset;} std_gamma[] = { { RADEON_OV0_GAMMA_0_F, false, 0x100, 0x0000 }, { RADEON_OV0_GAMMA_10_1F, false, 0x100, 0x0020 }, { RADEON_OV0_GAMMA_20_3F, false, 0x100, 0x0040 }, { RADEON_OV0_GAMMA_40_7F, false, 0x100, 0x0080 }, { RADEON_OV0_GAMMA_80_BF, true, 0x100, 0x0100 }, { RADEON_OV0_GAMMA_C0_FF, true, 0x100, 0x0100 }, { RADEON_OV0_GAMMA_100_13F, true, 0x100, 0x0200 }, { RADEON_OV0_GAMMA_140_17F, true, 0x100, 0x0200 }, { RADEON_OV0_GAMMA_180_1BF, true, 0x100, 0x0300 }, { RADEON_OV0_GAMMA_1C0_1FF, true, 0x100, 0x0300 }, { RADEON_OV0_GAMMA_200_23F, true, 0x100, 0x0400 }, { RADEON_OV0_GAMMA_240_27F, true, 0x100, 0x0400 }, { RADEON_OV0_GAMMA_280_2BF, true, 0x100, 0x0500 }, { RADEON_OV0_GAMMA_2C0_2FF, true, 0x100, 0x0500 }, { RADEON_OV0_GAMMA_300_33F, true, 0x100, 0x0600 }, { RADEON_OV0_GAMMA_340_37F, true, 0x100, 0x0600 }, { RADEON_OV0_GAMMA_380_3BF, false, 0x100, 0x0700 }, { RADEON_OV0_GAMMA_3C0_3FF, false, 0x100, 0x0700 }};// setup overlay unit before first usevoid Radeon_InitOverlay( accelerator_info *ai, int crtc_idx ){ vuint8 *regs = ai->regs; shared_info *si = ai->si; uint i; uint32 ecp_div; SHOW_FLOW0( 0, "" ); // make sure we really write this value as the "toggle" bit // contained in it (which is zero initially) is edge-sensitive! // for capturing, we need to select "software" video port si->overlay_mgr.auto_flip_reg = RADEON_OV0_VID_PORT_SELECT_SOFTWARE; OUTREG( regs, RADEON_OV0_SCALE_CNTL, RADEON_SCALER_SOFT_RESET ); OUTREG( regs, RADEON_OV0_AUTO_FLIP_CNTRL, si->overlay_mgr.auto_flip_reg ); OUTREG( regs, RADEON_OV0_FILTER_CNTL, // use fixed filter coefficients RADEON_OV0_HC_COEF_ON_HORZ_Y | RADEON_OV0_HC_COEF_ON_HORZ_UV | RADEON_OV0_HC_COEF_ON_VERT_Y | RADEON_OV0_HC_COEF_ON_VERT_UV ); OUTREG( regs, RADEON_OV0_KEY_CNTL, RADEON_GRAPHIC_KEY_FN_EQ | RADEON_VIDEO_KEY_FN_FALSE | RADEON_CMP_MIX_OR ); OUTREG( regs, RADEON_OV0_TEST, 0 );// OUTREG( regs, RADEON_FCP_CNTL, RADEON_FCP_CNTL_GND ); // disable capture clock// OUTREG( regs, RADEON_CAP0_TRIG_CNTL, 0 ); // disable capturing OUTREG( regs, RADEON_OV0_REG_LOAD_CNTL, 0 ); // tell deinterlacer to always show recent field OUTREG( regs, RADEON_OV0_DEINTERLACE_PATTERN, 0xaaaaa | (9 << RADEON_OV0_DEINT_PAT_LEN_M1_SHIFT) ); // set gamma for( i = 0; i < sizeof( std_gamma ) / sizeof( std_gamma[0] ); ++i ) { if( !std_gamma[i].r200_or_above || si->asic >= rt_r200 ) { OUTREG( regs, std_gamma[i].reg, (std_gamma[i].slope << 16) | std_gamma[i].offset ); } } // overlay unit can only handle up to 175 MHz, if pixel clock is higher, // only every second pixel is handled if( si->crtc[crtc_idx].mode.timing.pixel_clock < 175000 ) ecp_div = 0; else ecp_div = 1; Radeon_OUTPLLP( regs, si->asic, RADEON_VCLK_ECP_CNTL, ecp_div << RADEON_ECP_DIV_SHIFT, ~RADEON_ECP_DIV_MASK ); si->active_overlay.crtc_idx = si->pending_overlay.crtc_idx; // invalidate active colour space si->active_overlay.ob.space = -1; // invalidate position/scaling si->active_overlay.ob.width = -1;}// colour space transformation matrixtypedef struct space_transform{ float RefLuma; // scaling of luma to use full RGB range float RefRCb; // b/u -> r float RefRY; // g/y -> r float RefRCr; // r/v -> r float RefGCb; float RefGY; float RefGCr; float RefBCb; float RefBY; float RefBCr;} space_transform;// Parameters for ITU-R BT.601 and ITU-R BT.709 colour spacesspace_transform trans_yuv[2] ={ { 1.1678, 0.0, 1, 1.6007, -0.3929, 1, -0.8154, 2.0232, 1, 0.0 }, /* BT.601 */ { 1.1678, 0.0, 1, 1.7980, -0.2139, 1, -0.5345, 2.1186, 1, 0.0 } /* BT.709 */};// RGB is a pass throughspace_transform trans_rgb = { 1, 0, 0, 1, 0, 1, 0, 1, 0, 0 };// set overlay colour space transformation matrixstatic void Radeon_SetTransform( accelerator_info *ai, float bright, float cont, float sat, float hue, float red_intensity, float green_intensity, float blue_intensity, uint ref){ vuint8 *regs = ai->regs; shared_info *si = ai->si; float OvHueSin, OvHueCos; float CAdjOff; float CAdjRY, CAdjGY, CAdjBY; float CAdjRCb, CAdjRCr; float CAdjGCb, CAdjGCr; float CAdjBCb, CAdjBCr; float RedAdj,GreenAdj,BlueAdj; float OvROff, OvGOff, OvBOff; float OvRY, OvGY, OvBY; float OvRCb, OvRCr; float OvGCb, OvGCr; float OvBCb, OvBCr; float Loff; float Coff; uint32 dwOvROff, dwOvGOff, dwOvBOff; uint32 dwOvRY, dwOvGY, dwOvBY; uint32 dwOvRCb, dwOvRCr; uint32 dwOvGCb, dwOvGCr; uint32 dwOvBCb, dwOvBCr; space_transform *trans; SHOW_FLOW0( 0, "" ); // get proper conversion formula switch( si->pending_overlay.ob.space ) { case B_YCbCr422: case B_YUV12: Loff = 16 * 4; // internal representation is 10 Bits Coff = 128 * 4; if (ref >= 2) ref = 0; trans = &trans_yuv[ref]; break; case B_RGB15: case B_RGB16: case B_RGB32: default: Loff = 0; Coff = 0; trans = &trans_rgb; } OvHueSin = sin(hue); OvHueCos = cos(hue); // get matrix values to convert overlay colour space to RGB // applying colour adjustment, saturation and luma scaling // (saturation doesn't work with RGB input, perhaps it did with some // maths; this is left to the reader :) CAdjRY = cont * trans->RefLuma * trans->RefRY; CAdjGY = cont * trans->RefLuma * trans->RefGY; CAdjBY = cont * trans->RefLuma * trans->RefBY; CAdjRCb = sat * -OvHueSin * trans->RefRCr; CAdjRCr = sat * OvHueCos * trans->RefRCr; CAdjGCb = sat * (OvHueCos * trans->RefGCb - OvHueSin * trans->RefGCr); CAdjGCr = sat * (OvHueSin * trans->RefGCb + OvHueCos * trans->RefGCr); CAdjBCb = sat * OvHueCos * trans->RefBCb; CAdjBCr = sat * OvHueSin * trans->RefBCb; // adjust black level CAdjOff = cont * trans[ref].RefLuma * bright * 1023.0; RedAdj = cont * trans[ref].RefLuma * red_intensity * 1023.0; GreenAdj = cont * trans[ref].RefLuma * green_intensity * 1023.0; BlueAdj = cont * trans[ref].RefLuma * blue_intensity * 1023.0; OvRY = CAdjRY; OvGY = CAdjGY; OvBY = CAdjBY; OvRCb = CAdjRCb; OvRCr = CAdjRCr; OvGCb = CAdjGCb; OvGCr = CAdjGCr; OvBCb = CAdjBCb; OvBCr = CAdjBCr; // apply offsets OvROff = RedAdj + CAdjOff - CAdjRY * Loff - (OvRCb + OvRCr) * Coff; OvGOff = GreenAdj + CAdjOff - CAdjGY * Loff - (OvGCb + OvGCr) * Coff; OvBOff = BlueAdj + CAdjOff - CAdjBY * Loff - (OvBCb + OvBCr) * Coff; dwOvROff = ((int32)(OvROff * 2.0)) & 0x1fff; dwOvGOff = ((int32)(OvGOff * 2.0)) & 0x1fff; dwOvBOff = ((int32)(OvBOff * 2.0)) & 0x1fff; dwOvRY = (((int32)(OvRY * 2048.0))&0x7fff)<<17; dwOvGY = (((int32)(OvGY * 2048.0))&0x7fff)<<17; dwOvBY = (((int32)(OvBY * 2048.0))&0x7fff)<<17; dwOvRCb = (((int32)(OvRCb * 2048.0))&0x7fff)<<1; dwOvRCr = (((int32)(OvRCr * 2048.0))&0x7fff)<<17; dwOvGCb = (((int32)(OvGCb * 2048.0))&0x7fff)<<1; dwOvGCr = (((int32)(OvGCr * 2048.0))&0x7fff)<<17; dwOvBCb = (((int32)(OvBCb * 2048.0))&0x7fff)<<1; dwOvBCr = (((int32)(OvBCr * 2048.0))&0x7fff)<<17; OUTREG( regs, RADEON_OV0_LIN_TRANS_A, dwOvRCb | dwOvRY ); OUTREG( regs, RADEON_OV0_LIN_TRANS_B, dwOvROff | dwOvRCr ); OUTREG( regs, RADEON_OV0_LIN_TRANS_C, dwOvGCb | dwOvGY ); OUTREG( regs, RADEON_OV0_LIN_TRANS_D, dwOvGOff | dwOvGCr ); OUTREG( regs, RADEON_OV0_LIN_TRANS_E, dwOvBCb | dwOvBY ); OUTREG( regs, RADEON_OV0_LIN_TRANS_F, dwOvBOff | dwOvBCr ); si->active_overlay.ob.space = si->pending_overlay.ob.space;}// convert Be colour key to rgb valuestatic uint32 colourKey2RGB32( uint32 space, uint8 red, uint8 green, uint8 blue ) { uint32 res; SHOW_FLOW0( 3, "" ); // the way Be defines colour keys may be convinient to some driver developers, // but it's not well defined - took me some time to find out the format used // and still I have no idea how alpha is defined; Rudolf told me that alpha is // never used switch( space ) { case B_RGB15: res = ((uint32)(red >> 0) << (16+3)) | ((uint32)(green >> 0) << (8+3)) | ((blue >> 0) << 3); break; case B_RGB16: res = ((uint32)(red >> 0) << (16+3)) | ((uint32)(green >> 0) << (8+2)) | ((blue >> 0) << 3); break; case B_RGB32: case B_CMAP8: res = ((uint32)(red) << 16) | ((uint32)(green) << 8) | blue; break; default: res = 0; } SHOW_FLOW( 3, "key=%lx", res ); return res;}// set colour key of overlaystatic void Radeon_SetColourKey( accelerator_info *ai, const overlay_window *ow ){ virtual_card *vc = ai->vc; vuint8 *regs = ai->regs; uint32 rgb32, mask32, min32, max32; /*SHOW_FLOW( 0, "value=%02x %02x %02x, mask=%02x %02x %02x", ow->red.value, ow->green.value, ow->blue.value, ow->red.mask, ow->green.mask, ow->blue.mask );*/ // Radeons don't support value and mask as colour key but colour range rgb32 = colourKey2RGB32( vc->mode.space, ow->red.value, ow->green.value, ow->blue.value ); mask32 = colourKey2RGB32( vc->mode.space, ow->red.mask, ow->green.mask, ow->blue.mask ); // ~mask32 are all unimportant (usually low order) bits // oring this to the colour should give us the highest valid colour value // (add would be more precise but may lead to overflows) min32 = rgb32; max32 = rgb32 | ~mask32; OUTREG( regs, RADEON_OV0_GRAPHICS_KEY_CLR_LOW, min32 ); OUTREG( regs, RADEON_OV0_GRAPHICS_KEY_CLR_HIGH, max32 ); OUTREG( regs, RADEON_OV0_KEY_CNTL, RADEON_GRAPHIC_KEY_FN_EQ | RADEON_VIDEO_KEY_FN_FALSE | RADEON_CMP_MIX_OR );}typedef struct { uint max_scale; // maximum src_width/dest_width, // i.e. source increment per screen pixel uint8 group_size; // size of one filter group in pixels uint8 p1_step_by, p23_step_by; // > 0: log(source pixel increment)+1, 2-tap filter // = 0: source pixel increment = 1, 4-tap filter} hscale_factor;#define count_of( a ) (sizeof( a ) / sizeof( a[0] ))// scaling/filter tables depending on overlay colour space:// magnifying pixels is no problem, but minifying can lead to overload,// so we have to skip pixels and/or use 2-tap filtersstatic hscale_factor scale_RGB16[] = { { (2 << 12), 2, 1, 1 }, { (4 << 12), 2, 2, 2 }, { (8 << 12), 2, 3, 3 }, { (16 << 12), 2, 4, 4 }, { (32 << 12), 2, 5, 5 }};static hscale_factor scale_RGB32[] = { { (2 << 12) / 3, 2, 0, 0 }, { (4 << 12) / 3, 4, 1, 1 }, { (8 << 12) / 3, 4, 2, 2 }, { (4 << 12), 4, 2, 3 }, { (16 << 12) / 3, 4, 3, 3 }, { (8 << 12), 4, 3, 4 }, { (32 << 12) / 3, 4, 4, 4 }, { (16 << 12), 4, 5, 5 }};static hscale_factor scale_YUV[] = {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -