[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH] Paravirt framebuffer kernel infrastructure [1/6]
Hi, IMHO, I think it should be better to move the refresh timer from kernel to user space, and to know which part of the image to refresh, a bitmap array should be easy to use than an event ring. I propose following patches to do this. Any comments ? Regards, Laurent Index: xen-3.0-testing.hg/linux-2.6.16.13-xen/drivers/xen/xenfb/xenfb.c =================================================================== --- xen-3.0-testing.hg.orig/linux-2.6.16.13-xen/drivers/xen/xenfb/xenfb.c 2006-08-29 12:16:49.000000000 +0200 +++ xen-3.0-testing.hg/linux-2.6.16.13-xen/drivers/xen/xenfb/xenfb.c 2006-08-29 16:15:04.000000000 +0200 @@ -24,118 +24,33 @@ #include <linux/xenfb.h> #include <linux/kthread.h> -static int xenfb_fps = 20; -static unsigned long xenfb_mem_len = 2 * 1024 * 1024; +static unsigned long xenfb_mem_len = XENFB_VIDEOMEM_SIZE; struct xenfb_mapping { - struct list_head next; struct vm_area_struct *vma; atomic_t map_refs; - int faults; struct xenfb_info *info; }; struct xenfb_info { - struct task_struct *kthread; - wait_queue_head_t wq; - unsigned char *fb; struct fb_fix_screeninfo *fix; struct fb_var_screeninfo *var; struct fb_info *fb_info; - struct timer_list refresh; - int dirty; int y1, y2; int x1, x2; struct semaphore mm_lock; int nr_pages; struct page **pages; - struct list_head mappings; unsigned evtchn; struct xenfb_page *page; unsigned long *mfns; }; -static void xenfb_do_update(struct xenfb_info *info, - int x, int y, int w, int h) -{ - union xenfb_out_event event; - __u32 prod; - - event.type = XENFB_TYPE_UPDATE; - event.update.x = x; - event.update.y = y; - event.update.width = w; - event.update.height = h; - - prod = info->page->out_prod; - if (prod - info->page->out_cons == XENFB_RING_SIZE(info->page->out)) - return; /* ring buffer full, event lost */ - XENFB_RING_REF(info->page->out, prod) = event; - info->page->out_prod = prod + 1; - - notify_remote_via_evtchn(info->evtchn); -} - -static int xenfb_queue_full(struct xenfb_info *info) -{ - __u32 cons, prod; - - prod = info->page->out_prod; - cons = info->page->out_cons; - return prod - cons == XENFB_RING_SIZE(info->page->out); -} - -static void xenfb_update_screen(struct xenfb_info *info) -{ - int y1, y2, x1, x2; - struct list_head *item; - struct xenfb_mapping *map; - - if (xenfb_queue_full(info)) - return; - - y1 = info->y1; - y2 = info->y2; - x1 = info->x1; - x2 = info->x2; - info->dirty = info->y1 = info->y2 = info->x1 = info->x2 = 0; - down(&info->mm_lock); - list_for_each(item, &info->mappings) { - map = list_entry(item, struct xenfb_mapping, next); - if (!map->faults) - continue; - zap_page_range(map->vma, map->vma->vm_start, - map->vma->vm_end - map->vma->vm_start, NULL); - map->faults = 0; - } - up(&info->mm_lock); - - xenfb_do_update(info, x1, y1, x2 - x1, y2 - y1); -} - -static int xenfb_thread(void *data) -{ - struct xenfb_info *info = data; - DECLARE_WAITQUEUE(wait, current); - - add_wait_queue(&info->wq, &wait); - for (;;) { - if (kthread_should_stop()) - break; - if (info->dirty) - xenfb_update_screen(info); - set_current_state(TASK_INTERRUPTIBLE); - schedule(); - } - remove_wait_queue(&info->wq, &wait); - return 0; -} - static int xenfb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *info) @@ -164,50 +79,24 @@ static int xenfb_setcolreg(unsigned regn return 0; } -static void xenfb_timer(unsigned long data) +static void xenfb_update_pages(struct xenfb_info *info, int x, int y, int w, int h) { - struct xenfb_info *info = (struct xenfb_info *)data; - info->dirty++; - wake_up(&info->wq); -} - -static void xenfb_refresh(struct xenfb_info *info, - int x1, int y1, int w, int h) -{ - int y2, x2; - - y2 = y1 + h; - x2 = x1 + w; - if (info->y2 == 0) { - info->y1 = y1; - info->y2 = y2; - } - if (info->x2 == 0) { - info->x1 = x1; - info->x2 = x2; - } + int begin, end; + int pgnr; - if (info->y1 > y1) - info->y1 = y1; - if (info->y2 < y2) - info->y2 = y2; - if (info->x1 > x1) - info->x1 = x1; - if (info->x2 < x2) - info->x2 = x2; + begin = (y * info->page->line_length + x * (info->page->depth / 8)) >> PAGE_SHIFT; + end = ((y + h - 1) * info->page->line_length + + ((x + w - 1) * (info->page->depth / 8))) >> PAGE_SHIFT; - if (timer_pending(&info->refresh)) - return; - - mod_timer(&info->refresh, jiffies + HZ/xenfb_fps); + for (pgnr = begin; pgnr <= end; pgnr++) + set_bit(pgnr, &info->page->dirty_pages); } static void xenfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect) { struct xenfb_info *info = p->par; - cfb_fillrect(p, rect); - xenfb_refresh(info, rect->dx, rect->dy, rect->width, rect->height); + xenfb_update_pages(info, rect->dx, rect->dy, rect->width, rect->height); } static void xenfb_imageblit(struct fb_info *p, const struct fb_image *image) @@ -215,7 +104,7 @@ static void xenfb_imageblit(struct fb_in struct xenfb_info *info = p->par; cfb_imageblit(p, image); - xenfb_refresh(info, image->dx, image->dy, image->width, image->height); + xenfb_update_pages(info, image->dx, image->dy, image->width, image->height); } static void xenfb_copyarea(struct fb_info *p, const struct fb_copyarea *area) @@ -223,7 +112,7 @@ static void xenfb_copyarea(struct fb_inf struct xenfb_info *info = p->par; cfb_copyarea(p, area); - xenfb_refresh(info, area->dx, area->dy, area->width, area->height); + xenfb_update_pages(info, area->dx, area->dy, area->width, area->height); } static void xenfb_vm_open(struct vm_area_struct *vma) @@ -239,7 +128,7 @@ static void xenfb_vm_close(struct vm_are down(&info->mm_lock); if (atomic_dec_and_test(&map->map_refs)) { - list_del(&map->next); + vma->vm_private_data = NULL; kfree(map); } up(&info->mm_lock); @@ -252,7 +141,6 @@ static struct page *xenfb_vm_nopage(stru struct xenfb_info *info = map->info; int pgnr = (vaddr - vma->vm_start) >> PAGE_SHIFT; struct page *page; - int y1, y2; if (pgnr >= info->nr_pages) return NOPAGE_SIGBUS; @@ -260,13 +148,10 @@ static struct page *xenfb_vm_nopage(stru down(&info->mm_lock); page = info->pages[pgnr]; get_page(page); - map->faults++; - y1 = pgnr * PAGE_SIZE / info->fix->line_length; - y2 = (pgnr * PAGE_SIZE + PAGE_SIZE - 1) / info->fix->line_length; - if (y2 > info->var->yres) - y2 = info->var->yres; - xenfb_refresh(info, 0, y1, info->var->xres, y2 - y1); + set_bit(pgnr, &info->page->dirty_pages); + zap_page_range(map->vma, map->vma->vm_start, map->vma->vm_end - map->vma->vm_start, NULL); + up(&info->mm_lock); if (type) @@ -309,10 +194,8 @@ static int xenfb_mmap(struct fb_info *fb memset(map, 0, sizeof(*map)); map->vma = vma; - map->faults = 0; map->info = info; atomic_set(&map->map_refs, 1); - list_add(&map->next, &info->mappings); vma->vm_ops = &xenfb_vm_ops; vma->vm_flags |= (VM_DONTEXPAND | VM_RESERVED); vma->vm_private_data = map; @@ -375,8 +258,6 @@ static int __init xenfb_probe(void) return -ENOMEM; memset(info, 0, sizeof(*info)); - INIT_LIST_HEAD(&info->mappings); - info->fb = vmalloc(xenfb_mem_len); if (info->fb == NULL) goto error; @@ -416,6 +297,8 @@ static int __init xenfb_probe(void) info->page->mem_length = xenfb_mem_len; info->page->in_cons = info->page->in_prod = 0; info->page->out_cons = info->page->out_prod = 0; + for (i = 0; i < XENFB_DIRTY_PAGES_SIZE; i++) + info->page->dirty_pages[i] = 0xFF; ret = bind_evtchn_to_irqhandler(info->evtchn, xenfb_event_handler, 0, "xenfb", info); @@ -464,12 +347,6 @@ static int __init xenfb_probe(void) info->var = &fb_info->var; init_MUTEX(&info->mm_lock); - init_waitqueue_head(&info->wq); - init_timer(&info->refresh); - info->refresh.function = xenfb_timer; - info->refresh.data = (unsigned long)info; - - info->kthread = kthread_run(xenfb_thread, info, "xenfb thread"); ret = register_framebuffer(fb_info); if (ret) @@ -518,30 +395,6 @@ static int __init xenfb_probe(void) return -ENODEV; } -void xenfb_resume(void) -{ -#if 0 /* FIXME */ - int i, ret; - - xenfb_info->page = mfn_to_virt(xen_start_info->fbdev_mfn); - for (i = 0; i < xenfb_info->nr_pages; i++) - xenfb_info->mfns[i] = vmalloc_to_mfn(xenfb_info->fb + i * PAGE_SIZE); - xenfb_info->page->pd[0] = vmalloc_to_mfn(xenfb_info->mfns); - - if (xenfb_irq) - unbind_from_irqhandler(xenfb_irq, NULL); - - printk("xenfb: resume(%d)\n", xen_start_info->fbdev_evtchn); - ret = bind_evtchn_to_irqhandler(xen_start_info->fbdev_evtchn, - xenfb_event_handler, 0, "xenfb", xenfb_info); - if (ret <= 0) - return; - xenfb_irq = ret; -#else - printk(KERN_DEBUG "xenfb_resume not implemented\n"); -#endif -} - static int __init xenfb_init(void) { return xenfb_probe(); Index: xen-3.0-testing.hg/linux-2.6.16.13-xen/include/linux/xenfb.h =================================================================== --- xen-3.0-testing.hg.orig/linux-2.6.16.13-xen/include/linux/xenfb.h 2006-08-29 12:16:49.000000000 +0200 +++ xen-3.0-testing.hg/linux-2.6.16.13-xen/include/linux/xenfb.h 2006-08-29 12:36:06.000000000 +0200 @@ -27,20 +27,10 @@ struct xenfb_motion __u16 y; /* The new y coordinate */ }; -struct xenfb_update -{ - __u8 type; /* XENFB_TYPE_UPDATE */ - __u16 x; /* source x */ - __u16 y; /* source y */ - __u16 width; /* rect width */ - __u16 height; /* rect height */ -}; - union xenfb_out_event { __u8 type; struct xenfb_motion motion; - struct xenfb_update update; char _[40]; }; @@ -69,11 +59,14 @@ union xenfb_in_event /* shared page */ #define XENFB_IN_RING_SIZE (1024 / 40) -#define XENFB_OUT_RING_SIZE (2048 / 40) +#define XENFB_OUT_RING_SIZE (1024 / 40) #define XENFB_RING_SIZE(ring) (sizeof((ring)) / sizeof(*(ring))) #define XENFB_RING_REF(ring, idx) (ring)[(idx) % XENFB_RING_SIZE((ring))] +#define XENFB_VIDEOMEM_SIZE (2 * 1024 * 1024) +#define XENFB_DIRTY_PAGES_SIZE ((((XENFB_VIDEOMEM_SIZE + 4096 - 1)/ 4096) + 7) / 8) + struct xenfb_page { __u8 initialized; @@ -90,6 +83,8 @@ struct xenfb_page union xenfb_in_event in[XENFB_IN_RING_SIZE]; union xenfb_out_event out[XENFB_OUT_RING_SIZE]; + + __u8 dirty_pages[XENFB_DIRTY_PAGES_SIZE]; }; void xenfb_resume(void); Index: vncfb/sdlfb.c =================================================================== --- vncfb.orig/sdlfb.c 2006-08-29 12:17:02.000000000 +0200 +++ vncfb/sdlfb.c 2006-08-29 14:16:33.000000000 +0200 @@ -7,13 +7,17 @@ typedef unsigned long kernel_ulong_t; #include <linux/input.h> #include "xenfb.h" +extern char *get_bitmap(struct xenfb *xenfb, int *size); + +#define IPS (30) + struct data { SDL_Surface *dst; SDL_Surface *src; }; -void sdl_update(struct xenfb *xenfb, int x, int y, int width, int height) +static void sdl_update(struct xenfb *xenfb, int x, int y, int width, int height) { struct data *data = xenfb->user_data; SDL_Rect r = { x, y, width, height }; @@ -21,6 +25,65 @@ void sdl_update(struct xenfb *xenfb, int SDL_UpdateRect(data->dst, x, y, width, height); } +static __inline__ int test_and_clear_bit(int nr, volatile void * addr) +{ + int oldbit; + __asm__ __volatile__( "lock ; " + "btrl %2,%1\n\tsbbl %0,%0" + :"=r" (oldbit),"+m" (*(volatile long *) addr) + :"Ir" (nr) : "memory"); + return oldbit; +} + +static void sdl_memory_udpate(struct xenfb *xenfb, int begin, int end) +{ + int y1, y2; + begin *= 4096; + end *= 4096; + + y1 = begin / xenfb->row_stride; + y2 = end / xenfb->row_stride; + + if (y1 != y2) + sdl_update(xenfb, 0, y1, xenfb->width, y2 - y1); + else { + int x1, x2; + x1 = (begin - y1 * xenfb->row_stride) / (xenfb->depth / 8); + x2 = (begin - y2 * xenfb->row_stride) / (xenfb->depth / 8); + sdl_update(xenfb, x1, y1, xenfb->width - x1, 1); + sdl_update(xenfb, x1, y1 + 1, x2 - x1 + 1, y2 - y1 - 1); + sdl_update(xenfb, 0, y2, x2 - 1, 1); + } +} + +static Uint32 refresh_handler(Uint32 interval, void *param) +{ +#define WSIZE (sizeof(unsigned long)*8) + struct xenfb * xenfb = param; + int size; + unsigned long *bitmap; + int i, j; + int begin = -1; + bitmap = (unsigned long*)get_bitmap(xenfb, &size); + for (i = 0; i < size / sizeof(unsigned long); i++) { + for (j = 0; j < WSIZE; j++) { + if (test_and_clear_bit(j, bitmap + i)) { + if (begin == -1) + begin = i * WSIZE + j; + } else if (begin != -1) { + sdl_memory_udpate(xenfb, + begin, + i * WSIZE + j); + begin = -1; + } + } + } + if (begin != -1) { + sdl_memory_udpate(xenfb, begin, size * WSIZE - 1); + } + return interval; +} + int sdl2linux[1024] = { [9] = KEY_ESC, [67] = KEY_F1, @@ -132,13 +195,11 @@ int sdl2linux[1024] = { int main(int argc, char **argv) { struct xenfb *xenfb; - int fd; int domid; - fd_set readfds; struct data data; SDL_Rect r; - struct timeval tv = { 0, 500 }; int do_quit = 0; + SDL_TimerID refreshTimer; if (argc != 2) @@ -153,12 +214,10 @@ int main(int argc, char **argv) if (!xenfb_set_domid(xenfb, domid)) return 1; - SDL_Init(SDL_INIT_VIDEO); - - fd = xenfb_get_fileno(xenfb); + SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER); data.dst = SDL_SetVideoMode(xenfb->width, xenfb->height, xenfb->depth, - SDL_SWSURFACE); + SDL_HWSURFACE); data.src = SDL_CreateRGBSurfaceFrom(xenfb->pixels, xenfb->width, xenfb->height, xenfb->depth, xenfb->row_stride, @@ -170,15 +229,12 @@ int main(int argc, char **argv) SDL_BlitSurface(data.src, &r, data.dst, &r); SDL_UpdateRect(data.dst, 0, 0, xenfb->width, xenfb->height); - xenfb->update = sdl_update; xenfb->user_data = &data; - FD_ZERO(&readfds); - FD_SET(fd, &readfds); - SDL_ShowCursor(0); - while (!do_quit && select(fd + 1, &readfds, NULL, NULL, &tv) != -1) { + refreshTimer = SDL_AddTimer(1000 / IPS, refresh_handler, xenfb); + while (!do_quit) { SDL_Event event; while (SDL_PollEvent(&event)) { @@ -207,15 +263,9 @@ int main(int argc, char **argv) break; } } - if (FD_ISSET(fd, &readfds)) - xenfb_on_incoming(xenfb); - - FD_ZERO(&readfds); - FD_SET(fd, &readfds); - - tv = (struct timeval){0, 500}; } + SDL_RemoveTimer(refreshTimer); xenfb_delete(xenfb); SDL_Quit(); Index: vncfb/vncfb.c =================================================================== --- vncfb.orig/vncfb.c 2006-08-28 18:20:00.000000000 +0200 +++ vncfb/vncfb.c 2006-08-29 14:45:52.000000000 +0200 @@ -1,7 +1,15 @@ +#include <signal.h> +#include <sys/time.h> #include <malloc.h> #include <rfb/rfb.h> #include "xenfb.h" +static struct xenfb *xenfb; + +extern char *get_bitmap(struct xenfb *xenfb, int *size); + +#define IPS (30) + static void on_kbd_event(rfbBool down, rfbKeySym keycode, rfbClientPtr cl) { extern uint32_t gdk_linux_mapping[0x10000]; @@ -23,7 +31,6 @@ static void on_ptr_event(int buttonMask, for (i = 0; i < 8; i++) { if ((last_button & (1 << i)) != (buttonMask & (1 << i))) { - printf("%d %d\n", buttonMask & (1 << i), i); xenfb_send_button(xenfb, buttonMask & (1 << i), 2 - i); } @@ -52,16 +59,72 @@ static void vnc_update(struct xenfb *xen rfbMarkRectAsModified(server, x, y, x + w, y + h); } +static __inline__ int test_and_clear_bit(int nr, volatile void * addr) +{ + int oldbit; + __asm__ __volatile__( "lock ; " + "btrl %2,%1\n\tsbbl %0,%0" + :"=r" (oldbit),"+m" (*(volatile long *) addr) + :"Ir" (nr) : "memory"); + return oldbit; +} + +static void vnc_memory_udpate(struct xenfb *xenfb, int begin, int end) +{ + int y1, y2; + begin *= 4096; + end *= 4096; + + y1 = begin / xenfb->row_stride; + y2 = end / xenfb->row_stride; + + if (y1 != y2) + vnc_update(xenfb, 0, y1, xenfb->width, y2 - y1); + else { + int x1, x2; + x1 = (begin - y1 * xenfb->row_stride) / (xenfb->depth / 8); + x2 = (begin - y2 * xenfb->row_stride) / (xenfb->depth / 8); + vnc_update(xenfb, x1, y1, xenfb->width - x1, 1); + vnc_update(xenfb, x1, y1 + 1, x2 - x1 + 1, y2 - y1 - 1); + vnc_update(xenfb, 0, y2, x2 - 1, 1); + } +} + +static void refresh_handler(int sig, siginfo_t *info, void* env) +{ +#define WSIZE (sizeof(unsigned long)*8) + int size; + unsigned long *bitmap; + int i, j; + int begin = -1; + bitmap = (unsigned long*)get_bitmap(xenfb, &size); + for (i = 0; i < size / sizeof(unsigned long); i++) { + for (j = 0; j < WSIZE; j++) { + if (test_and_clear_bit(j, bitmap + i)) { + if (begin == -1) + begin = i * WSIZE + j; + } else if (begin != -1) { + vnc_memory_udpate(xenfb, + begin, + i * WSIZE + j); + begin = -1; + } + } + } + if (begin != -1) { + vnc_memory_udpate(xenfb, begin, size * WSIZE - 1); + } +} + int main(int argc, char **argv) { rfbScreenInfoPtr server; char *fake_argv[3] = { "vncfb", "-rfbport", "5901" }; int fake_argc = sizeof(fake_argv) / sizeof(fake_argv[0]); int domid; - struct xenfb *xenfb; - fd_set readfds; - int fd; char buffer[1024]; + struct sigaction action; + struct itimerval timer; if (argc != 2) BUG(); @@ -85,7 +148,6 @@ int main(int argc, char **argv) BUG(); xenfb->user_data = server; - xenfb->update = vnc_update; server->serverFormat.redShift = 16; server->serverFormat.greenShift = 8; @@ -96,21 +158,20 @@ int main(int argc, char **argv) server->screenData = xenfb; rfbInitServer(server); - rfbRunEventLoop(server, -1, TRUE); - - fd = xenfb_get_fileno(xenfb); - FD_ZERO(&readfds); - FD_SET(fd, &readfds); + memset(&action, 0, sizeof(action)); + action.sa_sigaction = refresh_handler; + action.sa_flags = SA_RESTART; + sigemptyset(&action.sa_mask); + sigaction(SIGALRM, &action, NULL); + + timer.it_value.tv_sec = 0; + timer.it_value.tv_usec = 100000 / IPS; + timer.it_interval.tv_sec = timer.it_value.tv_sec; + timer.it_interval.tv_usec = timer.it_value.tv_usec; + setitimer(ITIMER_REAL, &timer, NULL); - while (select(fd + 1, &readfds, NULL, NULL, NULL) != -1) { - if (FD_ISSET(fd, &readfds)) { - xenfb_on_incoming(xenfb); - } - - FD_ZERO(&readfds); - FD_SET(fd, &readfds); - } + rfbRunEventLoop(server, 100000 / IPS, FALSE); rfbScreenCleanup(server); xenfb_delete(xenfb); Index: vncfb/xenfb.c =================================================================== --- vncfb.orig/xenfb.c 2006-08-29 12:17:02.000000000 +0200 +++ vncfb/xenfb.c 2006-08-29 14:42:41.000000000 +0200 @@ -69,15 +69,6 @@ struct xenfb *xenfb_new(void) return &xenfb->pub; } -int xenfb_get_fileno(struct xenfb *xenfb_pub) -{ - struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub; - if (xenfb->domid == -1) - return -1; - - return xenfb->fd; -} - static void xenfb_unset_domid(struct xenfb_private *xenfb) { struct ioctl_evtchn_unbind unbind; @@ -357,10 +348,10 @@ bool xenfb_set_domid(struct xenfb *xenfb return false; } -static void xenfb_update(struct xenfb_private *xenfb, int x, int y, int width, int height) +char *get_bitmap(struct xenfb_private *xenfb, int *size) { - if (xenfb->pub.update) - xenfb->pub.update(&xenfb->pub, x, y, width, height); + *size = XENFB_DIRTY_PAGES_SIZE; + return xenfb->fb_info->dirty_pages; } static void xenfb_on_fb_event(struct xenfb_private *xenfb) @@ -375,7 +366,6 @@ static void xenfb_on_fb_event(struct xen switch (event->type) { case XENFB_TYPE_UPDATE: - xenfb_update(xenfb, event->update.x, event->update.y, event->update.width, event->update.height); break; } } Index: vncfb/xenfb.h =================================================================== --- vncfb.orig/xenfb.h 2006-07-21 18:21:33.000000000 +0200 +++ vncfb/xenfb.h 2006-08-29 13:53:20.000000000 +0200 @@ -14,8 +14,6 @@ struct xenfb int height; void *user_data; - - void (*update)(struct xenfb *xenfb, int x, int y, int width, int height); }; struct xenfb *xenfb_new(void); -- Laurent.Vivier@xxxxxxxx Bull, Architect of an Open World (TM) +----- "Any sufficiently advanced technology is ----+ | indistinguishable from magic." - Arthur C. Clarke | Attachment:
signature.asc _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |