On 2 May 2015 at 20:15, Axel Davy <axel.d...@ens.fr> wrote: > Signed-off-by: Axel Davy <axel.d...@ens.fr>
I think I'd like to see the os-compatibility ported code be in a separate file, I wonder if any of it would be useful in other places, But even that isn't a major problem, Reviewed-by: Dave Airlie <airl...@redhat.com> > +static int > +dri2_wl_swrast_get_stride_for_format(int format, int w) > +{ > + if (format == WL_SHM_FORMAT_RGB565) > + return 2 * w; > + else /* ARGB8888 || XRGB8888 */ > + return 4 * w; > +} > + > +/* > + * Taken from weston shared/os-compatibility.c > + */ > + > +static int > +set_cloexec_or_close(int fd) > +{ > + long flags; > + > + if (fd == -1) > + return -1; > + > + flags = fcntl(fd, F_GETFD); > + if (flags == -1) > + goto err; > + > + if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) > + goto err; > + > + return fd; > + > +err: > + close(fd); > + return -1; > +} > + > +/* > + * Taken from weston shared/os-compatibility.c > + */ > + > +static int > +create_tmpfile_cloexec(char *tmpname) > +{ > + int fd; > + > +#ifdef HAVE_MKOSTEMP > + fd = mkostemp(tmpname, O_CLOEXEC); > + if (fd >= 0) > + unlink(tmpname); > +#else > + fd = mkstemp(tmpname); > + if (fd >= 0) { > + fd = set_cloexec_or_close(fd); > + unlink(tmpname); > + } > +#endif > + > + return fd; > +} > + > +/* > + * Taken from weston shared/os-compatibility.c > + * > + * Create a new, unique, anonymous file of the given size, and > + * return the file descriptor for it. The file descriptor is set > + * CLOEXEC. The file is immediately suitable for mmap()'ing > + * the given size at offset zero. > + * > + * The file should not have a permanent backing store like a disk, > + * but may have if XDG_RUNTIME_DIR is not properly implemented in OS. > + * > + * The file name is deleted from the file system. > + * > + * The file is suitable for buffer sharing between processes by > + * transmitting the file descriptor over Unix sockets using the > + * SCM_RIGHTS methods. > + * > + * If the C library implements posix_fallocate(), it is used to > + * guarantee that disk space is available for the file at the > + * given size. If disk space is insufficent, errno is set to ENOSPC. > + * If posix_fallocate() is not supported, program may receive > + * SIGBUS on accessing mmap()'ed file contents instead. > + */ > +static int > +os_create_anonymous_file(off_t size) > +{ > + static const char template[] = "/mesa-shared-XXXXXX"; > + const char *path; > + char *name; > + int fd; > + int ret; > + > + path = getenv("XDG_RUNTIME_DIR"); > + if (!path) { > + errno = ENOENT; > + return -1; > + } > + > + name = malloc(strlen(path) + sizeof(template)); > + if (!name) > + return -1; > + > + strcpy(name, path); > + strcat(name, template); > + > + fd = create_tmpfile_cloexec(name); > + > + free(name); > + > + if (fd < 0) > + return -1; > + > + ret = ftruncate(fd, size); > + if (ret < 0) { > + close(fd); > + return -1; > + } > + > + return fd; > +} > + > + > +static EGLBoolean > +dri2_wl_swrast_allocate_buffer(struct dri2_egl_display *dri2_dpy, > + int format, int w, int h, > + void **data, int *size, > + struct wl_buffer **buffer) > +{ > + struct wl_shm_pool *pool; > + int fd, stride, size_map; > + void *data_map; > + > + stride = dri2_wl_swrast_get_stride_for_format(format, w); > + size_map = h * stride; > + > + /* Create a sharable buffer */ > + fd = os_create_anonymous_file(size_map); > + if (fd < 0) > + return EGL_FALSE; > + > + data_map = mmap(NULL, size_map, PROT_READ | PROT_WRITE, MAP_SHARED, fd, > 0); > + if (data_map == MAP_FAILED) { > + close(fd); > + return EGL_FALSE; > + } > + > + /* Share it in a wl_buffer */ > + pool = wl_shm_create_pool(dri2_dpy->wl_shm, fd, size_map); > + *buffer = wl_shm_pool_create_buffer(pool, 0, w, h, stride, format); > + wl_shm_pool_destroy(pool); > + close(fd); > + > + *data = data_map; > + *size = size_map; > + return EGL_TRUE; > +} > + > +static int > +swrast_update_buffers(struct dri2_egl_surface *dri2_surf) > +{ > + struct dri2_egl_display *dri2_dpy = > + dri2_egl_display(dri2_surf->base.Resource.Display); > + int i; > + > + /* we need to do the following operations only once per frame */ > + if (dri2_surf->back) > + return 0; > + > + if (dri2_surf->base.Width != dri2_surf->wl_win->width || > + dri2_surf->base.Height != dri2_surf->wl_win->height) { > + > + dri2_wl_release_buffers(dri2_surf); > + > + dri2_surf->base.Width = dri2_surf->wl_win->width; > + dri2_surf->base.Height = dri2_surf->wl_win->height; > + dri2_surf->dx = dri2_surf->wl_win->dx; > + dri2_surf->dy = dri2_surf->wl_win->dy; > + dri2_surf->current = NULL; > + } > + > + /* find back buffer */ > + > + /* We always want to throttle to some event (either a frame callback or > + * a sync request) after the commit so that we can be sure the > + * compositor has had a chance to handle it and send us a release event > + * before we look for a free buffer */ > + while (dri2_surf->throttle_callback != NULL) > + if (wl_display_dispatch_queue(dri2_dpy->wl_dpy, > + dri2_dpy->wl_queue) == -1) > + return -1; > + > + /* try get free buffer already created */ > + for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) { > + if (!dri2_surf->color_buffers[i].locked && > + dri2_surf->color_buffers[i].wl_buffer) { > + dri2_surf->back = &dri2_surf->color_buffers[i]; > + break; > + } > + } > + > + /* else choose any another free location */ > + if (!dri2_surf->back) { > + for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) { > + if (!dri2_surf->color_buffers[i].locked) { > + dri2_surf->back = &dri2_surf->color_buffers[i]; > + if (!dri2_wl_swrast_allocate_buffer(dri2_dpy, > + dri2_surf->format, > + dri2_surf->base.Width, > + dri2_surf->base.Height, > + &dri2_surf->back->data, > + &dri2_surf->back->data_size, > + > &dri2_surf->back->wl_buffer)) { > + _eglError(EGL_BAD_ALLOC, "failed to allocate color buffer"); > + return -1; > + } > + wl_proxy_set_queue((struct wl_proxy *) > dri2_surf->back->wl_buffer, > + dri2_dpy->wl_queue); > + wl_buffer_add_listener(dri2_surf->back->wl_buffer, > + &wl_buffer_listener, dri2_surf); > + break; > + } > + } > + } > + > + if (!dri2_surf->back) { > + _eglError(EGL_BAD_ALLOC, "failed to find free buffer"); > + return -1; > + } > + > + dri2_surf->back->locked = 1; > + > + /* If we have an extra unlocked buffer at this point, we had to do triple > + * buffering for a while, but now can go back to just double buffering. > + * That means we can free any unlocked buffer now. */ > + for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) { > + if (!dri2_surf->color_buffers[i].locked && > + dri2_surf->color_buffers[i].wl_buffer) { > + wl_buffer_destroy(dri2_surf->color_buffers[i].wl_buffer); > + munmap(dri2_surf->color_buffers[i].data, > + dri2_surf->color_buffers[i].data_size); > + dri2_surf->color_buffers[i].wl_buffer = NULL; > + dri2_surf->color_buffers[i].data = NULL; > + } > + } > + > + return 0; > +} > + > +static void* > +dri2_wl_swrast_get_frontbuffer_data(struct dri2_egl_surface *dri2_surf) > +{ > + /* if there has been a resize: */ > + if (!dri2_surf->current) > + return NULL; > + > + return dri2_surf->current->data; > +} > + > +static void* > +dri2_wl_swrast_get_backbuffer_data(struct dri2_egl_surface *dri2_surf) > +{ > + assert(dri2_surf->back); > + return dri2_surf->back->data; > +} > + > +static void > +dri2_wl_swrast_commit_backbuffer(struct dri2_egl_surface *dri2_surf) > +{ > + struct dri2_egl_display *dri2_dpy = > dri2_egl_display(dri2_surf->base.Resource.Display); > + > + if (dri2_surf->base.SwapInterval > 0) { > + dri2_surf->throttle_callback = > + wl_surface_frame(dri2_surf->wl_win->surface); > + wl_callback_add_listener(dri2_surf->throttle_callback, > + &throttle_listener, dri2_surf); > + wl_proxy_set_queue((struct wl_proxy *) dri2_surf->throttle_callback, > + dri2_dpy->wl_queue); > + } > + > + dri2_surf->current = dri2_surf->back; > + dri2_surf->back = NULL; > + > + wl_surface_attach(dri2_surf->wl_win->surface, > + dri2_surf->current->wl_buffer, > + dri2_surf->dx, dri2_surf->dy); > + > + dri2_surf->wl_win->attached_width = dri2_surf->base.Width; > + dri2_surf->wl_win->attached_height = dri2_surf->base.Height; > + /* reset resize growing parameters */ > + dri2_surf->dx = 0; > + dri2_surf->dy = 0; > + > + wl_surface_damage(dri2_surf->wl_win->surface, > + 0, 0, INT32_MAX, INT32_MAX); > + wl_surface_commit(dri2_surf->wl_win->surface); > + > + /* If we're not waiting for a frame callback then we'll at least throttle > + * to a sync callback so that we always give a chance for the compositor > to > + * handle the commit and send a release event before checking for a free > + * buffer */ > + if (dri2_surf->throttle_callback == NULL) { > + dri2_surf->throttle_callback = wl_display_sync(dri2_dpy->wl_dpy); > + wl_callback_add_listener(dri2_surf->throttle_callback, > + &throttle_listener, dri2_surf); > + wl_proxy_set_queue((struct wl_proxy *) dri2_surf->throttle_callback, > + dri2_dpy->wl_queue); > + } > + > + wl_display_flush(dri2_dpy->wl_dpy); > +} > + > +static void > +dri2_wl_swrast_get_drawable_info(__DRIdrawable * draw, > + int *x, int *y, int *w, int *h, > + void *loaderPrivate) > +{ > + struct dri2_egl_surface *dri2_surf = loaderPrivate; > + > + (void) swrast_update_buffers(dri2_surf); > + *x = 0; > + *y = 0; > + *w = dri2_surf->base.Width; > + *h = dri2_surf->base.Height; > +} > + > +static void > +dri2_wl_swrast_get_image(__DRIdrawable * read, > + int x, int y, int w, int h, > + char *data, void *loaderPrivate) > +{ > + struct dri2_egl_surface *dri2_surf = loaderPrivate; > + int copy_width = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, > w); > + int x_offset = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, x); > + int src_stride = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, > dri2_surf->base.Width); > + int dst_stride = copy_width; > + char *src, *dst; > + > + src = dri2_wl_swrast_get_frontbuffer_data(dri2_surf); > + if (!src) { > + memset(data, 0, copy_width * h); > + return; > + } > + > + assert(data != src); > + assert(copy_width <= src_stride); > + > + src += x_offset; > + src += y * src_stride; > + dst = data; > + > + if (copy_width > src_stride-x_offset) > + copy_width = src_stride-x_offset; > + if (h > dri2_surf->base.Height-y) > + h = dri2_surf->base.Height-y; > + > + for (; h>0; h--) { > + memcpy(dst, src, copy_width); > + src += src_stride; > + dst += dst_stride; > + } > +} > + > +static void > +dri2_wl_swrast_put_image2(__DRIdrawable * draw, int op, > + int x, int y, int w, int h, int stride, > + char *data, void *loaderPrivate) > +{ > + struct dri2_egl_surface *dri2_surf = loaderPrivate; > + int copy_width = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, > w); > + int dst_stride = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, > dri2_surf->base.Width); > + int x_offset = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, x); > + char *src, *dst; > + > + assert(copy_width <= stride); > + > + (void) swrast_update_buffers(dri2_surf); > + dst = dri2_wl_swrast_get_backbuffer_data(dri2_surf); > + > + /* partial copy, copy old content */ > + if (copy_width < dst_stride) > + dri2_wl_swrast_get_image(draw, 0, 0, > + dri2_surf->base.Width, dri2_surf->base.Height, > + dst, loaderPrivate); > + > + dst += x_offset; > + dst += y * dst_stride; > + > + src = data; > + > + /* drivers expect we do these checks (and some rely on it) */ > + if (copy_width > dst_stride-x_offset) > + copy_width = dst_stride-x_offset; > + if (h > dri2_surf->base.Height-y) > + h = dri2_surf->base.Height-y; > + > + for (; h>0; h--) { > + memcpy(dst, src, copy_width); > + src += stride; > + dst += dst_stride; > + } > + dri2_wl_swrast_commit_backbuffer(dri2_surf); > +} > + > +static void > +dri2_wl_swrast_put_image(__DRIdrawable * draw, int op, > + int x, int y, int w, int h, > + char *data, void *loaderPrivate) > +{ > + struct dri2_egl_surface *dri2_surf = loaderPrivate; > + int stride; > + > + stride = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, w); > + dri2_wl_swrast_put_image2(draw, op, x, y, w, h, > + stride, data, loaderPrivate); > +} > + > +/** > + * Called via eglCreateWindowSurface(), drv->API.CreateWindowSurface(). > + */ > +static _EGLSurface * > +dri2_wl_swrast_create_window_surface(_EGLDriver *drv, _EGLDisplay *disp, > + _EGLConfig *conf, void *native_window, > + const EGLint *attrib_list) > +{ > + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); > + struct dri2_egl_config *dri2_conf = dri2_egl_config(conf); > + struct wl_egl_window *window = native_window; > + struct dri2_egl_surface *dri2_surf; > + > + (void) drv; > + > + dri2_surf = calloc(1, sizeof *dri2_surf); > + if (!dri2_surf) { > + _eglError(EGL_BAD_ALLOC, "dri2_create_surface"); > + return NULL; > + } > + > + if (!_eglInitSurface(&dri2_surf->base, disp, EGL_WINDOW_BIT, conf, > attrib_list)) > + goto cleanup_surf; > + > + if (conf->RedSize == 5) > + dri2_surf->format = WL_SHM_FORMAT_RGB565; > + else if (conf->AlphaSize == 0) > + dri2_surf->format = WL_SHM_FORMAT_XRGB8888; > + else > + dri2_surf->format = WL_SHM_FORMAT_ARGB8888; > + > + dri2_surf->wl_win = window; > + > + dri2_surf->base.Width = -1; > + dri2_surf->base.Height = -1; > + > + dri2_surf->dri_drawable = > + (*dri2_dpy->swrast->createNewDrawable) (dri2_dpy->dri_screen, > + dri2_conf->dri_double_config, > + dri2_surf); > + if (dri2_surf->dri_drawable == NULL) { > + _eglError(EGL_BAD_ALLOC, "swrast->createNewDrawable"); > + goto cleanup_dri_drawable; > + } > + > + dri2_wl_swap_interval(drv, disp, &dri2_surf->base, > + dri2_dpy->default_swap_interval); > + > + return &dri2_surf->base; > + > + cleanup_dri_drawable: > + dri2_dpy->core->destroyDrawable(dri2_surf->dri_drawable); > + cleanup_surf: > + free(dri2_surf); > + > + return NULL; > +} > + > +static EGLBoolean > +dri2_wl_swrast_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface > *draw) > +{ > + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); > + struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw); > + > + dri2_dpy->core->swapBuffers(dri2_surf->dri_drawable); > + return EGL_TRUE; > +} > + > +static void > +shm_handle_format(void *data, struct wl_shm *shm, uint32_t format) > +{ > + struct dri2_egl_display *dri2_dpy = data; > + > + switch (format) { > + case WL_SHM_FORMAT_ARGB8888: > + dri2_dpy->formats |= HAS_ARGB8888; > + break; > + case WL_SHM_FORMAT_XRGB8888: > + dri2_dpy->formats |= HAS_XRGB8888; > + break; > + case WL_SHM_FORMAT_RGB565: > + dri2_dpy->formats |= HAS_RGB565; > + break; > + } > +} > + > +static const struct wl_shm_listener shm_listener = { > + shm_handle_format > +}; > + > +static void > +registry_handle_global_swrast(void *data, struct wl_registry *registry, > uint32_t name, > + const char *interface, uint32_t version) > +{ > + struct dri2_egl_display *dri2_dpy = data; > + > + if (strcmp(interface, "wl_shm") == 0) { > + dri2_dpy->wl_shm = > + wl_registry_bind(registry, name, &wl_shm_interface, 1); > + wl_shm_add_listener(dri2_dpy->wl_shm, &shm_listener, dri2_dpy); > + } > +} > + > +static const struct wl_registry_listener registry_listener_swrast = { > + registry_handle_global_swrast, > + registry_handle_global_remove > +}; > + > +static struct dri2_egl_display_vtbl dri2_wl_swrast_display_vtbl = { > + .authenticate = NULL, > + .create_window_surface = dri2_wl_swrast_create_window_surface, > + .create_pixmap_surface = dri2_wl_create_pixmap_surface, > + .create_pbuffer_surface = dri2_fallback_create_pbuffer_surface, > + .destroy_surface = dri2_wl_destroy_surface, > + .create_image = dri2_fallback_create_image_khr, > + .swap_interval = dri2_wl_swap_interval, > + .swap_buffers = dri2_wl_swrast_swap_buffers, > + .swap_buffers_with_damage = dri2_fallback_swap_buffers_with_damage, > + .swap_buffers_region = dri2_fallback_swap_buffers_region, > + .post_sub_buffer = dri2_fallback_post_sub_buffer, > + .copy_buffers = dri2_fallback_copy_buffers, > + .query_buffer_age = dri2_fallback_query_buffer_age, > + .create_wayland_buffer_from_image = > dri2_fallback_create_wayland_buffer_from_image, > + .get_sync_values = dri2_fallback_get_sync_values, > +}; > + > +static EGLBoolean > +dri2_initialize_wayland_swrast(_EGLDriver *drv, _EGLDisplay *disp) > +{ > + struct dri2_egl_display *dri2_dpy; > + const __DRIconfig *config; > + uint32_t types; > + int i; > + static const unsigned int argb_masks[4] = > + { 0xff0000, 0xff00, 0xff, 0xff000000 }; > + static const unsigned int rgb_masks[4] = { 0xff0000, 0xff00, 0xff, 0 }; > + static const unsigned int rgb565_masks[4] = { 0xf800, 0x07e0, 0x001f, 0 }; > + > + loader_set_logger(_eglLog); > + > + dri2_dpy = calloc(1, sizeof *dri2_dpy); > + if (!dri2_dpy) > + return _eglError(EGL_BAD_ALLOC, "eglInitialize"); > + > + disp->DriverData = (void *) dri2_dpy; > + if (disp->PlatformDisplay == NULL) { > + dri2_dpy->wl_dpy = wl_display_connect(NULL); > + if (dri2_dpy->wl_dpy == NULL) > + goto cleanup_dpy; > + dri2_dpy->own_device = 1; > + } else { > + dri2_dpy->wl_dpy = disp->PlatformDisplay; > + } > + > + dri2_dpy->wl_queue = wl_display_create_queue(dri2_dpy->wl_dpy); > + > + if (dri2_dpy->own_device) > + wl_display_dispatch_pending(dri2_dpy->wl_dpy); > + > + dri2_dpy->wl_registry = wl_display_get_registry(dri2_dpy->wl_dpy); > + wl_proxy_set_queue((struct wl_proxy *) dri2_dpy->wl_registry, > + dri2_dpy->wl_queue); > + wl_registry_add_listener(dri2_dpy->wl_registry, > + ®istry_listener_swrast, dri2_dpy); > + > + if (roundtrip(dri2_dpy) < 0 || dri2_dpy->wl_shm == NULL) > + goto cleanup_registry; > + > + if (roundtrip(dri2_dpy) < 0 || dri2_dpy->formats == 0) > + goto cleanup_shm; > + > + dri2_dpy->driver_name = strdup("swrast"); > + if (!dri2_load_driver_swrast(disp)) > + goto cleanup_shm; > + > + dri2_dpy->swrast_loader_extension.base.name = __DRI_SWRAST_LOADER; > + dri2_dpy->swrast_loader_extension.base.version = 2; > + dri2_dpy->swrast_loader_extension.getDrawableInfo = > dri2_wl_swrast_get_drawable_info; > + dri2_dpy->swrast_loader_extension.putImage = dri2_wl_swrast_put_image; > + dri2_dpy->swrast_loader_extension.getImage = dri2_wl_swrast_get_image; > + dri2_dpy->swrast_loader_extension.putImage2 = dri2_wl_swrast_put_image2; > + > + dri2_dpy->extensions[0] = &dri2_dpy->swrast_loader_extension.base; > + dri2_dpy->extensions[1] = NULL; > + > + if (!dri2_create_screen(disp)) > + goto cleanup_driver; > + > + dri2_wl_setup_swap_interval(dri2_dpy); > + > + types = EGL_WINDOW_BIT; > + for (i = 0; dri2_dpy->driver_configs[i]; i++) { > + config = dri2_dpy->driver_configs[i]; > + if (dri2_dpy->formats & HAS_XRGB8888) > + dri2_add_config(disp, config, i + 1, types, NULL, rgb_masks); > + if (dri2_dpy->formats & HAS_ARGB8888) > + dri2_add_config(disp, config, i + 1, types, NULL, argb_masks); > + if (dri2_dpy->formats & HAS_RGB565) > + dri2_add_config(disp, config, i + 1, types, NULL, rgb565_masks); > + } > + > + /* we're supporting EGL 1.4 */ > + disp->VersionMajor = 1; > + disp->VersionMinor = 4; > + > + /* Fill vtbl last to prevent accidentally calling virtual function during > + * initialization. > + */ > + dri2_dpy->vtbl = &dri2_wl_swrast_display_vtbl; > + > + return EGL_TRUE; > + > + cleanup_driver: > + dlclose(dri2_dpy->driver); > + cleanup_shm: > + wl_shm_destroy(dri2_dpy->wl_shm); > + cleanup_registry: > + wl_registry_destroy(dri2_dpy->wl_registry); > + wl_event_queue_destroy(dri2_dpy->wl_queue); > + cleanup_dpy: > + free(dri2_dpy); > + > + return EGL_FALSE; > +} > + > +EGLBoolean > +dri2_initialize_wayland(_EGLDriver *drv, _EGLDisplay *disp) > +{ > + EGLBoolean initialized = EGL_TRUE; > + > + int hw_accel = (getenv("LIBGL_ALWAYS_SOFTWARE") == NULL); > + > + if (hw_accel) { > + if (!dri2_initialize_wayland_drm(drv, disp)) { > + initialized = dri2_initialize_wayland_swrast(drv, disp); > + } > + } else { > + initialized = dri2_initialize_wayland_swrast(drv, disp); > + } > + > + return initialized; > + > +} > -- > 2.3.7 > > _______________________________________________ > mesa-dev mailing list > mesa-dev@lists.freedesktop.org > http://lists.freedesktop.org/mailman/listinfo/mesa-dev _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev