mirror of
https://github.com/brl/mutter.git
synced 2024-11-13 01:36:10 -05:00
b499696d83
This uses actor paint volumes to perform culling during clutter_actor_paint. When performing a clipped redraw (because only a few localized actors changed) then as we traverse the scenegraph painting the actors we can now ignore actors that don't intersect the clip region. Early testing shows this can have a big performance benefit; e.g. 100% fps improvement for test-state with culling enabled and we hope that there are even much more compelling examples than that in the real world, Most Clutter applications are 2Dish interfaces and have quite a lot of actors that get continuously painted when anything is animated. The dynamic actors are often localized to an area of user focus though so with culling we can completely avoid painting any of the static actors outside the current clip region. Obviously the cost of culling has to be offset against the cost of painting to determine if it's a win, but our (limited) testing suggests it should be a win for most applications. Note: we hope we will be able to also bring another performance bump from culling with another iteration - hopefully in the 1.6 cycle - to avoid doing the culling in screen space and instead do it in the stage's model space. This will hopefully let us minimize the cost of transforming the actor volumes for culling.
269 lines
7.0 KiB
C
269 lines
7.0 KiB
C
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include "clutter-backend-fruity.h"
|
|
#include "clutter-stage-fruity.h"
|
|
#include "../clutter-private.h"
|
|
#include "../clutter-main.h"
|
|
#include "../clutter-debug.h"
|
|
|
|
static ClutterBackendEGL *backend_singleton = NULL;
|
|
|
|
|
|
G_DEFINE_TYPE (ClutterBackendEGL, clutter_backend_egl, CLUTTER_TYPE_BACKEND);
|
|
|
|
static gboolean
|
|
clutter_backend_egl_pre_parse (ClutterBackend *backend,
|
|
GError **error)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
clutter_backend_egl_post_parse (ClutterBackend *backend,
|
|
GError **error)
|
|
{
|
|
ClutterBackendEGL *backend_egl = CLUTTER_BACKEND_EGL(backend);
|
|
EGLBoolean status;
|
|
|
|
backend_egl->edpy = eglGetDisplay (EGL_DEFAULT_DISPLAY);
|
|
|
|
status = eglInitialize (backend_egl->edpy,
|
|
&backend_egl->egl_version_major,
|
|
&backend_egl->egl_version_minor);
|
|
|
|
if (status != EGL_TRUE)
|
|
{
|
|
g_set_error (error, CLUTTER_INIT_ERROR,
|
|
CLUTTER_INIT_ERROR_BACKEND,
|
|
"Unable to Initialize EGL");
|
|
return FALSE;
|
|
}
|
|
|
|
CLUTTER_NOTE (BACKEND, "EGL Reports version %i.%i",
|
|
backend_egl->egl_version_major,
|
|
backend_egl->egl_version_minor);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
clutter_backend_egl_ensure_context (ClutterBackend *backend,
|
|
ClutterStage *stage)
|
|
{
|
|
/* not doing anything since we only have one context */
|
|
}
|
|
|
|
static void
|
|
clutter_backend_egl_redraw (ClutterBackend *backend,
|
|
ClutterStage *stage)
|
|
{
|
|
ClutterBackendEGL *backend_egl = CLUTTER_BACKEND_EGL (backend);
|
|
ClutterStageEGL *stage_egl;
|
|
ClutterStageWindow *impl;
|
|
|
|
impl = _clutter_stage_get_window (stage);
|
|
if (!impl)
|
|
return;
|
|
|
|
g_assert (CLUTTER_IS_STAGE_EGL (impl));
|
|
stage_egl = CLUTTER_STAGE_EGL (impl);
|
|
|
|
eglWaitNative (EGL_CORE_NATIVE_ENGINE);
|
|
_clutter_stage_do_paint (stage, NULL);
|
|
cogl_flush ();
|
|
eglWaitGL();
|
|
eglSwapBuffers (backend_egl->edpy, stage_egl->egl_surface);
|
|
}
|
|
|
|
static ClutterActor *
|
|
clutter_backend_egl_create_stage (ClutterBackend *backend,
|
|
ClutterStage *wrapper,
|
|
GError **error)
|
|
{
|
|
ClutterBackendEGL *backend_egl = CLUTTER_BACKEND_EGL (backend);
|
|
ClutterStageEGL *stage_egl;
|
|
ClutterActor *stage;
|
|
|
|
if (backend_egl->stage)
|
|
{
|
|
g_warning ("The EGL native backend does not support multiple stages");
|
|
return backend_egl->stage;
|
|
}
|
|
|
|
stage = g_object_new (CLUTTER_TYPE_STAGE_FRUITY, NULL);
|
|
|
|
stage_egl = CLUTTER_STAGE_EGL (stage);
|
|
stage_egl->backend = backend_egl;
|
|
stage_egl->wrapper = wrapper;
|
|
|
|
backend_egl->stage = CLUTTER_ACTOR (stage_egl);
|
|
|
|
return stage;
|
|
}
|
|
|
|
|
|
static void
|
|
clutter_backend_egl_init_events (ClutterBackend *backend)
|
|
{
|
|
}
|
|
|
|
static const GOptionEntry entries[] =
|
|
{
|
|
{ NULL }
|
|
};
|
|
|
|
static void
|
|
clutter_backend_egl_finalize (GObject *gobject)
|
|
{
|
|
if (backend_singleton)
|
|
backend_singleton = NULL;
|
|
|
|
G_OBJECT_CLASS (clutter_backend_egl_parent_class)->finalize (gobject);
|
|
}
|
|
|
|
static void
|
|
clutter_backend_egl_dispose (GObject *gobject)
|
|
{
|
|
ClutterBackendEGL *backend_egl = CLUTTER_BACKEND_EGL (gobject);
|
|
|
|
_clutter_events_uninit (CLUTTER_BACKEND (backend_egl));
|
|
|
|
if (backend_egl->egl_context)
|
|
{
|
|
eglDestroyContext (backend_egl->edpy, backend_egl->egl_context);
|
|
backend_egl->egl_context = NULL;
|
|
}
|
|
|
|
if (backend_egl->edpy)
|
|
{
|
|
eglTerminate (backend_egl->edpy);
|
|
backend_egl->edpy = 0;
|
|
}
|
|
|
|
G_OBJECT_CLASS (clutter_backend_egl_parent_class)->dispose (gobject);
|
|
}
|
|
|
|
static GObject *
|
|
clutter_backend_egl_constructor (GType gtype,
|
|
guint n_params,
|
|
GObjectConstructParam *params)
|
|
{
|
|
GObjectClass *parent_class;
|
|
GObject *retval;
|
|
|
|
if (!backend_singleton)
|
|
{
|
|
parent_class = G_OBJECT_CLASS (clutter_backend_egl_parent_class);
|
|
retval = parent_class->constructor (gtype, n_params, params);
|
|
|
|
backend_singleton = CLUTTER_BACKEND_EGL (retval);
|
|
|
|
return retval;
|
|
}
|
|
|
|
g_warning ("Attempting to create a new backend object. This should "
|
|
"never happen, so we return the singleton instance.");
|
|
|
|
return g_object_ref (backend_singleton);
|
|
}
|
|
|
|
static ClutterFeatureFlags
|
|
clutter_backend_egl_get_features (ClutterBackend *backend)
|
|
{
|
|
ClutterBackendEGL *backend_egl = CLUTTER_BACKEND_EGL (backend);
|
|
|
|
CLUTTER_NOTE (BACKEND, "Checking features\n"
|
|
"GL_VENDOR: %s\n"
|
|
"GL_RENDERER: %s\n"
|
|
"GL_VERSION: %s\n"
|
|
"EGL_VENDOR: %s\n"
|
|
"EGL_VERSION: %s\n"
|
|
"EGL_EXTENSIONS: %s\n",
|
|
glGetString (GL_VENDOR),
|
|
glGetString (GL_RENDERER),
|
|
glGetString (GL_VERSION),
|
|
eglQueryString (backend_egl->edpy, EGL_VENDOR),
|
|
eglQueryString (backend_egl->edpy, EGL_VERSION),
|
|
eglQueryString (backend_egl->edpy, EGL_EXTENSIONS));
|
|
|
|
return CLUTTER_FEATURE_STAGE_STATIC;
|
|
}
|
|
|
|
static void
|
|
clutter_backend_egl_class_init (ClutterBackendEGLClass *klass)
|
|
{
|
|
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
|
ClutterBackendClass *backend_class = CLUTTER_BACKEND_CLASS (klass);
|
|
|
|
gobject_class->constructor = clutter_backend_egl_constructor;
|
|
gobject_class->dispose = clutter_backend_egl_dispose;
|
|
gobject_class->finalize = clutter_backend_egl_finalize;
|
|
|
|
backend_class->pre_parse = clutter_backend_egl_pre_parse;
|
|
backend_class->post_parse = clutter_backend_egl_post_parse;
|
|
backend_class->init_events = clutter_backend_egl_init_events;
|
|
backend_class->create_stage = clutter_backend_egl_create_stage;
|
|
backend_class->ensure_context = clutter_backend_egl_ensure_context;
|
|
backend_class->redraw = clutter_backend_egl_redraw;
|
|
backend_class->get_features = clutter_backend_egl_get_features;
|
|
}
|
|
|
|
static void
|
|
clutter_backend_egl_init (ClutterBackendEGL *backend_egl)
|
|
{
|
|
ClutterBackend *backend = CLUTTER_BACKEND (backend_egl);
|
|
ClutterMainContext *context;
|
|
int i;
|
|
|
|
clutter_backend_set_resolution (backend, 96.0);
|
|
clutter_backend_set_double_click_time (backend, 250);
|
|
clutter_backend_set_double_click_distance (backend, 5);
|
|
|
|
context = _clutter_context_get_default ();
|
|
|
|
#define MAX_FINGERS 5
|
|
|
|
for (i = 0; i < MAX_FINGERS; i++)
|
|
{
|
|
ClutterFruityFingerDevice *device;
|
|
|
|
device = g_new0 (ClutterFruityFingerDevice, 1);
|
|
context->input_devices = g_slist_append (context->input_devices, device);
|
|
|
|
device->device.id = i;
|
|
device->device.click_count = 0;
|
|
device->device.previous_time = 0;
|
|
device->device.previous_x = -1;
|
|
device->device.previous_y = -1;
|
|
device->device.previous_button_number = -1;
|
|
device->x = 0;
|
|
device->y = 0;
|
|
}
|
|
|
|
#undef MAX_FINGERS
|
|
}
|
|
|
|
GType
|
|
_clutter_backend_impl_get_type (void)
|
|
{
|
|
return clutter_backend_egl_get_type ();
|
|
}
|
|
|
|
EGLDisplay
|
|
clutter_egl_display (void)
|
|
{
|
|
return backend_singleton->edpy;
|
|
}
|
|
|
|
void *rpl_malloc (size_t allocation)
|
|
{
|
|
return g_malloc (allocation);
|
|
}
|
|
|
|
void rpl_free (void *ptr)
|
|
{
|
|
g_free (ptr);
|
|
}
|