MetaCursorSprite: Put renderer specific code in the renderer

There were lots of code handling the native renderer specific cases;
move these parts to the renderer. Note that this causes the X11 case to
always generate the texture which is a waste of memory, but his
regression will be fixed in a following commit.

The lazy loading of the texture was removed because it was eventually
always loaded anyway indirectly by the renderer to calculate the
current rect.

https://bugzilla.gnome.org/show_bug.cgi?id=744932
This commit is contained in:
Jonas Ådahl 2015-03-11 11:16:58 +08:00
parent 165050f8f9
commit d3fdaa3232
5 changed files with 295 additions and 230 deletions

View File

@ -181,3 +181,28 @@ meta_cursor_renderer_get_rect (MetaCursorRenderer *renderer)
return &priv->current_rect;
}
#ifdef HAVE_WAYLAND
void
meta_cursor_renderer_realize_cursor_from_wl_buffer (MetaCursorRenderer *renderer,
MetaCursorSprite *cursor_sprite,
struct wl_resource *buffer)
{
MetaCursorRendererClass *renderer_class = META_CURSOR_RENDERER_GET_CLASS (renderer);
if (renderer_class->realize_cursor_from_wl_buffer)
renderer_class->realize_cursor_from_wl_buffer (renderer, cursor_sprite, buffer);
}
#endif
void
meta_cursor_renderer_realize_cursor_from_xcursor (MetaCursorRenderer *renderer,
MetaCursorSprite *cursor_sprite,
XcursorImage *xc_image)
{
MetaCursorRendererClass *renderer_class = META_CURSOR_RENDERER_GET_CLASS (renderer);
if (renderer_class->realize_cursor_from_xcursor)
renderer_class->realize_cursor_from_xcursor (renderer, cursor_sprite, xc_image);
}

View File

@ -26,6 +26,10 @@
#define META_CURSOR_RENDERER_H
#include <glib-object.h>
#include <X11/Xcursor/Xcursor.h>
#ifdef HAVE_WAYLAND
#include <wayland-server.h>
#endif
#include <meta/screen.h>
#include "meta-cursor.h"
@ -39,6 +43,14 @@ struct _MetaCursorRendererClass
GObjectClass parent_class;
gboolean (* update_cursor) (MetaCursorRenderer *renderer);
#ifdef HAVE_WAYLAND
void (* realize_cursor_from_wl_buffer) (MetaCursorRenderer *renderer,
MetaCursorSprite *cursor_sprite,
struct wl_resource *buffer);
#endif
void (* realize_cursor_from_xcursor) (MetaCursorRenderer *renderer,
MetaCursorSprite *cursor_sprite,
XcursorImage *xc_image);
};
GType meta_cursor_renderer_get_type (void) G_GNUC_CONST;
@ -55,4 +67,14 @@ void meta_cursor_renderer_force_update (MetaCursorRenderer *renderer);
MetaCursorSprite * meta_cursor_renderer_get_cursor (MetaCursorRenderer *renderer);
const MetaRectangle * meta_cursor_renderer_get_rect (MetaCursorRenderer *renderer);
#ifdef HAVE_WAYLAND
void meta_cursor_renderer_realize_cursor_from_wl_buffer (MetaCursorRenderer *renderer,
MetaCursorSprite *cursor_sprite,
struct wl_resource *buffer);
#endif
void meta_cursor_renderer_realize_cursor_from_xcursor (MetaCursorRenderer *renderer,
MetaCursorSprite *cursor_sprite,
XcursorImage *xc_image);
#endif /* META_CURSOR_RENDERER_H */

View File

@ -29,11 +29,6 @@
#include "screen-private.h"
#include "meta-backend-private.h"
#ifdef HAVE_NATIVE_BACKEND
#include <gbm.h>
#include "backends/native/meta-cursor-renderer-native.h"
#endif
#include <string.h>
#include <X11/cursorfont.h>
@ -48,10 +43,6 @@ typedef struct
{
CoglTexture2D *texture;
int hot_x, hot_y;
#ifdef HAVE_NATIVE_BACKEND
struct gbm_bo *bo;
#endif
} MetaCursorImage;
struct _MetaCursorSprite
@ -74,11 +65,6 @@ meta_cursor_image_free (MetaCursorImage *image)
{
if (image->texture)
cogl_object_unref (image->texture);
#ifdef HAVE_NATIVE_BACKEND
if (image->bo)
gbm_bo_destroy (image->bo);
#endif
}
static const char *
@ -144,81 +130,13 @@ load_cursor_on_client (MetaCursor cursor)
meta_prefs_get_cursor_size ());
}
#ifdef HAVE_NATIVE_BACKEND
static void
get_hardware_cursor_size (uint64_t *cursor_width, uint64_t *cursor_height)
meta_cursor_sprite_load_from_xcursor_image (MetaCursorSprite *self,
XcursorImage *xc_image)
{
MetaCursorImage *image = &self->image;
MetaBackend *meta_backend = meta_get_backend ();
MetaCursorRenderer *renderer = meta_backend_get_cursor_renderer (meta_backend);
if (META_IS_CURSOR_RENDERER_NATIVE (renderer))
{
meta_cursor_renderer_native_get_cursor_size (META_CURSOR_RENDERER_NATIVE (renderer), cursor_width, cursor_height);
return;
}
g_assert_not_reached ();
}
#endif
#ifdef HAVE_NATIVE_BACKEND
static void
meta_cursor_image_load_gbm_buffer (struct gbm_device *gbm,
MetaCursorImage *image,
uint8_t *pixels,
uint width,
uint height,
int rowstride,
uint32_t gbm_format)
{
uint64_t cursor_width, cursor_height;
get_hardware_cursor_size (&cursor_width, &cursor_height);
if (width > cursor_width || height > cursor_height)
{
meta_warning ("Invalid theme cursor size (must be at most %ux%u)\n",
(unsigned int)cursor_width, (unsigned int)cursor_height);
return;
}
if (gbm_device_is_format_supported (gbm, gbm_format,
GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE))
{
uint8_t buf[4 * cursor_width * cursor_height];
uint i;
image->bo = gbm_bo_create (gbm, cursor_width, cursor_height,
gbm_format, GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE);
memset (buf, 0, sizeof(buf));
for (i = 0; i < height; i++)
memcpy (buf + i * 4 * cursor_width, pixels + i * rowstride, width * 4);
gbm_bo_write (image->bo, buf, cursor_width * cursor_height * 4);
}
else
meta_warning ("HW cursor for format %d not supported\n", gbm_format);
}
#endif
#ifdef HAVE_NATIVE_BACKEND
static struct gbm_device *
get_gbm_device (void)
{
MetaBackend *meta_backend = meta_get_backend ();
MetaCursorRenderer *renderer = meta_backend_get_cursor_renderer (meta_backend);
if (META_IS_CURSOR_RENDERER_NATIVE (renderer))
return meta_cursor_renderer_native_get_gbm_device (META_CURSOR_RENDERER_NATIVE (renderer));
else
return NULL;
}
#endif
static void
meta_cursor_image_load_from_xcursor_image (MetaCursorImage *image,
XcursorImage *xc_image)
{
uint width, height, rowstride;
CoglPixelFormat cogl_format;
ClutterBackend *clutter_backend;
@ -246,15 +164,7 @@ meta_cursor_image_load_from_xcursor_image (MetaCursorImage *image,
(uint8_t *) xc_image->pixels,
NULL);
#ifdef HAVE_NATIVE_BACKEND
struct gbm_device *gbm = get_gbm_device ();
if (gbm)
meta_cursor_image_load_gbm_buffer (gbm,
image,
(uint8_t *) xc_image->pixels,
width, height, rowstride,
GBM_FORMAT_ARGB8888);
#endif
meta_cursor_renderer_realize_cursor_from_xcursor (renderer, self, xc_image);
}
static XcursorImage *
@ -278,7 +188,7 @@ meta_cursor_sprite_tick_frame (MetaCursorSprite *self)
meta_cursor_image_free (&self->image);
image = meta_cursor_sprite_get_current_frame_image (self);
meta_cursor_image_load_from_xcursor_image (&self->image, image);
meta_cursor_sprite_load_from_xcursor_image (self, image);
}
guint
@ -297,36 +207,22 @@ meta_cursor_sprite_is_animated (MetaCursorSprite *self)
self->xcursor_images->nimage > 1);
}
static void
load_cursor_image (MetaCursorSprite *self)
{
XcursorImage *image;
/* Either cursors are loaded from X cursors or buffers. Since
* buffers are converted over immediately, we can make sure to
* load this directly. */
g_assert (self->cursor != META_CURSOR_NONE);
if (!self->xcursor_images)
{
self->current_frame = 0;
self->xcursor_images = load_cursor_on_client (self->cursor);
if (!self->xcursor_images)
meta_fatal ("Could not find cursor. Perhaps set XCURSOR_PATH?");
}
image = meta_cursor_sprite_get_current_frame_image (self);
meta_cursor_image_load_from_xcursor_image (&self->image, image);
}
MetaCursorSprite *
meta_cursor_sprite_from_theme (MetaCursor cursor)
{
MetaCursorSprite *self;
XcursorImage *image;
self = g_object_new (META_TYPE_CURSOR_SPRITE, NULL);
self->cursor = cursor;
self->current_frame = 0;
self->xcursor_images = load_cursor_on_client (self->cursor);
if (!self->xcursor_images)
meta_fatal ("Could not find cursor. Perhaps set XCURSOR_PATH?");
image = meta_cursor_sprite_get_current_frame_image (self);
meta_cursor_sprite_load_from_xcursor_image (self, image);
return self;
}
@ -351,11 +247,15 @@ meta_cursor_sprite_from_texture (CoglTexture2D *texture,
#ifdef HAVE_WAYLAND
static void
meta_cursor_image_load_from_buffer (MetaCursorImage *image,
struct wl_resource *buffer,
int hot_x,
int hot_y)
meta_cursor_sprite_load_from_buffer (MetaCursorSprite *self,
struct wl_resource *buffer,
int hot_x,
int hot_y)
{
MetaCursorImage *image = &self->image;
MetaBackend *meta_backend = meta_get_backend ();
MetaCursorRenderer *renderer =
meta_backend_get_cursor_renderer (meta_backend);
ClutterBackend *backend;
CoglContext *cogl_context;
@ -367,76 +267,7 @@ meta_cursor_image_load_from_buffer (MetaCursorImage *image,
image->texture = cogl_wayland_texture_2d_new_from_buffer (cogl_context, buffer, NULL);
#ifdef HAVE_NATIVE_BACKEND
struct gbm_device *gbm = get_gbm_device ();
if (gbm)
{
uint32_t gbm_format;
uint64_t cursor_width, cursor_height;
uint width, height;
width = cogl_texture_get_width (COGL_TEXTURE (image->texture));
height = cogl_texture_get_height (COGL_TEXTURE (image->texture));
struct wl_shm_buffer *shm_buffer = wl_shm_buffer_get (buffer);
if (shm_buffer)
{
int rowstride = wl_shm_buffer_get_stride (shm_buffer);
wl_shm_buffer_begin_access (shm_buffer);
switch (wl_shm_buffer_get_format (shm_buffer))
{
#if G_BYTE_ORDER == G_BIG_ENDIAN
case WL_SHM_FORMAT_ARGB8888:
gbm_format = GBM_FORMAT_ARGB8888;
break;
case WL_SHM_FORMAT_XRGB8888:
gbm_format = GBM_FORMAT_XRGB8888;
break;
#else
case WL_SHM_FORMAT_ARGB8888:
gbm_format = GBM_FORMAT_ARGB8888;
break;
case WL_SHM_FORMAT_XRGB8888:
gbm_format = GBM_FORMAT_XRGB8888;
break;
#endif
default:
g_warn_if_reached ();
gbm_format = GBM_FORMAT_ARGB8888;
}
meta_cursor_image_load_gbm_buffer (gbm,
image,
(uint8_t *) wl_shm_buffer_get_data (shm_buffer),
width, height, rowstride,
gbm_format);
wl_shm_buffer_end_access (shm_buffer);
}
else
{
/* HW cursors have a predefined size (at least 64x64), which usually is bigger than cursor theme
size, so themed cursors must be padded with transparent pixels to fill the
overlay. This is trivial if we have CPU 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.
*/
get_hardware_cursor_size (&cursor_width, &cursor_height);
if (width != cursor_width || height != cursor_height)
{
meta_warning ("Invalid cursor size (must be 64x64), falling back to software (GL) cursors\n");
return;
}
image->bo = gbm_bo_import (gbm, GBM_BO_IMPORT_WL_BUFFER, buffer, GBM_BO_USE_CURSOR);
if (!image->bo)
meta_warning ("Importing HW cursor from wl_buffer failed\n");
}
}
#endif
meta_cursor_renderer_realize_cursor_from_wl_buffer (renderer, self, buffer);
}
MetaCursorSprite *
@ -448,7 +279,7 @@ meta_cursor_sprite_from_buffer (struct wl_resource *buffer,
self = g_object_new (META_TYPE_CURSOR_SPRITE, NULL);
meta_cursor_image_load_from_buffer (&self->image, buffer, hot_x, hot_y);
meta_cursor_sprite_load_from_buffer (self, buffer, hot_x, hot_y);
return self;
}
@ -459,9 +290,6 @@ meta_cursor_sprite_get_cogl_texture (MetaCursorSprite *self,
int *hot_x,
int *hot_y)
{
if (!self->image.texture)
load_cursor_image (self);
if (hot_x)
*hot_x = self->image.hot_x;
if (hot_y)
@ -470,29 +298,33 @@ meta_cursor_sprite_get_cogl_texture (MetaCursorSprite *self,
return COGL_TEXTURE (self->image.texture);
}
#ifdef HAVE_NATIVE_BACKEND
struct gbm_bo *
meta_cursor_sprite_get_gbm_bo (MetaCursorSprite *self,
int *hot_x,
int *hot_y)
{
if (!self->image.bo)
load_cursor_image (self);
if (hot_x)
*hot_x = self->image.hot_x;
if (hot_y)
*hot_y = self->image.hot_y;
return self->image.bo;
}
#endif
MetaCursor
meta_cursor_sprite_get_meta_cursor (MetaCursorSprite *self)
{
return self->cursor;
}
void
meta_cursor_sprite_get_hotspot (MetaCursorSprite *self,
int *hot_x,
int *hot_y)
{
*hot_x = self->image.hot_x;
*hot_y = self->image.hot_y;
}
guint
meta_cursor_sprite_get_width (MetaCursorSprite *self)
{
return cogl_texture_get_width (COGL_TEXTURE (self->image.texture));
}
guint
meta_cursor_sprite_get_height (MetaCursorSprite *self)
{
return cogl_texture_get_height (COGL_TEXTURE (self->image.texture));
}
static void
meta_cursor_sprite_init (MetaCursorSprite *self)
{

View File

@ -54,11 +54,13 @@ CoglTexture *meta_cursor_sprite_get_cogl_texture (MetaCursorSprite *self,
int *hot_x,
int *hot_y);
#ifdef HAVE_NATIVE_BACKEND
struct gbm_bo *meta_cursor_sprite_get_gbm_bo (MetaCursorSprite *self,
int *hot_x,
int *hot_y);
#endif
void meta_cursor_sprite_get_hotspot (MetaCursorSprite *self,
int *hot_x,
int *hot_y);
guint meta_cursor_sprite_get_width (MetaCursorSprite *self);
guint meta_cursor_sprite_get_height (MetaCursorSprite *self);
gboolean meta_cursor_sprite_is_animated (MetaCursorSprite *self);
void meta_cursor_sprite_tick_frame (MetaCursorSprite *self);

View File

@ -26,9 +26,11 @@
#include "meta-cursor-renderer-native.h"
#include <string.h>
#include <gbm.h>
#include <xf86drm.h>
#include <meta/util.h>
#include "meta-monitor-manager-private.h"
#ifndef DRM_CAP_CURSOR_WIDTH
@ -38,6 +40,8 @@
#define DRM_CAP_CURSOR_HEIGHT 0x9
#endif
static GQuark quark_cursor_sprite = 0;
struct _MetaCursorRendererNativePrivate
{
gboolean has_hw_cursor;
@ -70,6 +74,28 @@ meta_cursor_renderer_native_finalize (GObject *object)
G_OBJECT_CLASS (meta_cursor_renderer_native_parent_class)->finalize (object);
}
static struct gbm_bo *
get_cursor_sprite_gbm_bo (MetaCursorSprite *cursor_sprite)
{
return g_object_get_qdata (G_OBJECT (cursor_sprite), quark_cursor_sprite);
}
static void
cursor_gbm_bo_free (gpointer data)
{
if (!data)
return;
gbm_bo_destroy ((struct gbm_bo *)data);
}
static void
set_cursor_sprite_gbm_bo (MetaCursorSprite *cursor_sprite, struct gbm_bo *bo)
{
g_object_set_qdata_full (G_OBJECT (cursor_sprite), quark_cursor_sprite,
bo, cursor_gbm_bo_free);
}
static void
set_crtc_cursor (MetaCursorRendererNative *native,
MetaCRTC *crtc,
@ -89,9 +115,10 @@ set_crtc_cursor (MetaCursorRendererNative *native,
union gbm_bo_handle handle;
int hot_x, hot_y;
bo = meta_cursor_sprite_get_gbm_bo (cursor_sprite, &hot_x, &hot_y);
bo = get_cursor_sprite_gbm_bo (cursor_sprite);
handle = gbm_bo_get_handle (bo);
meta_cursor_sprite_get_hotspot (cursor_sprite, &hot_x, &hot_y);
drmModeSetCursor2 (priv->drm_fd, crtc->crtc_id, handle.u32,
priv->cursor_width, priv->cursor_height, hot_x, hot_y);
}
@ -147,7 +174,7 @@ should_have_hw_cursor (MetaCursorRenderer *renderer)
MetaCursorSprite *cursor_sprite = meta_cursor_renderer_get_cursor (renderer);
if (cursor_sprite)
return (meta_cursor_sprite_get_gbm_bo (cursor_sprite, NULL, NULL) != NULL);
return (get_cursor_sprite_gbm_bo (cursor_sprite) != NULL);
else
return FALSE;
}
@ -219,6 +246,165 @@ meta_cursor_renderer_native_update_cursor (MetaCursorRenderer *renderer)
return priv->has_hw_cursor;
}
static void
get_hardware_cursor_size (MetaCursorRendererNative *native,
uint64_t *width, uint64_t *height)
{
MetaCursorRendererNativePrivate *priv =
meta_cursor_renderer_native_get_instance_private (native);
*width = priv->cursor_width;
*height = priv->cursor_height;
}
static void
load_cursor_sprite_gbm_buffer (MetaCursorRendererNative *native,
MetaCursorSprite *cursor_sprite,
uint8_t *pixels,
uint width,
uint height,
int rowstride,
uint32_t gbm_format)
{
MetaCursorRendererNativePrivate *priv =
meta_cursor_renderer_native_get_instance_private (native);
uint64_t cursor_width, cursor_height;
get_hardware_cursor_size (native, &cursor_width, &cursor_height);
if (width > cursor_width || height > cursor_height)
{
meta_warning ("Invalid theme cursor size (must be at most %ux%u)\n",
(unsigned int)cursor_width, (unsigned int)cursor_height);
return;
}
if (gbm_device_is_format_supported (priv->gbm, gbm_format,
GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE))
{
struct gbm_bo *bo;
uint8_t buf[4 * cursor_width * cursor_height];
uint i;
bo = gbm_bo_create (priv->gbm, cursor_width, cursor_height,
gbm_format, GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE);
memset (buf, 0, sizeof(buf));
for (i = 0; i < height; i++)
memcpy (buf + i * 4 * cursor_width, pixels + i * rowstride, width * 4);
gbm_bo_write (bo, buf, cursor_width * cursor_height * 4);
set_cursor_sprite_gbm_bo (cursor_sprite, bo);
}
else
meta_warning ("HW cursor for format %d not supported\n", gbm_format);
}
#ifdef HAVE_WAYLAND
static void
meta_cursor_renderer_native_realize_cursor_from_wl_buffer (MetaCursorRenderer *renderer,
MetaCursorSprite *cursor_sprite,
struct wl_resource *buffer)
{
MetaCursorRendererNative *native = META_CURSOR_RENDERER_NATIVE (renderer);
MetaCursorRendererNativePrivate *priv =
meta_cursor_renderer_native_get_instance_private (native);
uint32_t gbm_format;
uint64_t cursor_width, cursor_height;
uint width, height;
width = meta_cursor_sprite_get_width (cursor_sprite);
height = meta_cursor_sprite_get_height (cursor_sprite);
struct wl_shm_buffer *shm_buffer = wl_shm_buffer_get (buffer);
if (shm_buffer)
{
int rowstride = wl_shm_buffer_get_stride (shm_buffer);
uint8_t *buffer_data;
wl_shm_buffer_begin_access (shm_buffer);
switch (wl_shm_buffer_get_format (shm_buffer))
{
#if G_BYTE_ORDER == G_BIG_ENDIAN
case WL_SHM_FORMAT_ARGB8888:
gbm_format = GBM_FORMAT_ARGB8888;
break;
case WL_SHM_FORMAT_XRGB8888:
gbm_format = GBM_FORMAT_XRGB8888;
break;
#else
case WL_SHM_FORMAT_ARGB8888:
gbm_format = GBM_FORMAT_ARGB8888;
break;
case WL_SHM_FORMAT_XRGB8888:
gbm_format = GBM_FORMAT_XRGB8888;
break;
#endif
default:
g_warn_if_reached ();
gbm_format = GBM_FORMAT_ARGB8888;
}
buffer_data = wl_shm_buffer_get_data (shm_buffer);
load_cursor_sprite_gbm_buffer (native,
cursor_sprite,
buffer_data,
width, height, rowstride,
gbm_format);
wl_shm_buffer_end_access (shm_buffer);
}
else
{
struct gbm_bo *bo;
/* HW cursors have a predefined size (at least 64x64), which usually is
* bigger than cursor theme size, so themed cursors must be padded with
* transparent pixels to fill the overlay. This is trivial if we have CPU
* 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. */
get_hardware_cursor_size (native, &cursor_width, &cursor_height);
if (width != cursor_width || height != cursor_height)
{
meta_warning ("Invalid cursor size (must be 64x64), falling back to software (GL) cursors\n");
return;
}
bo = gbm_bo_import (priv->gbm,
GBM_BO_IMPORT_WL_BUFFER,
buffer,
GBM_BO_USE_CURSOR);
if (!bo)
{
meta_warning ("Importing HW cursor from wl_buffer failed\n");
return;
}
set_cursor_sprite_gbm_bo (cursor_sprite, bo);
}
}
#endif
static void
meta_cursor_renderer_native_realize_cursor_from_xcursor (MetaCursorRenderer *renderer,
MetaCursorSprite *cursor_sprite,
XcursorImage *xc_image)
{
MetaCursorRendererNative *native = META_CURSOR_RENDERER_NATIVE (renderer);
load_cursor_sprite_gbm_buffer (native,
cursor_sprite,
(uint8_t *) xc_image->pixels,
xc_image->width,
xc_image->height,
xc_image->width * 4,
GBM_FORMAT_ARGB8888);
}
static void
meta_cursor_renderer_native_class_init (MetaCursorRendererNativeClass *klass)
{
@ -227,6 +413,14 @@ meta_cursor_renderer_native_class_init (MetaCursorRendererNativeClass *klass)
object_class->finalize = meta_cursor_renderer_native_finalize;
renderer_class->update_cursor = meta_cursor_renderer_native_update_cursor;
#ifdef HAVE_WAYLAND
renderer_class->realize_cursor_from_wl_buffer =
meta_cursor_renderer_native_realize_cursor_from_wl_buffer;
#endif
renderer_class->realize_cursor_from_xcursor =
meta_cursor_renderer_native_realize_cursor_from_xcursor;
quark_cursor_sprite = g_quark_from_static_string ("-meta-cursor-native");
}
static void
@ -279,16 +473,6 @@ meta_cursor_renderer_native_get_gbm_device (MetaCursorRendererNative *native)
return priv->gbm;
}
void
meta_cursor_renderer_native_get_cursor_size (MetaCursorRendererNative *native,
uint64_t *width, uint64_t *height)
{
MetaCursorRendererNativePrivate *priv = meta_cursor_renderer_native_get_instance_private (native);
*width = priv->cursor_width;
*height = priv->cursor_height;
}
void
meta_cursor_renderer_native_force_update (MetaCursorRendererNative *native)
{