📄 overlay.c
字号:
} // get initial horizontal scaler values, taking care of precharge // don't ask questions about formulas - take them as is // (TBD: home-brewed sub-pixel source clipping may be wrong, // especially for uv-planes) { uint32 p23_group_size; tmp = ((src_left & 0xffff) >> 11) + ( ( I2FF( p1_x_start % factors->group_size, 12 ) + I2FF( 2.5, 12 ) + p1_h_inc / 2 + I2FF( 0.5, 12-5 ) // rounding ) >> (12 - 5)); // scaled by 1 << 5 SHOW_FLOW( 3, "p1_h_accum_init=%x", tmp ); p1_h_accum_init = ((tmp << 15) & RADEON_OV0_P1_H_ACCUM_INIT_MASK) | ((tmp << 23) & RADEON_OV0_P1_PRESHIFT_MASK); p23_group_size = 2; tmp = ((src_left & 0xffff) >> 11) + ( ( I2FF( p23_x_start % p23_group_size, 12 ) + I2FF( 2.5, 12 ) + p23_h_inc / 2 + I2FF( 0.5, 12-5 ) // rounding ) >> (12 - 5)); // scaled by 1 << 5 SHOW_FLOW( 3, "p23_h_accum_init=%x", tmp ); p23_h_accum_init = ((tmp << 15) & RADEON_OV0_P23_H_ACCUM_INIT_MASK) | ((tmp << 23) & RADEON_OV0_P23_PRESHIFT_MASK); } // get initial vertical scaler values, taking care of precharge { uint extra_full_line; extra_full_line = factors->p1_step_by == 0 ? 1 : 0; tmp = ((src_top & 0x0000ffff) >> 11) + ( (min( I2FF( 1.5, 20 ) + I2FF( extra_full_line, 20 ) + v_inc / 2, I2FF( 2.5, 20 ) + 2 * I2FF( extra_full_line, 20 ) ) + I2FF( 0.5, 20-5 )) // rounding >> (20 - 5)); // scaled by 1 << 5 SHOW_FLOW( 3, "p1_v_accum_init=%x", tmp ); p1_v_accum_init = ((tmp << 15) & RADEON_OV0_P1_V_ACCUM_INIT_MASK) | 0x00000001; extra_full_line = factors->p23_step_by == 0 ? 1 : 0; if( params->v_uv_sub_sample_shift > 0 ) { tmp = ((src_top & 0x0000ffff) >> 11) + ( (min( I2FF( 1.5, 20 ) + I2FF( extra_full_line, 20 ) + ((v_inc / 2) >> params->v_uv_sub_sample_shift), I2FF( 2.5, 20 ) + 2 * I2FF( extra_full_line, 20 ) ) + I2FF( 0.5, 20-5 )) // rounding >> (20 - 5)); // scaled by 1 << 5 } else { tmp = ((src_top & 0x0000ffff) >> 11) + ( ( I2FF( 2.5, 20 ) + 2 * I2FF( extra_full_line, 20 ) + I2FF( 0.5, 20-5 ) // rounding ) >> (20 - 5)); // scaled by 1 << 5 } SHOW_FLOW( 3, "p23_v_accum_init=%x", tmp ); p23_v_accum_init = ((tmp << 15) & RADEON_OV0_P23_V_ACCUM_INIT_MASK) | 0x00000001; } // show me what you've got! // we could lock double buffering of overlay unit during update // (new values are copied during vertical blank, so if we've updated // only some of them, you get a whole frame of mismatched values) // but during tests I couldn't get the artifacts go away, so // we use the dangerous way which has the pro to not require any // waiting // let's try to lock overlay unit // we had to wait now until the lock takes effect, but this is // impossible with CCE; perhaps we have to convert this code to // direct register access; did that - let's see what happens... OUTREG( regs, RADEON_OV0_REG_LOAD_CNTL, RADEON_REG_LD_CTL_LOCK ); // wait until register access is locked while( (INREG( regs, RADEON_OV0_REG_LOAD_CNTL) & RADEON_REG_LD_CTL_LOCK_READBACK) == 0 ) ; OUTREG( regs, RADEON_OV0_VID_BUF0_BASE_ADRS, offset ); OUTREG( regs, RADEON_OV0_VID_BUF_PITCH0_VALUE, node->buffer.bytes_per_row ); OUTREG( regs, RADEON_OV0_H_INC, p1_h_inc | (p23_h_inc << 16) ); OUTREG( regs, RADEON_OV0_STEP_BY, factors->p1_step_by | (factors->p23_step_by << 8) ); OUTREG( regs, RADEON_OV0_V_INC, v_inc ); OUTREG( regs, crtc->crtc_idx == 0 ? RADEON_OV0_Y_X_START : RADEON_OV1_Y_X_START, (dest_left) | (dest_top << 16) ); OUTREG( regs, crtc->crtc_idx == 0 ? RADEON_OV0_Y_X_END : RADEON_OV1_Y_X_END, (dest_right - 1) | ((dest_bottom - 1) << 16) ); OUTREG( regs, RADEON_OV0_P1_BLANK_LINES_AT_TOP, RADEON_P1_BLNK_LN_AT_TOP_M1_MASK | (p1_active_lines << 16) ); OUTREG( regs, RADEON_OV0_P1_X_START_END, p1_x_end | (p1_x_start << 16) ); OUTREG( regs, RADEON_OV0_P1_H_ACCUM_INIT, p1_h_accum_init ); OUTREG( regs, RADEON_OV0_P1_V_ACCUM_INIT, p1_v_accum_init ); OUTREG( regs, RADEON_OV0_P23_BLANK_LINES_AT_TOP, RADEON_P23_BLNK_LN_AT_TOP_M1_MASK | (p23_active_lines << 16) ); OUTREG( regs, RADEON_OV0_P2_X_START_END, p23_x_end | (p23_x_start << 16) ); OUTREG( regs, RADEON_OV0_P3_X_START_END, p23_x_end | (p23_x_start << 16) ); OUTREG( regs, RADEON_OV0_P23_H_ACCUM_INIT, p23_h_accum_init ); OUTREG( regs, RADEON_OV0_P23_V_ACCUM_INIT, p23_v_accum_init ); OUTREG( regs, RADEON_OV0_TEST, node->test_reg ); OUTREG( regs, RADEON_OV0_SCALE_CNTL, RADEON_SCALER_ENABLE | RADEON_SCALER_DOUBLE_BUFFER | (node->ati_space << 8) | /*RADEON_SCALER_ADAPTIVE_DEINT |*/ (crtc->crtc_idx == 0 ? 0 : RADEON_SCALER_CRTC_SEL )); si->overlay_mgr.auto_flip_reg ^= RADEON_OV0_SOFT_EOF_TOGGLE; OUTREG( regs, RADEON_OV0_AUTO_FLIP_CNTRL, si->overlay_mgr.auto_flip_reg ); OUTREG( regs, RADEON_OV0_REG_LOAD_CNTL, 0 ); done: ai->si->active_overlay.on = ai->si->pending_overlay.on; ai->si->active_overlay.ow = ai->si->pending_overlay.ow; ai->si->active_overlay.ov = ai->si->pending_overlay.ov; ai->si->active_overlay.ob = ai->si->pending_overlay.ob; ai->si->active_overlay.h_display_start = vc->mode.h_display_start; ai->si->active_overlay.v_display_start = vc->mode.v_display_start; return B_OK;}// hide overlay, but not permanentlyvoid Radeon_TempHideOverlay( accelerator_info *ai ){ SHOW_FLOW0( 3, "" ); OUTREG( ai->regs, RADEON_OV0_SCALE_CNTL, 0 );}// hide overlay (can be called even if there is none visible)void Radeon_HideOverlay( accelerator_info *ai ){ shared_info *si = ai->si; Radeon_TempHideOverlay( ai ); // remember that there is no overlay to be shown si->active_overlay.on = NULL; si->active_overlay.prev_on = NULL; si->pending_overlay.on = NULL; // invalidate active head so it will be setup again once // a new overlay is shown si->active_overlay.crtc_idx = -1;}// show new overlay buffer with same parameters as last onestatic void Radeon_ReplaceOverlayBuffer( accelerator_info *ai ){#if 0 shared_info *si = ai->si; vuint8 *regs = ai->regs; uint32 offset; int /*old_buf, */new_buf; offset = si->pending_overlay.on->mem_offset + si->active_overlay.rel_offset; /*old_buf = si->overlay_mgr.auto_flip_reg & RADEON_OV0_SOFT_BUF_NUM_MASK; new_buf = old_buf == 0 ? 3 : 0; si->overlay_mgr.auto_flip_reg &= ~RADEON_OV0_SOFT_BUF_NUM_MASK; si->overlay_mgr.auto_flip_reg |= new_buf;*/ new_buf = 0; // lock overlay registers/* OUTREG( regs, RADEON_OV0_REG_LOAD_CNTL, RADEON_REG_LD_CTL_LOCK ); // wait until register access is locked while( (INREG( regs, RADEON_OV0_REG_LOAD_CNTL) & RADEON_REG_LD_CTL_LOCK_READBACK) == 0 ) ;*/ // setup new buffer /*OUTREG( regs, new_buf == 0 ? RADEON_OV0_VID_BUF_PITCH0_VALUE : RADEON_OV0_VID_BUF_PITCH1_VALUE, si->pending_overlay.on->buffer.bytes_per_row );*/ OUTREG( regs, new_buf == 0 ? RADEON_OV0_VID_BUF0_BASE_ADRS : RADEON_OV0_VID_BUF3_BASE_ADRS, offset | (new_buf == 0 ? 0 : RADEON_VIF_BUF0_PITCH_SEL)); // make changes visible si->overlay_mgr.auto_flip_reg ^= RADEON_OV0_SOFT_EOF_TOGGLE; OUTREG( regs, RADEON_OV0_AUTO_FLIP_CNTRL, si->overlay_mgr.auto_flip_reg ); // unlock overlay registers// OUTREG( regs, RADEON_OV0_REG_LOAD_CNTL, 0 ); ai->si->active_overlay.on = ai->si->pending_overlay.on;#else shared_info *si = ai->si; uint32 offset; START_IB(); offset = si->pending_overlay.on->mem_offset + si->active_overlay.rel_offset; WRITE_IB_REG( RADEON_OV0_VID_BUF0_BASE_ADRS, offset); si->overlay_mgr.auto_flip_reg ^= RADEON_OV0_SOFT_EOF_TOGGLE; WRITE_IB_REG( RADEON_OV0_AUTO_FLIP_CNTRL, si->overlay_mgr.auto_flip_reg ); SUBMIT_IB(); ai->si->active_overlay.on = ai->si->pending_overlay.on;#endif}// get number of pixels of overlay shown on virtual portstatic int getIntersectArea( accelerator_info *ai, overlay_window *ow, crtc_info *crtc ){ virtual_card *vc = ai->vc; int left, top, right, bottom; left = ow->h_start - (vc->mode.h_display_start + crtc->rel_x); top = ow->v_start - (vc->mode.v_display_start + crtc->rel_y); right = left + ow->width; bottom = top + ow->height; if( left < 0 ) left = 0; if( top < 0 ) top = 0; if( right > crtc->mode.timing.h_display ) right = crtc->mode.timing.h_display; if( bottom > crtc->mode.timing.v_display ) bottom = crtc->mode.timing.v_display; if( right < left || bottom < top ) return 0; return (right - left) * (bottom - top);}// update overlay, to be called whenever something in terms of // overlay have or can have been changedstatus_t Radeon_UpdateOverlay( accelerator_info *ai ){ virtual_card *vc = ai->vc; shared_info *si = ai->si; int crtc_idx; float brightness = 0.0f; float contrast = 1.0f; float saturation = 1.0f; float hue = 0.0f; int32 ref = 0; SHOW_FLOW0( 3, "" ); // don't mess around with overlay of someone else if( !vc->uses_overlay ) return B_OK; // make sure there really is an overlay if( si->pending_overlay.on == NULL ) return B_OK; // verify that the overlay is still valid if( (uint32)si->pending_overlay.ot != si->overlay_mgr.token ) return B_BAD_VALUE; if( vc->different_heads > 1 ) { int area0, area1; // determine on which port most of the overlay is shown area0 = getIntersectArea( ai, &si->pending_overlay.ow, &si->crtc[0] ); area1 = getIntersectArea( ai, &si->pending_overlay.ow, &si->crtc[0] ); SHOW_FLOW( 3, "area0=%d, area1=%d", area0, area1 ); if( area0 >= area1 ) crtc_idx = 0; else crtc_idx = 1; } else if( vc->independant_heads > 1 ) { // both ports show the same, use "swap displays" to decide // where to show the overlay (to be improved as this flag isn't // really designed for that) if( vc->swap_displays ) crtc_idx = 1; else crtc_idx = 0; } else { // one crtc used only - pick the one that we use crtc_idx = vc->used_crtc[0] ? 0 : 1; } si->pending_overlay.crtc_idx = crtc_idx; // only update registers that have been changed to minimize work if( si->active_overlay.crtc_idx != si->pending_overlay.crtc_idx ) { Radeon_InitOverlay( ai, crtc_idx ); } if( si->active_overlay.ob.space != si->pending_overlay.ob.space ) { Radeon_SetTransform( ai, brightness, contrast, saturation, hue, 0, 0, 0, ref ); } if( memcmp( &si->active_overlay.ow, &si->pending_overlay.ow, sizeof( si->active_overlay.ow )) != 0 || memcmp( &si->active_overlay.ov, &si->pending_overlay.ov, sizeof( si->active_overlay.ov )) != 0 || si->active_overlay.h_display_start != vc->mode.h_display_start || si->active_overlay.v_display_start != vc->mode.v_display_start || si->active_overlay.ob.width != si->pending_overlay.ob.width || si->active_overlay.ob.height != si->pending_overlay.ob.height || si->active_overlay.ob.bytes_per_row != si->pending_overlay.ob.bytes_per_row ) Radeon_ShowOverlay( ai, crtc_idx ); else if( si->active_overlay.on != si->pending_overlay.on ) Radeon_ReplaceOverlayBuffer( ai ); SHOW_FLOW0( 3, "success" ); return B_OK;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -