diff --git a/src/egl/drivers/dri2/egl_dri2.c b/src/egl/drivers/dri2/egl_dri2.c index 5f3fb0714d1..77658fb2a1b 100644 --- a/src/egl/drivers/dri2/egl_dri2.c +++ b/src/egl/drivers/dri2/egl_dri2.c @@ -845,6 +845,7 @@ dri2_setup_screen(_EGLDisplay *disp) disp->Extensions.MESA_x11_native_visual_id = EGL_TRUE; + disp->Extensions.EXT_surface_compression = EGL_TRUE; disp->Extensions.KHR_image_base = EGL_TRUE; disp->Extensions.KHR_gl_renderbuffer_image = EGL_TRUE; disp->Extensions.KHR_gl_texture_2D_image = EGL_TRUE; @@ -3650,6 +3651,33 @@ dri2_interop_flush_objects(_EGLDisplay *disp, _EGLContext *ctx, unsigned count, objects, out); } +static EGLBoolean +dri2_query_supported_compression_rates(_EGLDisplay *disp, _EGLConfig *config, + const EGLAttrib *attr_list, + EGLint *rates, EGLint rate_size, + EGLint *num_rate) +{ + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + struct dri2_egl_config *conf = dri2_egl_config(config); + enum __DRIFixedRateCompression dri_rates[rate_size]; + + if (dri2_dpy->image->base.version >= 22 && + dri2_dpy->image->queryCompressionRates) { + const __DRIconfig *dri_conf = + dri2_get_dri_config(conf, EGL_WINDOW_BIT, EGL_GL_COLORSPACE_LINEAR); + if (!dri2_dpy->image->queryCompressionRates( + dri2_dpy->dri_screen_render_gpu, dri_conf, rate_size, dri_rates, + num_rate)) + return EGL_FALSE; + + for (int i = 0; i < *num_rate && i < rate_size; ++i) + rates[i] = dri_rates[i]; + return EGL_TRUE; + } + *num_rate = 0; + return EGL_TRUE; +} + const _EGLDriver _eglDriver = { .Initialize = dri2_initialize, .Terminate = dri2_terminate, @@ -3703,4 +3731,5 @@ const _EGLDriver _eglDriver = { .GLInteropFlushObjects = dri2_interop_flush_objects, .DupNativeFenceFDANDROID = dri2_dup_native_fence_fd, .SetBlobCacheFuncsANDROID = dri2_set_blob_cache_funcs, + .QuerySupportedCompressionRatesEXT = dri2_query_supported_compression_rates, }; diff --git a/src/egl/drivers/dri2/egl_dri2.h b/src/egl/drivers/dri2/egl_dri2.h index 8f57720e2db..93427fa80ce 100644 --- a/src/egl/drivers/dri2/egl_dri2.h +++ b/src/egl/drivers/dri2/egl_dri2.h @@ -527,6 +527,12 @@ dri2_add_config(_EGLDisplay *disp, const __DRIconfig *dri_config, void dri2_add_pbuffer_configs_for_visuals(_EGLDisplay *disp); +EGLint +dri2_from_dri_compression_rate(enum __DRIFixedRateCompression rate); + +enum __DRIFixedRateCompression +dri2_to_dri_compression_rate(EGLint rate); + _EGLImage * dri2_create_image_khr(_EGLDisplay *disp, _EGLContext *ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attr_list); diff --git a/src/egl/drivers/dri2/platform_wayland.c b/src/egl/drivers/dri2/platform_wayland.c index d0d7962d8e7..160eb5e72cd 100644 --- a/src/egl/drivers/dri2/platform_wayland.c +++ b/src/egl/drivers/dri2/platform_wayland.c @@ -891,18 +891,100 @@ dri2_wl_release_buffers(struct dri2_egl_surface *dri2_surf) dri2_egl_surface_free_local_buffers(dri2_surf); } +/* Return list of modifiers that should be used to restrict the list of + * modifiers actually supported by the surface. As of now, it is only used + * to get the set of modifiers used for fixed-rate compression. */ +static uint64_t * +get_surface_specific_modifiers(struct dri2_egl_surface *dri2_surf, + int *modifiers_count) +{ + struct dri2_egl_display *dri2_dpy = + dri2_egl_display(dri2_surf->base.Resource.Display); + int rate = dri2_surf->base.CompressionRate; + uint64_t *modifiers; + + if (rate == EGL_SURFACE_COMPRESSION_FIXED_RATE_NONE_EXT || + !dri2_surf->wl_win) + return NULL; + + if (!dri2_dpy->image->queryCompressionModifiers( + dri2_dpy->dri_screen_render_gpu, dri2_surf->format, rate, + 0, NULL, modifiers_count)) + return NULL; + + modifiers = malloc(*modifiers_count * sizeof(uint64_t)); + if (!modifiers) + return NULL; + + if (!dri2_dpy->image->queryCompressionModifiers( + dri2_dpy->dri_screen_render_gpu, dri2_surf->format, rate, + *modifiers_count, modifiers, modifiers_count)) { + free(modifiers); + return NULL; + } + + return modifiers; +} + +static void +update_surface(struct dri2_egl_surface *dri2_surf, __DRIimage *dri_img) +{ + struct dri2_egl_display *dri2_dpy = + dri2_egl_display(dri2_surf->base.Resource.Display); + int compression_rate; + + if (!dri_img) + return; + + /* Update the surface with the actual compression rate */ + dri2_dpy->image->queryImage(dri_img, __DRI_IMAGE_ATTRIB_COMPRESSION_RATE, + &compression_rate); + dri2_surf->base.CompressionRate = compression_rate; +} + +static bool +intersect_modifiers(struct u_vector *subset, struct u_vector *set, + uint64_t *other_modifiers, int other_modifiers_count) +{ + if (!u_vector_init_pow2(subset, 4, sizeof(uint64_t))) + return false; + + uint64_t *modifier_ptr, *mod; + u_vector_foreach(mod, set) { + for (int i = 0; i < other_modifiers_count; ++i) { + if (other_modifiers[i] != *mod) + continue; + modifier_ptr = u_vector_add(subset); + if (modifier_ptr) + *modifier_ptr = *mod; + } + } + + return true; +} + static void create_dri_image(struct dri2_egl_surface *dri2_surf, enum pipe_format pipe_format, uint32_t use_flags, + uint64_t *surf_modifiers, int surf_modifiers_count, struct u_vector *modifiers_set) { struct dri2_egl_display *dri2_dpy = dri2_egl_display(dri2_surf->base.Resource.Display); + struct u_vector modifiers_subset; uint64_t *modifiers; unsigned int num_modifiers; - modifiers = u_vector_tail(modifiers_set); - num_modifiers = u_vector_length(modifiers_set); + if (surf_modifiers_count > 0) { + if (!intersect_modifiers(&modifiers_subset, modifiers_set, surf_modifiers, + surf_modifiers_count)) + return; + modifiers = u_vector_tail(&modifiers_subset); + num_modifiers = u_vector_length(&modifiers_subset); + } else { + modifiers = u_vector_tail(modifiers_set); + num_modifiers = u_vector_length(modifiers_set); + } /* For the purposes of this function, an INVALID modifier on * its own means the modifiers aren't supported. */ @@ -917,12 +999,19 @@ create_dri_image(struct dri2_egl_surface *dri2_surf, dri2_surf->base.Height, pipe_format, (dri2_dpy->fd_render_gpu != dri2_dpy->fd_display_gpu) ? 0 : use_flags, modifiers, num_modifiers, NULL); + + if (surf_modifiers_count > 0) { + u_vector_finish(&modifiers_subset); + update_surface(dri2_surf, dri2_surf->back->dri_image); + } } static void create_dri_image_from_dmabuf_feedback(struct dri2_egl_surface *dri2_surf, enum pipe_format pipe_format, - uint32_t use_flags) + uint32_t use_flags, + uint64_t *surf_modifiers, + int surf_modifiers_count) { int visual_idx; uint32_t flags; @@ -954,7 +1043,8 @@ create_dri_image_from_dmabuf_feedback(struct dri2_egl_surface *dri2_surf, if (tranche->flags & ZWP_LINUX_DMABUF_FEEDBACK_V1_TRANCHE_FLAGS_SCANOUT) flags |= __DRI_IMAGE_USE_SCANOUT; - create_dri_image(dri2_surf, pipe_format, flags, + create_dri_image(dri2_surf, pipe_format, flags, surf_modifiers, + surf_modifiers_count, &tranche->formats.modifiers[visual_idx]); if (dri2_surf->back->dri_image) @@ -964,14 +1054,17 @@ create_dri_image_from_dmabuf_feedback(struct dri2_egl_surface *dri2_surf, static void create_dri_image_from_formats(struct dri2_egl_surface *dri2_surf, - enum pipe_format pipe_format, uint32_t use_flags) + enum pipe_format pipe_format, uint32_t use_flags, + uint64_t *surf_modifiers, + int surf_modifiers_count) { struct dri2_egl_display *dri2_dpy = dri2_egl_display(dri2_surf->base.Resource.Display); int visual_idx; visual_idx = dri2_wl_visual_idx_from_fourcc(dri2_surf->format); - create_dri_image(dri2_surf, pipe_format, use_flags, + create_dri_image(dri2_surf, pipe_format, use_flags, surf_modifiers, + surf_modifiers_count, &dri2_dpy->formats.modifiers[visual_idx]); } @@ -1148,11 +1241,18 @@ get_back_bo(struct dri2_egl_surface *dri2_surf) } if (dri2_surf->back->dri_image == NULL) { + int modifiers_count = 0; + uint64_t *modifiers = + get_surface_specific_modifiers(dri2_surf, &modifiers_count); + if (dri2_surf->wl_dmabuf_feedback) - create_dri_image_from_dmabuf_feedback(dri2_surf, pipe_format, - use_flags); + create_dri_image_from_dmabuf_feedback( + dri2_surf, pipe_format, use_flags, modifiers, modifiers_count); if (dri2_surf->back->dri_image == NULL) - create_dri_image_from_formats(dri2_surf, pipe_format, use_flags); + create_dri_image_from_formats(dri2_surf, pipe_format, use_flags, + modifiers, modifiers_count); + + free(modifiers); dri2_surf->back->age = 0; }