diff --git a/src/backends/native/meta-cursor-renderer-native.c b/src/backends/native/meta-cursor-renderer-native.c index 83458cfe6..2cb46a82f 100644 --- a/src/backends/native/meta-cursor-renderer-native.c +++ b/src/backends/native/meta-cursor-renderer-native.c @@ -590,6 +590,98 @@ calculate_crtc_cursor_hotspot (MetaCursorSprite *cursor_sprite, *hotspot = GRAPHENE_POINT_INIT (hot_x * scale, hot_y * scale); } +static gboolean +get_optimal_cursor_size (MetaCrtcKms *crtc_kms, + int required_width, + int required_height, + uint64_t *out_cursor_width, + uint64_t *out_cursor_height) +{ + MetaGpu *gpu = meta_crtc_get_gpu (META_CRTC (crtc_kms)); + MetaGpuKms *gpu_kms = META_GPU_KMS (gpu); + MetaCursorRendererNativeGpuData *cursor_renderer_gpu_data; + MetaKmsPlane *kms_plane; + const MetaKmsPlaneCursorSizeHints *size_hints; + size_t i; + + cursor_renderer_gpu_data = + meta_cursor_renderer_native_gpu_data_from_gpu (gpu_kms); + + if (!cursor_renderer_gpu_data) + return FALSE; + + kms_plane = meta_crtc_kms_get_assigned_cursor_plane (crtc_kms); + if (!kms_plane) + return FALSE; + + size_hints = meta_kms_plane_get_cursor_size_hints (kms_plane); + + for (i = 0; i < size_hints->num_of_size_hints; i++) + { + if (size_hints->cursor_width[i] >= required_width && + size_hints->cursor_height[i] >= required_height) + { + *out_cursor_width = size_hints->cursor_width[i]; + *out_cursor_height = size_hints->cursor_height[i]; + return TRUE; + } + } + + if (!size_hints->has_size_hints && + cursor_renderer_gpu_data->cursor_width >= required_width && + cursor_renderer_gpu_data->cursor_height >= required_height) + { + *out_cursor_width = cursor_renderer_gpu_data->cursor_width; + *out_cursor_height = cursor_renderer_gpu_data->cursor_height; + return TRUE; + } + + return FALSE; +} + +static gboolean +supports_exact_cursor_size (MetaCrtcKms *crtc_kms, + int required_width, + int required_height) +{ + MetaGpu *gpu = meta_crtc_get_gpu (META_CRTC (crtc_kms)); + MetaGpuKms *gpu_kms = META_GPU_KMS (gpu); + MetaCursorRendererNativeGpuData *cursor_renderer_gpu_data; + MetaKmsPlane *kms_plane; + const MetaKmsPlaneCursorSizeHints *size_hints; + size_t i; + + cursor_renderer_gpu_data = + meta_cursor_renderer_native_gpu_data_from_gpu (gpu_kms); + + if (!cursor_renderer_gpu_data) + return FALSE; + + kms_plane = meta_crtc_kms_get_assigned_cursor_plane (crtc_kms); + if (!kms_plane) + return FALSE; + + size_hints = meta_kms_plane_get_cursor_size_hints (kms_plane); + + for (i = 0; i < size_hints->num_of_size_hints; i++) + { + if (size_hints->cursor_width[i] == required_width && + size_hints->cursor_height[i] == required_height) + { + return TRUE; + } + } + + if (!size_hints->has_size_hints && + cursor_renderer_gpu_data->cursor_width == required_width && + cursor_renderer_gpu_data->cursor_height == required_height) + { + return TRUE; + } + + return FALSE; +} + static gboolean load_cursor_sprite_gbm_buffer_for_crtc (MetaCursorRendererNative *native, MetaCrtcKms *crtc_kms, @@ -614,23 +706,15 @@ load_cursor_sprite_gbm_buffer_for_crtc (MetaCursorRendererNative *native, MetaKmsCrtc *kms_crtc; uint64_t cursor_width, cursor_height; g_autoptr (MetaDrmBuffer) buffer = NULL; - MetaCursorRendererNativeGpuData *cursor_renderer_gpu_data; g_autoptr (MetaDeviceFile) device_file = NULL; g_autoptr (GError) error = NULL; graphene_point_t hotspot; - cursor_renderer_gpu_data = - meta_cursor_renderer_native_gpu_data_from_gpu (gpu_kms); - if (!cursor_renderer_gpu_data) - return FALSE; - - cursor_width = (uint64_t) cursor_renderer_gpu_data->cursor_width; - cursor_height = (uint64_t) cursor_renderer_gpu_data->cursor_height; - - if (width > cursor_width || height > cursor_height) + if (!get_optimal_cursor_size (crtc_kms, + width, height, + &cursor_width, &cursor_height)) { - meta_warning ("Invalid theme cursor size (must be at most %ux%u)", - (unsigned int)cursor_width, (unsigned int)cursor_height); + meta_warning ("Can't handle cursor size %ux%u)", width, height); return FALSE; } @@ -834,7 +918,6 @@ realize_cursor_sprite_from_wl_buffer_for_crtc (MetaCursorRenderer *renderer MetaGpu *gpu = meta_crtc_get_gpu (META_CRTC (crtc_kms)); MetaGpuKms *gpu_kms = META_GPU_KMS (gpu); MetaCursorRendererNativeGpuData *cursor_renderer_gpu_data; - uint64_t cursor_width, cursor_height; CoglTexture *texture; uint width, height; MetaWaylandBuffer *buffer; @@ -950,16 +1033,13 @@ realize_cursor_sprite_from_wl_buffer_for_crtc (MetaCursorRenderer *renderer * access to the data, but it's not possible if the buffer is in GPU * memory (and possibly tiled too), so if we don't get the right size, we * fallback to GL. */ - cursor_width = (uint64_t) cursor_renderer_gpu_data->cursor_width; - cursor_height = (uint64_t) cursor_renderer_gpu_data->cursor_height; - texture = meta_cursor_sprite_get_cogl_texture (cursor_sprite); width = cogl_texture_get_width (texture); height = cogl_texture_get_height (texture); - if (width != cursor_width || height != cursor_height) + if (!supports_exact_cursor_size (crtc_kms, width, height)) { - meta_warning ("Invalid cursor size (must be 64x64), falling back to software (GL) cursors"); + meta_warning ("Invalid cursor size %ux%u, falling back to SW GL cursors)", width, height); return FALSE; } diff --git a/src/backends/native/meta-kms-plane-private.h b/src/backends/native/meta-kms-plane-private.h index 8d3c5f88c..21df3b726 100644 --- a/src/backends/native/meta-kms-plane-private.h +++ b/src/backends/native/meta-kms-plane-private.h @@ -42,6 +42,7 @@ typedef enum _MetaKmsPlaneProp META_KMS_PLANE_PROP_IN_FENCE_FD, META_KMS_PLANE_PROP_HOTSPOT_X, META_KMS_PLANE_PROP_HOTSPOT_Y, + META_KMS_PLANE_PROP_SIZE_HINTS, META_KMS_PLANE_N_PROPS } MetaKmsPlaneProp; diff --git a/src/backends/native/meta-kms-plane.c b/src/backends/native/meta-kms-plane.c index 69a0b12d3..699dc02db 100644 --- a/src/backends/native/meta-kms-plane.c +++ b/src/backends/native/meta-kms-plane.c @@ -56,11 +56,19 @@ struct _MetaKmsPlane */ GHashTable *formats_modifiers; + MetaKmsPlaneCursorSizeHints size_hints; + MetaKmsPlanePropTable prop_table; MetaKmsDevice *device; }; +/* Shall be removed once available on libdrm.*/ +struct drm_plane_size_hint { + __u16 width; + __u16 height; +}; + G_DEFINE_TYPE (MetaKmsPlane, meta_kms_plane, G_TYPE_OBJECT) MetaKmsDevice * @@ -83,6 +91,12 @@ meta_kms_plane_get_plane_type (MetaKmsPlane *plane) return plane->type; } +const MetaKmsPlaneCursorSizeHints * +meta_kms_plane_get_cursor_size_hints (MetaKmsPlane *plane) +{ + return &plane->size_hints; +} + uint32_t meta_kms_plane_get_prop_id (MetaKmsPlane *plane, MetaKmsPlaneProp prop) @@ -348,6 +362,48 @@ update_formats (MetaKmsPlane *plane, drmModeFreePropertyBlob (blob); } +static void +update_cursor_size_hints (MetaKmsPlane *plane, + MetaKmsImplDevice *impl_device) + +{ + MetaKmsProp *prop; + drmModePropertyBlobPtr size_hints_blob = NULL; + struct drm_plane_size_hint *size_hints_ptr; + uint32_t blob_id, i, num_of_size_hints; + int fd; + MetaKmsPlaneType type = meta_kms_plane_get_plane_type (plane); + + if (type != META_KMS_PLANE_TYPE_CURSOR) + return; + prop = &plane->prop_table.props[META_KMS_PLANE_PROP_SIZE_HINTS]; + if(!prop) + return; + + blob_id = prop->value; + if (blob_id == 0) + return; + + fd = meta_kms_impl_device_get_fd (impl_device); + size_hints_blob = drmModeGetPropertyBlob (fd, blob_id); + if (!size_hints_blob) + return; + + plane->size_hints.has_size_hints = TRUE; + size_hints_ptr = size_hints_blob->data; + + num_of_size_hints = size_hints_blob->length / sizeof (struct drm_plane_size_hint); + plane->size_hints.cursor_width = g_new0 (uint64_t, num_of_size_hints); + plane->size_hints.cursor_height = g_new0 (uint64_t, num_of_size_hints); + plane->size_hints.num_of_size_hints = num_of_size_hints; + + for (i = 0; i < num_of_size_hints; i++) + { + plane->size_hints.cursor_width [i] = size_hints_ptr[i].width; + plane->size_hints.cursor_height [i] = size_hints_ptr[i].height; + } +} + static void set_formats_from_array (MetaKmsPlane *plane, const uint32_t *formats, @@ -426,6 +482,7 @@ meta_kms_plane_read_state (MetaKmsPlane *plane, META_KMS_PLANE_N_PROPS); update_formats (plane, impl_device); + update_cursor_size_hints (plane, impl_device); update_rotations (plane); update_legacy_formats (plane, drm_plane); @@ -534,6 +591,11 @@ init_properties (MetaKmsPlane *plane, .name = "HOTSPOT_Y", .type = DRM_MODE_PROP_SIGNED_RANGE, }, + [META_KMS_PLANE_PROP_SIZE_HINTS] = + { + .name = "SIZE_HINTS", + .type = DRM_MODE_PROP_BLOB, + }, }, .rotation_bitmask = { [META_KMS_PLANE_ROTATION_BIT_ROTATE_0] = @@ -627,6 +689,8 @@ meta_kms_plane_finalize (GObject *object) MetaKmsPlane *plane = META_KMS_PLANE (object); g_hash_table_destroy (plane->formats_modifiers); + g_clear_pointer (&plane->size_hints.cursor_width, g_free); + g_clear_pointer (&plane->size_hints.cursor_height, g_free); G_OBJECT_CLASS (meta_kms_plane_parent_class)->finalize (object); } diff --git a/src/backends/native/meta-kms-plane.h b/src/backends/native/meta-kms-plane.h index 21f9b3345..3b52de070 100644 --- a/src/backends/native/meta-kms-plane.h +++ b/src/backends/native/meta-kms-plane.h @@ -31,6 +31,14 @@ enum _MetaKmsPlaneType META_KMS_PLANE_TYPE_OVERLAY, }; +typedef struct _MetaKmsPlaneCursorSizeHints +{ + gboolean has_size_hints; + uint64_t num_of_size_hints; + uint64_t *cursor_width; + uint64_t *cursor_height; +} MetaKmsPlaneCursorSizeHints; + #define META_TYPE_KMS_PLANE meta_kms_plane_get_type () G_DECLARE_FINAL_TYPE (MetaKmsPlane, meta_kms_plane, META, KMS_PLANE, GObject) @@ -44,6 +52,9 @@ uint32_t meta_kms_plane_get_id (MetaKmsPlane *plane); META_EXPORT_TEST MetaKmsPlaneType meta_kms_plane_get_plane_type (MetaKmsPlane *plane); +const MetaKmsPlaneCursorSizeHints * +meta_kms_plane_get_cursor_size_hints (MetaKmsPlane *plane); + gboolean meta_kms_plane_is_transform_handled (MetaKmsPlane *plane, MetaMonitorTransform transform);