X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Floader%2Floader_dri3_helper.c;h=2e1603c3fe22afa114bf13ee5bef7213e407a756;hb=e9add0c501c3765cae43ef60ec58404c2340991b;hp=6db8303d26df595647045d2a7912341094e9ca73;hpb=6f81e07ecb8c0793dc482307d5d96fd3df95b7d2;p=mesa.git diff --git a/src/loader/loader_dri3_helper.c b/src/loader/loader_dri3_helper.c index 6db8303d26d..2e1603c3fe2 100644 --- a/src/loader/loader_dri3_helper.c +++ b/src/loader/loader_dri3_helper.c @@ -35,7 +35,7 @@ #include "loader_dri3_helper.h" #include "util/macros.h" -#include "drm_fourcc.h" +#include "drm-uapi/drm_fourcc.h" /* From xmlpool/options.h, user exposed so should be stable */ #define DRI_CONF_VBLANK_NEVER 0 @@ -64,6 +64,81 @@ dri3_flush_present_events(struct loader_dri3_drawable *draw); static struct loader_dri3_buffer * dri3_find_back_alloc(struct loader_dri3_drawable *draw); +static xcb_screen_t * +get_screen_for_root(xcb_connection_t *conn, xcb_window_t root) +{ + xcb_screen_iterator_t screen_iter = + xcb_setup_roots_iterator(xcb_get_setup(conn)); + + for (; screen_iter.rem; xcb_screen_next (&screen_iter)) { + if (screen_iter.data->root == root) + return screen_iter.data; + } + + return NULL; +} + +static xcb_visualtype_t * +get_xcb_visualtype_for_depth(struct loader_dri3_drawable *draw, int depth) +{ + xcb_visualtype_iterator_t visual_iter; + xcb_screen_t *screen = draw->screen; + xcb_depth_iterator_t depth_iter; + + if (!screen) + return NULL; + + depth_iter = xcb_screen_allowed_depths_iterator(screen); + for (; depth_iter.rem; xcb_depth_next(&depth_iter)) { + if (depth_iter.data->depth != depth) + continue; + + visual_iter = xcb_depth_visuals_iterator(depth_iter.data); + if (visual_iter.rem) + return visual_iter.data; + } + + return NULL; +} + +/* Sets the adaptive sync window property state. */ +static void +set_adaptive_sync_property(xcb_connection_t *conn, xcb_drawable_t drawable, + uint32_t state) +{ + static char const name[] = "_VARIABLE_REFRESH"; + xcb_intern_atom_cookie_t cookie; + xcb_intern_atom_reply_t* reply; + xcb_void_cookie_t check; + + cookie = xcb_intern_atom(conn, 0, strlen(name), name); + reply = xcb_intern_atom_reply(conn, cookie, NULL); + if (reply == NULL) + return; + + if (state) + check = xcb_change_property_checked(conn, XCB_PROP_MODE_REPLACE, + drawable, reply->atom, + XCB_ATOM_CARDINAL, 32, 1, &state); + else + check = xcb_delete_property_checked(conn, drawable, reply->atom); + + xcb_discard_reply(conn, check.sequence); + free(reply); +} + +/* Get red channel mask for given drawable at given depth. */ +static unsigned int +dri3_get_red_mask_for_depth(struct loader_dri3_drawable *draw, int depth) +{ + xcb_visualtype_t *visual = get_xcb_visualtype_for_depth(draw, depth); + + if (visual) + return visual->red_mask; + + return 0; +} + /** * Do we have blit functionality in the image blit extension? * @@ -282,16 +357,30 @@ loader_dri3_drawable_init(xcb_connection_t *conn, draw->have_back = 0; draw->have_fake_front = 0; draw->first_init = true; + draw->adaptive_sync = false; + draw->adaptive_sync_active = false; draw->cur_blit_source = -1; draw->back_format = __DRI_IMAGE_FORMAT_NONE; mtx_init(&draw->mtx, mtx_plain); cnd_init(&draw->event_cnd); - if (draw->ext->config) + if (draw->ext->config) { + unsigned char adaptive_sync = 0; + draw->ext->config->configQueryi(draw->dri_screen, "vblank_mode", &vblank_mode); + draw->ext->config->configQueryb(draw->dri_screen, + "adaptive_sync", + &adaptive_sync); + + draw->adaptive_sync = adaptive_sync; + } + + if (!draw->adaptive_sync) + set_adaptive_sync_property(conn, draw->drawable, false); + switch (vblank_mode) { case DRI_CONF_VBLANK_NEVER: case DRI_CONF_VBLANK_DEF_INTERVAL_0: @@ -323,6 +412,7 @@ loader_dri3_drawable_init(xcb_connection_t *conn, return 1; } + draw->screen = get_screen_for_root(draw->conn, reply->root); draw->width = reply->width; draw->height = reply->height; draw->depth = reply->depth; @@ -370,9 +460,17 @@ dri3_handle_present_event(struct loader_dri3_drawable *draw, * checking for wrap. */ if (ce->kind == XCB_PRESENT_COMPLETE_KIND_PIXMAP) { - draw->recv_sbc = (draw->send_sbc & 0xffffffff00000000LL) | ce->serial; - if (draw->recv_sbc > draw->send_sbc) - draw->recv_sbc -= 0x100000000; + uint64_t recv_sbc = (draw->send_sbc & 0xffffffff00000000LL) | ce->serial; + + /* Only assume wraparound if that results in exactly the previous + * SBC + 1, otherwise ignore received SBC > sent SBC (those are + * probably from a previous loader_dri3_drawable instance) to avoid + * calculating bogus target MSC values in loader_dri3_swap_buffers_msc + */ + if (recv_sbc <= draw->send_sbc) + draw->recv_sbc = recv_sbc; + else if (recv_sbc == (draw->recv_sbc + 0x100000001ULL)) + draw->recv_sbc = recv_sbc - 0x100000000ULL; /* When moving from flip to copy, we assume that we can allocate in * a more optimal way if we don't need to cater for the display @@ -386,7 +484,7 @@ dri3_handle_present_event(struct loader_dri3_drawable *draw, } } - /* If the server tells us that our allocation is suboptimal, we + /* If the server tells us that our allocation is suboptimal, we * reallocate once. */ #ifdef HAVE_DRI3_MODIFIERS @@ -665,7 +763,7 @@ loader_dri3_copy_sub_buffer(struct loader_dri3_drawable *draw, if (flush) flags |= __DRI2_FLUSH_CONTEXT; - loader_dri3_flush(draw, flags, __DRI2_THROTTLE_SWAPBUFFER); + loader_dri3_flush(draw, flags, __DRI2_THROTTLE_COPYSUBBUFFER); back = dri3_find_back_alloc(draw); if (!back) @@ -719,7 +817,7 @@ loader_dri3_copy_drawable(struct loader_dri3_drawable *draw, xcb_drawable_t dest, xcb_drawable_t src) { - loader_dri3_flush(draw, __DRI2_FLUSH_DRAWABLE, 0); + loader_dri3_flush(draw, __DRI2_FLUSH_DRAWABLE, __DRI2_THROTTLE_COPYSUBBUFFER); dri3_fence_reset(draw->conn, dri3_fake_front_buffer(draw)); dri3_copy_area(draw->conn, @@ -821,6 +919,12 @@ loader_dri3_swap_buffers_msc(struct loader_dri3_drawable *draw, back = dri3_find_back_alloc(draw); mtx_lock(&draw->mtx); + + if (draw->adaptive_sync && !draw->adaptive_sync_active) { + set_adaptive_sync_property(draw->conn, draw->drawable, true); + draw->adaptive_sync_active = true; + } + if (draw->is_different_gpu && back) { /* Update the linear buffer before presenting the pixmap */ (void) loader_dri3_blit_image(draw, @@ -1015,35 +1119,72 @@ dri3_cpp_for_format(uint32_t format) { case __DRI_IMAGE_FORMAT_ABGR2101010: case __DRI_IMAGE_FORMAT_SARGB8: case __DRI_IMAGE_FORMAT_SABGR8: + case __DRI_IMAGE_FORMAT_SXRGB8: return 4; + case __DRI_IMAGE_FORMAT_XBGR16161616F: + case __DRI_IMAGE_FORMAT_ABGR16161616F: + return 8; case __DRI_IMAGE_FORMAT_NONE: default: return 0; } } +/* Map format of render buffer to corresponding format for the linear_buffer + * used for sharing with the display gpu of a Prime setup (== is_different_gpu). + * Usually linear_format == format, except for depth >= 30 formats, where + * different gpu vendors have different preferences wrt. color channel ordering. + */ +static uint32_t +dri3_linear_format_for_format(struct loader_dri3_drawable *draw, uint32_t format) +{ + switch (format) { + case __DRI_IMAGE_FORMAT_XRGB2101010: + case __DRI_IMAGE_FORMAT_XBGR2101010: + /* Different preferred formats for different hw */ + if (dri3_get_red_mask_for_depth(draw, 30) == 0x3ff) + return __DRI_IMAGE_FORMAT_XBGR2101010; + else + return __DRI_IMAGE_FORMAT_XRGB2101010; + + case __DRI_IMAGE_FORMAT_ARGB2101010: + case __DRI_IMAGE_FORMAT_ABGR2101010: + /* Different preferred formats for different hw */ + if (dri3_get_red_mask_for_depth(draw, 30) == 0x3ff) + return __DRI_IMAGE_FORMAT_ABGR2101010; + else + return __DRI_IMAGE_FORMAT_ARGB2101010; + + default: + return format; + } +} + /* the DRIimage createImage function takes __DRI_IMAGE_FORMAT codes, while - * the createImageFromFds call takes __DRI_IMAGE_FOURCC codes. To avoid + * the createImageFromFds call takes DRM_FORMAT codes. To avoid * complete confusion, just deal in __DRI_IMAGE_FORMAT codes for now and - * translate to __DRI_IMAGE_FOURCC codes in the call to createImageFromFds + * translate to DRM_FORMAT codes in the call to createImageFromFds */ static int image_format_to_fourcc(int format) { - /* Convert from __DRI_IMAGE_FORMAT to __DRI_IMAGE_FOURCC (sigh) */ + /* Convert from __DRI_IMAGE_FORMAT to DRM_FORMAT (sigh) */ switch (format) { case __DRI_IMAGE_FORMAT_SARGB8: return __DRI_IMAGE_FOURCC_SARGB8888; case __DRI_IMAGE_FORMAT_SABGR8: return __DRI_IMAGE_FOURCC_SABGR8888; - case __DRI_IMAGE_FORMAT_RGB565: return __DRI_IMAGE_FOURCC_RGB565; - case __DRI_IMAGE_FORMAT_XRGB8888: return __DRI_IMAGE_FOURCC_XRGB8888; - case __DRI_IMAGE_FORMAT_ARGB8888: return __DRI_IMAGE_FOURCC_ARGB8888; - case __DRI_IMAGE_FORMAT_ABGR8888: return __DRI_IMAGE_FOURCC_ABGR8888; - case __DRI_IMAGE_FORMAT_XBGR8888: return __DRI_IMAGE_FOURCC_XBGR8888; - case __DRI_IMAGE_FORMAT_XRGB2101010: return __DRI_IMAGE_FOURCC_XRGB2101010; - case __DRI_IMAGE_FORMAT_ARGB2101010: return __DRI_IMAGE_FOURCC_ARGB2101010; - case __DRI_IMAGE_FORMAT_XBGR2101010: return __DRI_IMAGE_FOURCC_XBGR2101010; - case __DRI_IMAGE_FORMAT_ABGR2101010: return __DRI_IMAGE_FOURCC_ABGR2101010; + case __DRI_IMAGE_FORMAT_SXRGB8: return __DRI_IMAGE_FOURCC_SXRGB8888; + case __DRI_IMAGE_FORMAT_RGB565: return DRM_FORMAT_RGB565; + case __DRI_IMAGE_FORMAT_XRGB8888: return DRM_FORMAT_XRGB8888; + case __DRI_IMAGE_FORMAT_ARGB8888: return DRM_FORMAT_ARGB8888; + case __DRI_IMAGE_FORMAT_ABGR8888: return DRM_FORMAT_ABGR8888; + case __DRI_IMAGE_FORMAT_XBGR8888: return DRM_FORMAT_XBGR8888; + case __DRI_IMAGE_FORMAT_XRGB2101010: return DRM_FORMAT_XRGB2101010; + case __DRI_IMAGE_FORMAT_ARGB2101010: return DRM_FORMAT_ARGB2101010; + case __DRI_IMAGE_FORMAT_XBGR2101010: return DRM_FORMAT_XBGR2101010; + case __DRI_IMAGE_FORMAT_ABGR2101010: return DRM_FORMAT_ABGR2101010; + case __DRI_IMAGE_FORMAT_XBGR16161616F: return DRM_FORMAT_XBGR16161616F; + case __DRI_IMAGE_FORMAT_ABGR16161616F: return DRM_FORMAT_ABGR16161616F; } return 0; } @@ -1141,7 +1282,7 @@ dri3_alloc_render_buffer(struct loader_dri3_drawable *draw, unsigned int format, uint32_t count = 0; mod_cookie = xcb_dri3_get_supported_modifiers(draw->conn, - draw->drawable, + draw->window, depth, buffer->cpp * 8); mod_reply = xcb_dri3_get_supported_modifiers_reply(draw->conn, mod_cookie, @@ -1185,12 +1326,20 @@ dri3_alloc_render_buffer(struct loader_dri3_drawable *draw, unsigned int format, free(mod_reply); - buffer->image = draw->ext->image->createImageWithModifiers(draw->dri_screen, - width, height, - format, - modifiers, - count, - buffer); + /* don't use createImageWithModifiers() if we have no + * modifiers, other things depend on the use flags when + * there are no modifiers to know that a buffer can be + * shared. + */ + if (modifiers) { + buffer->image = draw->ext->image->createImageWithModifiers(draw->dri_screen, + width, height, + format, + modifiers, + count, + buffer); + } + free(modifiers); } #endif @@ -1219,7 +1368,8 @@ dri3_alloc_render_buffer(struct loader_dri3_drawable *draw, unsigned int format, buffer->linear_buffer = draw->ext->image->createImage(draw->dri_screen, - width, height, format, + width, height, + dri3_linear_format_for_format(draw, format), __DRI_IMAGE_USE_SHARE | __DRI_IMAGE_USE_LINEAR | __DRI_IMAGE_USE_BACKBUFFER, @@ -1244,6 +1394,8 @@ dri3_alloc_render_buffer(struct loader_dri3_drawable *draw, unsigned int format, image = pixmap_buffer; } + buffer_fds[i] = -1; + ret = draw->ext->image->queryImage(image, __DRI_IMAGE_ATTRIB_FD, &buffer_fds[i]); ret &= draw->ext->image->queryImage(image, __DRI_IMAGE_ATTRIB_STRIDE, @@ -1273,7 +1425,7 @@ dri3_alloc_render_buffer(struct loader_dri3_drawable *draw, unsigned int format, buffer->modifier != DRM_FORMAT_MOD_INVALID) { xcb_dri3_pixmap_from_buffers(draw->conn, pixmap, - draw->drawable, + draw->window, num_planes, width, height, buffer->strides[0], buffer->offsets[0], @@ -1316,7 +1468,8 @@ dri3_alloc_render_buffer(struct loader_dri3_drawable *draw, unsigned int format, no_buffer_attrib: do { - close(buffer_fds[i]); + if (buffer_fds[i] != -1) + close(buffer_fds[i]); } while (--i >= 0); draw->ext->image->destroyImage(pixmap_buffer); no_linear_buffer: @@ -1338,8 +1491,7 @@ no_shm_fence: * track the geometry of the drawable */ static int -dri3_update_drawable(__DRIdrawable *driDrawable, - struct loader_dri3_drawable *draw) +dri3_update_drawable(struct loader_dri3_drawable *draw) { mtx_lock(&draw->mtx); if (draw->first_init) { @@ -1349,6 +1501,7 @@ dri3_update_drawable(__DRIdrawable *driDrawable, xcb_generic_error_t *error; xcb_present_query_capabilities_cookie_t present_capabilities_cookie; xcb_present_query_capabilities_reply_t *present_capabilities_reply; + xcb_window_t root_win; draw->first_init = false; @@ -1386,11 +1539,11 @@ dri3_update_drawable(__DRIdrawable *driDrawable, mtx_unlock(&draw->mtx); return false; } - draw->width = geom_reply->width; draw->height = geom_reply->height; draw->depth = geom_reply->depth; draw->vtable->set_drawable_size(draw, draw->width, draw->height); + root_win = geom_reply->root; free(geom_reply); @@ -1420,10 +1573,16 @@ dri3_update_drawable(__DRIdrawable *driDrawable, mtx_unlock(&draw->mtx); return false; } + free(error); draw->is_pixmap = true; xcb_unregister_for_special_event(draw->conn, draw->special_event); draw->special_event = NULL; } + + if (draw->is_pixmap) + draw->window = root_win; + else + draw->window = draw->drawable; } dri3_flush_present_events(draw); mtx_unlock(&draw->mtx); @@ -1642,6 +1801,7 @@ dri3_get_buffer(__DRIdrawable *driDrawable, struct loader_dri3_drawable *draw) { struct loader_dri3_buffer *buffer; + bool fence_await = buffer_type == loader_dri3_buffer_back; int buf_id; if (buffer_type == loader_dri3_buffer_back) { @@ -1683,11 +1843,12 @@ dri3_get_buffer(__DRIdrawable *driDrawable, && buffer) { /* Fill the new buffer with data from an old buffer */ - dri3_fence_await(draw->conn, draw, buffer); if (!loader_dri3_blit_image(draw, new_buffer->image, buffer->image, - 0, 0, draw->width, draw->height, + 0, 0, + MIN2(buffer->width, new_buffer->width), + MIN2(buffer->height, new_buffer->height), 0, 0, 0) && !buffer->linear_buffer) { dri3_fence_reset(draw->conn, new_buffer); @@ -1698,6 +1859,7 @@ dri3_get_buffer(__DRIdrawable *driDrawable, 0, 0, 0, 0, draw->width, draw->height); dri3_fence_trigger(draw->conn, new_buffer); + fence_await = true; } dri3_free_render_buffer(draw, buffer); } else if (buffer_type == loader_dri3_buffer_front) { @@ -1719,12 +1881,15 @@ dri3_get_buffer(__DRIdrawable *driDrawable, new_buffer->linear_buffer, 0, 0, draw->width, draw->height, 0, 0, 0); - } + } else + fence_await = true; } buffer = new_buffer; draw->buffers[buf_id] = buffer; } - dri3_fence_await(draw->conn, draw, buffer); + + if (fence_await) + dri3_fence_await(draw->conn, draw, buffer); /* * Do we need to preserve the content of a previous buffer? @@ -1816,7 +1981,7 @@ loader_dri3_get_buffers(__DRIdrawable *driDrawable, front = NULL; back = NULL; - if (!dri3_update_drawable(driDrawable, draw)) + if (!dri3_update_drawable(draw)) return false; dri3_update_num_back(draw); @@ -1971,7 +2136,7 @@ dri3_find_back_alloc(struct loader_dri3_drawable *draw) back = draw->buffers[id]; /* Allocate a new back if we haven't got one */ if (!back && draw->back_format != __DRI_IMAGE_FORMAT_NONE && - dri3_update_drawable(draw->dri_drawable, draw)) + dri3_update_drawable(draw)) back = dri3_alloc_render_buffer(draw, draw->back_format, draw->width, draw->height, draw->depth);