X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Floader%2Floader_dri3_helper.c;h=be33575e1a8f59dcdafdc470590824df33bd4b48;hb=71ca5fb68ad2e8c0ac7e4fbbd1eb56b0e3cd8732;hp=6587281c4ab8c5be507ab4c586eccbbb506b3dcb;hpb=069fdd5f9facbd72fb6a289696c7b74e3237e70f;p=mesa.git diff --git a/src/loader/loader_dri3_helper.c b/src/loader/loader_dri3_helper.c index 6587281c4ab..be33575e1a8 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,10 +460,42 @@ 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 + * controller. + */ + if (ce->mode == XCB_PRESENT_COMPLETE_MODE_COPY && + draw->last_present_mode == XCB_PRESENT_COMPLETE_MODE_FLIP) { + for (int b = 0; b < ARRAY_SIZE(draw->buffers); b++) { + if (draw->buffers[b]) + draw->buffers[b]->reallocate = true; + } + } + /* If the server tells us that our allocation is suboptimal, we + * reallocate once. + */ +#ifdef HAVE_DRI3_MODIFIERS + if (ce->mode == XCB_PRESENT_COMPLETE_MODE_SUBOPTIMAL_COPY && + draw->last_present_mode != ce->mode) { + for (int b = 0; b < ARRAY_SIZE(draw->buffers); b++) { + if (draw->buffers[b]) + draw->buffers[b]->reallocate = true; + } + } +#endif draw->last_present_mode = ce->mode; if (draw->vtable->show_fps) @@ -396,13 +518,6 @@ dri3_handle_present_event(struct loader_dri3_drawable *draw, if (buf && buf->pixmap == ie->pixmap) buf->busy = 0; - - if (buf && draw->num_back <= b && b < LOADER_DRI3_MAX_BACK && - draw->cur_blit_source != b && - !buf->busy) { - dri3_free_render_buffer(draw, buf); - draw->buffers[b] = NULL; - } } break; } @@ -535,7 +650,6 @@ dri3_find_back(struct loader_dri3_drawable *draw) /* Check whether we need to reuse the current back buffer as new back. * In that case, wait until it's not busy anymore. */ - dri3_update_num_back(draw); num_to_consider = draw->num_back; if (!loader_dri3_have_image_blit(draw) && draw->cur_blit_source != -1) { num_to_consider = 1; @@ -649,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) @@ -703,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, @@ -805,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, @@ -880,7 +1000,10 @@ loader_dri3_swap_buffers_msc(struct loader_dri3_drawable *draw, */ if (!loader_dri3_have_image_blit(draw) && draw->cur_blit_source != -1) options |= XCB_PRESENT_OPTION_COPY; - +#ifdef HAVE_DRI3_MODIFIERS + if (draw->multiplanes_available) + options |= XCB_PRESENT_OPTION_SUBOPTIMAL; +#endif back->busy = 1; back->last_swap = draw->send_sbc; xcb_present_pixmap(draw->conn, @@ -995,38 +1118,76 @@ dri3_cpp_for_format(uint32_t format) { case __DRI_IMAGE_FORMAT_XBGR2101010: case __DRI_IMAGE_FORMAT_ABGR2101010: case __DRI_IMAGE_FORMAT_SARGB8: + case __DRI_IMAGE_FORMAT_SABGR8: 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_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_SABGR8: return __DRI_IMAGE_FOURCC_SABGR8888; + 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; } +#ifdef HAVE_DRI3_MODIFIERS static bool has_supported_modifier(struct loader_dri3_drawable *draw, unsigned int format, uint64_t *modifiers, uint32_t count) @@ -1061,6 +1222,7 @@ has_supported_modifier(struct loader_dri3_drawable *draw, unsigned int format, free(supported_modifiers); return found; } +#endif /** loader_dri3_alloc_render_buffer * @@ -1106,6 +1268,7 @@ dri3_alloc_render_buffer(struct loader_dri3_drawable *draw, unsigned int format, goto no_image; if (!draw->is_different_gpu) { +#ifdef HAVE_DRI3_MODIFIERS if (draw->multiplanes_available && draw->ext->image->base.version >= 15 && draw->ext->image->queryDmaBufModifiers && @@ -1117,7 +1280,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, @@ -1161,15 +1324,23 @@ 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 if (!buffer->image) buffer->image = draw->ext->image->createImage(draw->dri_screen, width, height, @@ -1195,7 +1366,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,11 +1416,12 @@ dri3_alloc_render_buffer(struct loader_dri3_drawable *draw, unsigned int format, buffer->modifier = DRM_FORMAT_MOD_INVALID; pixmap = xcb_generate_id(draw->conn); +#ifdef HAVE_DRI3_MODIFIERS if (draw->multiplanes_available && 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], @@ -1258,7 +1431,9 @@ dri3_alloc_render_buffer(struct loader_dri3_drawable *draw, unsigned int format, depth, buffer->cpp * 8, buffer->modifier, buffer_fds); - } else { + } else +#endif + { xcb_dri3_pixmap_from_buffer(draw->conn, pixmap, draw->drawable, @@ -1311,8 +1486,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) { @@ -1322,6 +1496,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; @@ -1359,11 +1534,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); @@ -1393,10 +1568,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); @@ -1447,6 +1628,7 @@ loader_dri3_create_image(xcb_connection_t *c, return ret; } +#ifdef HAVE_DRI3_MODIFIERS __DRIimage * loader_dri3_create_image_from_buffers(xcb_connection_t *c, xcb_dri3_buffers_from_pixmap_reply_t *bp_reply, @@ -1488,6 +1670,7 @@ loader_dri3_create_image_from_buffers(xcb_connection_t *c, return ret; } +#endif /** dri3_get_pixmap_buffer * @@ -1541,7 +1724,7 @@ dri3_get_pixmap_buffer(__DRIdrawable *driDrawable, unsigned int format, (sync_fence = xcb_generate_id(draw->conn)), false, fence_fd); - +#ifdef HAVE_DRI3_MODIFIERS if (draw->multiplanes_available && draw->ext->image->base.version >= 15 && draw->ext->image->createImageFromDmaBufs2) { @@ -1560,7 +1743,9 @@ dri3_get_pixmap_buffer(__DRIdrawable *driDrawable, unsigned int format, width = bps_reply->width; height = bps_reply->height; free(bps_reply); - } else { + } else +#endif + { xcb_dri3_buffer_from_pixmap_cookie_t bp_cookie; xcb_dri3_buffer_from_pixmap_reply_t *bp_reply; @@ -1611,6 +1796,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) { @@ -1626,11 +1812,12 @@ dri3_get_buffer(__DRIdrawable *driDrawable, buffer = draw->buffers[buf_id]; - /* Allocate a new buffer if there isn't an old one, or if that - * old one is the wrong size + /* Allocate a new buffer if there isn't an old one, if that + * old one is the wrong size, or if it's suboptimal */ if (!buffer || buffer->width != draw->width || - buffer->height != draw->height) { + buffer->height != draw->height || + buffer->reallocate) { struct loader_dri3_buffer *new_buffer; /* Allocate the new buffers @@ -1651,11 +1838,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); @@ -1666,6 +1854,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) { @@ -1687,12 +1876,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? @@ -1775,6 +1967,7 @@ loader_dri3_get_buffers(__DRIdrawable *driDrawable, { struct loader_dri3_drawable *draw = loaderPrivate; struct loader_dri3_buffer *front, *back; + int buf_id; buffers->image_mask = 0; buffers->front = NULL; @@ -1783,9 +1976,19 @@ 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); + + /* Free no longer needed back buffers */ + for (buf_id = draw->num_back; buf_id < LOADER_DRI3_MAX_BACK; buf_id++) { + if (draw->cur_blit_source != buf_id && draw->buffers[buf_id]) { + dri3_free_render_buffer(draw, draw->buffers[buf_id]); + draw->buffers[buf_id] = NULL; + } + } + /* pixmaps always have front buffers. * Exchange swaps also mandate fake front buffers. */ @@ -1928,7 +2131,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);