DFBResult uc_ovl_update(UcDriverData* ucdrv, UcOverlayData* ucovl, int action, CoreSurface* surface) { int sw, sh, sp, sfmt; // Source width, height, pitch and format int dx, dy; // Destination position int dw, dh; // Destination width and height VideoMode *videomode; DFBRectangle scr; // Screen size bool write_buffers = false; bool write_settings = false; volatile u8* vio = ucdrv->hwregs; u32 win_start, win_end; // Overlay register settings u32 zoom, mini; u32 dcount, falign, qwpitch; u32 y_start, u_start, v_start; u32 v_ctrl, fifo_ctrl; int offset = surface->front_buffer->video.offset; if (!ucovl->v1.isenabled) return DFB_OK; qwpitch = 0; // Get screen size videomode = dfb_system_current_mode(); scr.w = videomode ? videomode->xres : 720; scr.h = videomode ? videomode->yres : 576; scr.x = 0; scr.y = 0; if (ucovl->scrwidth != scr.w) { // FIXME: fix uc_ovl_setup_fifo() // uc_ovl_setup_fifo(ucovl, scr.w); action |= UC_OVL_CHANGE; } D_ASSERT(surface); sw = surface->config.size.w; sh = surface->config.size.h; sp = surface->front_buffer->video.pitch; sfmt = surface->config.format; if (ucovl->deinterlace) { /*if (ucovl->field) offset += sp;*/ sh /= 2; //sp *= 2; } if (action & UC_OVL_CHANGE) { if ((sw > 4096) || (sh > 4096) || (sw < 32) || (sh < 1) || (sp > 0x1fff)) { D_DEBUG("Layer surface size is out of bounds."); return DFB_INVAREA; } dx = ucovl->v1.win.x; dy = ucovl->v1.win.y; dw = ucovl->v1.win.w; dh = ucovl->v1.win.h; // Get image format, FIFO size, etc. uc_ovl_map_v1_control(sfmt, sw, ucovl->hwrev, ucovl->extfifo_on, &v_ctrl, &fifo_ctrl); if (ucovl->deinterlace) { v_ctrl |= /*V1_BOB_ENABLE |*/ V1_FRAME_BASE; } // Get layer window. // The parts that fall outside the screen are clipped. uc_ovl_map_window(scr.w, scr.h, &(ucovl->v1.win), sw, sh, &win_start, &win_end, &ucovl->v1.ox, &ucovl->v1.oy); // Get scaling and data-fetch parameters // Note: the *_map_?zoom() functions return false if the scaling // is out of bounds. We don't act on it for now, because it only // makes the display look strange. zoom = 0; mini = 0; uc_ovl_map_vzoom(sh, dh, &zoom, &mini); uc_ovl_map_hzoom(sw, dw, &zoom, &mini, &falign, &dcount); qwpitch = uc_ovl_map_qwpitch(falign, sfmt, sw); write_settings = true; } if (action & (UC_OVL_FIELD | UC_OVL_FLIP | UC_OVL_CHANGE)) { int field = 0; // Update the buffer pointers if (ucovl->deinterlace) { field = ucovl->field; } uc_ovl_map_buffer(sfmt, offset, ucovl->v1.ox, ucovl->v1.oy, sw, surface->config.size.h, sp, 0/*field*/, &y_start, &u_start, &v_start); if (field) { y_start |= 0x08000000; } write_buffers = true; } // Write to the hardware /* if (write_settings || write_buffers) uc_ovl_vcmd_wait(vio);*/ if (write_settings) { VIDEO_OUT(vio, V1_CONTROL, v_ctrl); VIDEO_OUT(vio, V_FIFO_CONTROL, fifo_ctrl); VIDEO_OUT(vio, V1_WIN_START_Y, win_start); VIDEO_OUT(vio, V1_WIN_END_Y, win_end); VIDEO_OUT(vio, V1_SOURCE_HEIGHT, (sh << 16) | dcount); VIDEO_OUT(vio, V12_QWORD_PER_LINE, qwpitch); VIDEO_OUT(vio, V1_STRIDE, sp | ((sp >> 1) << 16)); VIDEO_OUT(vio, V1_MINI_CONTROL, mini); VIDEO_OUT(vio, V1_ZOOM_CONTROL, zoom); } if (write_buffers) { VIDEO_OUT(vio, V1_STARTADDR_0, y_start); VIDEO_OUT(vio, V1_STARTADDR_CB0, u_start); VIDEO_OUT(vio, V1_STARTADDR_CR0, v_start); } if (write_settings || write_buffers) { VIDEO_OUT(vio, V_COMPOSE_MODE, V1_COMMAND_FIRE); } return DFB_OK; }
static DFBResult uc_ovl_flip_region( CoreLayer *layer, void *driver_data, void *layer_data, void *region_data, CoreSurface *surface, DFBSurfaceFlipFlags flags, CoreSurfaceBufferLock *lock ) { //printf("Entering %s ... \n", __PRETTY_FUNCTION__); UcDriverData* ucdrv = (UcDriverData*) driver_data; UcOverlayData* ucovl = (UcOverlayData*) layer_data; DFBResult ret; FBDev *dfb_fbdev = dfb_system_data(); dfb_surface_flip(surface, false); ucovl->field = 0; ucovl->lock = lock; if (ucdrv->canfliponvsync) { if (ucovl->config.options & DLOP_FIELD_PARITY) { struct fb_flip flip; int field_option; field_option = VIAFB_WAIT_FLIP; // ensure last pending flip complete ioctl(dfb_fbdev->fd, FBIO_WAITFORVSYNC, &field_option); flip.device = VIAFB_FLIP_V1; flip.field = ucovl->config.parity; flip.count = 0; // until we implement this uc_ovl_map_buffer(surface->config.format, lock->offset, ucovl->v1.ox, ucovl->v1.oy, surface->config.size.w, surface->config.size.h, lock->pitch, 0, &flip.offset[0], &flip.offset[1], &flip.offset[2]); ioctl(dfb_fbdev->fd, FBIO_FLIPONVSYNC, &flip); } else { ret = uc_ovl_update(ucdrv, ucovl, UC_OVL_FLIP, surface, lock); if (ret) return ret; } } else { if (ucovl->config.options & DLOP_FIELD_PARITY) { int field_option; if (ucovl->config.parity == 0) // top field first? field_option = VIAFB_WAIT_BOTTOMFIELD; else field_option = VIAFB_WAIT_TOPFIELD; ioctl(dfb_fbdev->fd, FBIO_WAITFORVSYNC, &field_option); // that actually waits for VBLANK so we need a further delay // to be sure the field has started and that the flip will // take effect on the next field usleep(2500); } ret = uc_ovl_update(ucdrv, ucovl, UC_OVL_FLIP, surface, lock); if (ret) return ret; } if (flags & DSFLIP_WAIT) dfb_layer_wait_vsync(layer); return DFB_OK; }