diff --git a/clutter/clutter-backend.c b/clutter/clutter-backend.c index 014f2393e..0c61b08c6 100644 --- a/clutter/clutter-backend.c +++ b/clutter/clutter-backend.c @@ -204,6 +204,22 @@ clutter_backend_real_font_changed (ClutterBackend *backend) CLUTTER_NOTE (BACKEND, "Units per em: %.2f", priv->units_per_em); } +static void +clutter_backend_real_redraw (ClutterBackend *backend, + ClutterStage *stage) +{ + ClutterStageWindow *impl; + + if (CLUTTER_ACTOR_IN_DESTRUCTION (stage)) + return; + + impl = _clutter_stage_get_window (stage); + if (impl == NULL) + return; + + _clutter_stage_window_redraw (impl); +} + static void clutter_backend_class_init (ClutterBackendClass *klass) { @@ -243,6 +259,7 @@ clutter_backend_class_init (ClutterBackendClass *klass) klass->resolution_changed = clutter_backend_real_resolution_changed; klass->font_changed = clutter_backend_real_font_changed; + klass->redraw = clutter_backend_real_redraw; } static void @@ -333,7 +350,6 @@ void _clutter_backend_redraw (ClutterBackend *backend, ClutterStage *stage) { - ClutterBackendClass *klass; CLUTTER_STATIC_COUNTER (redraw_counter, "_clutter_backend_redraw counter", "Increments for each _clutter_backend_redraw call", @@ -347,9 +363,7 @@ _clutter_backend_redraw (ClutterBackend *backend, CLUTTER_COUNTER_INC (_clutter_uprof_context, redraw_counter); CLUTTER_TIMER_START (_clutter_uprof_context, redraw_timer); - klass = CLUTTER_BACKEND_GET_CLASS (backend); - if (G_LIKELY (klass->redraw)) - klass->redraw (backend, stage); + CLUTTER_BACKEND_GET_CLASS (backend)->redraw (backend, stage); CLUTTER_TIMER_STOP (_clutter_uprof_context, redraw_timer); } diff --git a/clutter/egl/clutter-backend-egl.c b/clutter/egl/clutter-backend-egl.c index 54d93db3c..cb5b28ce0 100644 --- a/clutter/egl/clutter-backend-egl.c +++ b/clutter/egl/clutter-backend-egl.c @@ -505,21 +505,6 @@ clutter_backend_egl_ensure_context (ClutterBackend *backend, #endif /* COGL_HAS_XLIB_SUPPORT */ } -static void -clutter_backend_egl_redraw (ClutterBackend *backend, - ClutterStage *stage) -{ - ClutterStageWindow *impl; - - impl = _clutter_stage_get_window (stage); - if (!impl) - return; - - g_assert (CLUTTER_IS_STAGE_EGL (impl)); - - _clutter_stage_egl_redraw (CLUTTER_STAGE_EGL (impl), stage); -} - #ifndef COGL_HAS_XLIB_SUPPORT static ClutterDeviceManager * clutter_backend_egl_get_device_manager (ClutterBackend *backend) @@ -879,7 +864,6 @@ _clutter_backend_egl_class_init (ClutterBackendEGLClass *klass) backend_class->create_stage = clutter_backend_egl_create_stage; backend_class->create_context = clutter_backend_egl_create_context; backend_class->ensure_context = clutter_backend_egl_ensure_context; - backend_class->redraw = clutter_backend_egl_redraw; #ifdef COGL_HAS_XLIB_SUPPORT backendx11_class->get_visual_info = clutter_backend_egl_get_visual_info; diff --git a/clutter/egl/clutter-stage-egl.c b/clutter/egl/clutter-stage-egl.c index 4b2673de2..23025cac3 100644 --- a/clutter/egl/clutter-stage-egl.c +++ b/clutter/egl/clutter-stage-egl.c @@ -297,6 +297,7 @@ clutter_stage_window_iface_init (ClutterStageWindowIface *iface) iface->add_redraw_clip = clutter_stage_egl_add_redraw_clip; iface->has_redraw_clips = clutter_stage_egl_has_redraw_clips; iface->ignoring_redraw_clips = clutter_stage_egl_ignoring_redraw_clips; + iface->redraw = clutter_stage_egl_redraw; } #ifdef COGL_HAS_X11_SUPPORT @@ -336,18 +337,18 @@ _clutter_stage_egl_init (ClutterStageEGL *stage) #endif /* COGL_HAS_X11_SUPPORT */ -void -_clutter_stage_egl_redraw (ClutterStageEGL *stage_egl, - ClutterStage *stage) +static void +clutter_stage_egl_redraw (ClutterStageWindow *stage_window) { - ClutterBackend *backend = clutter_get_default_backend (); - ClutterBackendEGL *backend_egl = CLUTTER_BACKEND_EGL (backend); - ClutterActor *wrapper; - EGLSurface egl_surface; - gboolean may_use_clipped_redraw; - gboolean use_clipped_redraw; + ClutterStageEGL *stage_egl = CLUTTER_STAGE_EGL (stage_window); + ClutterBackend *backend = clutter_get_default_backend (); + ClutterBackendEGL *backend_egl = CLUTTER_BACKEND_EGL (backend); + ClutterActor *wrapper; + EGLSurface egl_surface; + gboolean may_use_clipped_redraw; + gboolean use_clipped_redraw; #ifdef COGL_HAS_X11_SUPPORT - ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_egl); + ClutterStageX11 *stage_x11 = CLUTTER_STAGE_X11 (stage_egl); wrapper = CLUTTER_ACTOR (stage_x11->wrapper); egl_surface = stage_egl->egl_surface; diff --git a/clutter/egl/clutter-stage-egl.h b/clutter/egl/clutter-stage-egl.h index 8dc040158..86e075e1d 100644 --- a/clutter/egl/clutter-stage-egl.h +++ b/clutter/egl/clutter-stage-egl.h @@ -18,6 +18,7 @@ #include "clutter-egl-headers.h" #include "clutter-backend-egl.h" +G_BEGIN_DECLS #define CLUTTER_TYPE_STAGE_EGL (_clutter_stage_egl_get_type ()) #define CLUTTER_STAGE_EGL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), CLUTTER_TYPE_STAGE_EGL, ClutterStageEGL)) @@ -69,7 +70,6 @@ struct _ClutterStageEGLClass GType _clutter_stage_egl_get_type (void) G_GNUC_CONST; -void _clutter_stage_egl_redraw (ClutterStageEGL *stage_egl, - ClutterStage *stage); +G_END_DECLS #endif /* __CLUTTER_STAGE_EGL_H__ */ diff --git a/clutter/glx/clutter-backend-glx.c b/clutter/glx/clutter-backend-glx.c index bb0335841..232a9e5e3 100644 --- a/clutter/glx/clutter-backend-glx.c +++ b/clutter/glx/clutter-backend-glx.c @@ -772,28 +772,6 @@ clutter_backend_glx_ensure_context (ClutterBackend *backend, } } -/* - * FIXME: we should remove backend_class->redraw() and just - * have stage_window_iface->redraw() - */ -static void -clutter_backend_glx_redraw (ClutterBackend *backend, - ClutterStage *stage) -{ - ClutterStageWindow *impl = _clutter_stage_get_window (stage); - - if (G_UNLIKELY (impl == NULL)) - { - CLUTTER_NOTE (BACKEND, "Stage [%p] has no implementation", stage); - return; - } - - g_assert (CLUTTER_IS_STAGE_GLX (impl)); - - _clutter_stage_glx_redraw (CLUTTER_STAGE_GLX (impl), - stage); -} - static ClutterStageWindow * clutter_backend_glx_create_stage (ClutterBackend *backend, ClutterStage *wrapper, @@ -844,7 +822,6 @@ clutter_backend_glx_class_init (ClutterBackendGLXClass *klass) backend_class->create_stage = clutter_backend_glx_create_stage; backend_class->add_options = clutter_backend_glx_add_options; backend_class->get_features = clutter_backend_glx_get_features; - backend_class->redraw = clutter_backend_glx_redraw; backend_class->create_context = clutter_backend_glx_create_context; backend_class->ensure_context = clutter_backend_glx_ensure_context; diff --git a/clutter/glx/clutter-stage-glx.c b/clutter/glx/clutter-stage-glx.c index b0a2e5544..c68165447 100644 --- a/clutter/glx/clutter-stage-glx.c +++ b/clutter/glx/clutter-stage-glx.c @@ -311,6 +311,324 @@ clutter_stage_glx_add_redraw_clip (ClutterStageWindow *stage_window, stage_glx->initialized_redraw_clip = TRUE; } +#ifdef HAVE_DRM +static int +drm_wait_vblank(int fd, drm_wait_vblank_t *vbl) +{ + int ret, rc; + + do + { + ret = ioctl(fd, DRM_IOCTL_WAIT_VBLANK, vbl); + vbl->request.type &= ~_DRM_VBLANK_RELATIVE; + rc = errno; + } + while (ret && rc == EINTR); + + return rc; +} +#endif /* HAVE_DRM */ + +static void +wait_for_vblank (ClutterBackendGLX *backend_glx) +{ + if (backend_glx->vblank_type == CLUTTER_VBLANK_NONE) + return; + + if (backend_glx->wait_video_sync) + { + unsigned int retraceCount; + + CLUTTER_NOTE (BACKEND, "Waiting for vblank (wait_video_sync)"); + backend_glx->get_video_sync (&retraceCount); + backend_glx->wait_video_sync (2, + (retraceCount + 1) % 2, + &retraceCount); + } + else + { +#ifdef HAVE_DRM + drm_wait_vblank_t blank; + + CLUTTER_NOTE (BACKEND, "Waiting for vblank (drm)"); + blank.request.type = _DRM_VBLANK_RELATIVE; + blank.request.sequence = 1; + blank.request.signal = 0; + drm_wait_vblank (backend_glx->dri_fd, &blank); +#else + CLUTTER_NOTE (BACKEND, "No vblank mechanism found"); +#endif /* HAVE_DRM */ + } +} + +static void +clutter_stage_glx_redraw (ClutterStageWindow *stage_window) +{ + ClutterBackendX11 *backend_x11; + ClutterBackendGLX *backend_glx; + ClutterStageX11 *stage_x11; + ClutterStageGLX *stage_glx; + GLXDrawable drawable; + unsigned int video_sync_count; + gboolean may_use_clipped_redraw; + gboolean use_clipped_redraw; + + CLUTTER_STATIC_TIMER (painting_timer, + "Redrawing", /* parent */ + "Painting actors", + "The time spent painting actors", + 0 /* no application private data */); + CLUTTER_STATIC_TIMER (swapbuffers_timer, + "Redrawing", /* parent */ + "glXSwapBuffers", + "The time spent blocked by glXSwapBuffers", + 0 /* no application private data */); + CLUTTER_STATIC_TIMER (blit_sub_buffer_timer, + "Redrawing", /* parent */ + "glx_blit_sub_buffer", + "The time spent in _glx_blit_sub_buffer", + 0 /* no application private data */); + + stage_x11 = CLUTTER_STAGE_X11 (stage_window); + if (stage_x11->xwin == None) + return; + + stage_glx = CLUTTER_STAGE_GLX (stage_window); + + backend_x11 = stage_x11->backend; + backend_glx = CLUTTER_BACKEND_GLX (backend_x11); + + CLUTTER_TIMER_START (_clutter_uprof_context, painting_timer); + + if (G_LIKELY (backend_glx->can_blit_sub_buffer) && + /* NB: a zero width redraw clip == full stage redraw */ + stage_glx->bounding_redraw_clip.width != 0 && + /* some drivers struggle to get going and produce some junk + * frames when starting up... */ + G_LIKELY (stage_glx->frame_count > 3) && + /* While resizing a window clipped redraws are disabled to avoid + * artefacts. See clutter-event-x11.c:event_translate for a + * detailed explanation */ + G_LIKELY (stage_x11->clipped_redraws_cool_off == 0)) + { + may_use_clipped_redraw = TRUE; + } + else + may_use_clipped_redraw = FALSE; + + if (may_use_clipped_redraw && + G_LIKELY (!(clutter_paint_debug_flags & + CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS))) + use_clipped_redraw = TRUE; + else + use_clipped_redraw = FALSE; + + if (use_clipped_redraw) + { + cogl_clip_push_window_rectangle (stage_glx->bounding_redraw_clip.x, + stage_glx->bounding_redraw_clip.y, + stage_glx->bounding_redraw_clip.width, + stage_glx->bounding_redraw_clip.height); + _clutter_stage_do_paint (stage_x11->wrapper, + &stage_glx->bounding_redraw_clip); + cogl_clip_pop (); + } + else + _clutter_stage_do_paint (stage_x11->wrapper, NULL); + + if (may_use_clipped_redraw && + G_UNLIKELY ((clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS))) + { + static CoglMaterial *outline = NULL; + ClutterGeometry *clip = &stage_glx->bounding_redraw_clip; + ClutterActor *actor = CLUTTER_ACTOR (stage_x11->wrapper); + CoglHandle vbo; + float x_1 = clip->x; + float x_2 = clip->x + clip->width; + float y_1 = clip->y; + float y_2 = clip->y + clip->height; + float quad[8] = { + x_1, y_1, + x_2, y_1, + x_2, y_2, + x_1, y_2 + }; + CoglMatrix modelview; + + if (outline == NULL) + { + outline = cogl_material_new (); + cogl_material_set_color4ub (outline, 0xff, 0x00, 0x00, 0xff); + } + + vbo = cogl_vertex_buffer_new (4); + cogl_vertex_buffer_add (vbo, + "gl_Vertex", + 2, /* n_components */ + COGL_ATTRIBUTE_TYPE_FLOAT, + FALSE, /* normalized */ + 0, /* stride */ + quad); + cogl_vertex_buffer_submit (vbo); + + cogl_push_matrix (); + cogl_matrix_init_identity (&modelview); + _clutter_actor_apply_modelview_transform (actor, &modelview); + cogl_set_modelview_matrix (&modelview); + cogl_set_source (outline); + cogl_vertex_buffer_draw (vbo, COGL_VERTICES_MODE_LINE_LOOP, + 0 , 4); + cogl_pop_matrix (); + cogl_object_unref (vbo); + } + + cogl_flush (); + CLUTTER_TIMER_STOP (_clutter_uprof_context, painting_timer); + + drawable = stage_glx->glxwin + ? stage_glx->glxwin + : stage_x11->xwin; + + /* If we might ever use _clutter_backend_glx_blit_sub_buffer then we + * always need to keep track of the video_sync_count so that we can + * throttle blits. + * + * Note: we get the count *before* we issue any glXCopySubBuffer or + * blit_sub_buffer request in case the count would go up before + * returning control to us. + */ + if (backend_glx->can_blit_sub_buffer && backend_glx->get_video_sync) + backend_glx->get_video_sync (&video_sync_count); + + /* push on the screen */ + if (use_clipped_redraw) + { + ClutterGeometry *clip = &stage_glx->bounding_redraw_clip; + ClutterGeometry copy_area; + ClutterActor *actor; + + CLUTTER_NOTE (BACKEND, + "_glx_blit_sub_buffer (window: 0x%lx, " + "x: %d, y: %d, " + "width: %d, height: %d)", + (unsigned long) drawable, + stage_glx->bounding_redraw_clip.x, + stage_glx->bounding_redraw_clip.y, + stage_glx->bounding_redraw_clip.width, + stage_glx->bounding_redraw_clip.height); + + /* XXX: It seems there will be a race here in that the stage + * window may be resized before glXCopySubBufferMESA is handled + * and so we may copy the wrong region. I can't really see how + * we can handle this with the current state of X but at least + * in this case a full redraw should be queued by the resize + * anyway so it should only exhibit temporary artefacts. + */ + actor = CLUTTER_ACTOR (stage_x11->wrapper); + copy_area.y = clutter_actor_get_height (actor) + - clip->y + - clip->height; + copy_area.x = clip->x; + copy_area.width = clip->width; + copy_area.height = clip->height; + + /* glXCopySubBufferMESA and glBlitFramebuffer are not integrated + * with the glXSwapIntervalSGI mechanism which we usually use to + * throttle the Clutter framerate to the vertical refresh and so + * we have to manually wait for the vblank period... + */ + + /* Here 'is_synchronized' only means that the blit won't cause a + * tear, ie it won't prevent multiple blits per retrace if they + * can all be performed in the blanking period. If that's the + * case then we still want to use the vblank sync menchanism but + * we only need it to throttle redraws. + */ + if (!backend_glx->blit_sub_buffer_is_synchronized) + { + /* XXX: note that glXCopySubBuffer, at least for Intel, is + * synchronized with the vblank but glBlitFramebuffer may + * not be so we use the same scheme we do when calling + * glXSwapBuffers without the swap_control extension and + * call glFinish () before waiting for the vblank period. + * + * See where we call glXSwapBuffers for more details. + */ + glFinish (); + wait_for_vblank (backend_glx); + } + else if (backend_glx->get_video_sync) + { + /* If we have the GLX_SGI_video_sync extension then we can + * be a bit smarter about how we throttle blits by avoiding + * any waits if we can see that the video sync count has + * already progressed. */ + if (backend_glx->last_video_sync_count == video_sync_count) + wait_for_vblank (backend_glx); + } + else + wait_for_vblank (backend_glx); + + CLUTTER_TIMER_START (_clutter_uprof_context, blit_sub_buffer_timer); + _clutter_backend_glx_blit_sub_buffer (backend_glx, + drawable, + copy_area.x, + copy_area.y, + copy_area.width, + copy_area.height); + CLUTTER_TIMER_STOP (_clutter_uprof_context, blit_sub_buffer_timer); + } + else + { + CLUTTER_NOTE (BACKEND, "glXSwapBuffers (display: %p, window: 0x%lx)", + backend_x11->xdpy, + (unsigned long) drawable); + + /* If we have GLX swap buffer events then glXSwapBuffers will return + * immediately and we need to track that there is a swap in + * progress... */ + if (clutter_feature_available (CLUTTER_FEATURE_SWAP_EVENTS)) + stage_glx->pending_swaps++; + + if (backend_glx->vblank_type != CLUTTER_VBLANK_GLX_SWAP && + backend_glx->vblank_type != CLUTTER_VBLANK_NONE) + { + /* If we are going to wait for VBLANK manually, we not only + * need to flush out pending drawing to the GPU before we + * sleep, we need to wait for it to finish. Otherwise, we + * may end up with the situation: + * + * - We finish drawing - GPU drawing continues + * - We go to sleep - GPU drawing continues + * VBLANK - We call glXSwapBuffers - GPU drawing continues + * - GPU drawing continues + * - Swap buffers happens + * + * Producing a tear. Calling glFinish() first will cause us + * to properly wait for the next VBLANK before we swap. This + * obviously does not happen when we use _GLX_SWAP and let + * the driver do the right thing + */ + glFinish (); + + wait_for_vblank (backend_glx); + } + + CLUTTER_TIMER_START (_clutter_uprof_context, swapbuffers_timer); + glXSwapBuffers (backend_x11->xdpy, drawable); + CLUTTER_TIMER_STOP (_clutter_uprof_context, swapbuffers_timer); + + _cogl_swap_buffers_notify (); + } + + backend_glx->last_video_sync_count = video_sync_count; + + /* reset the redraw clipping for the next paint... */ + stage_glx->initialized_redraw_clip = FALSE; + + stage_glx->frame_count++; +} + static void clutter_stage_window_iface_init (ClutterStageWindowIface *iface) { @@ -323,6 +641,7 @@ clutter_stage_window_iface_init (ClutterStageWindowIface *iface) iface->add_redraw_clip = clutter_stage_glx_add_redraw_clip; iface->has_redraw_clips = clutter_stage_glx_has_redraw_clips; iface->ignoring_redraw_clips = clutter_stage_glx_ignoring_redraw_clips; + iface->redraw = clutter_stage_glx_redraw; /* the rest is inherited from ClutterStageX11 */ } @@ -375,316 +694,3 @@ clutter_event_translator_iface_init (ClutterEventTranslatorIface *iface) iface->translate_event = clutter_stage_glx_translate_event; } - -#ifdef HAVE_DRM -static int -drm_wait_vblank(int fd, drm_wait_vblank_t *vbl) -{ - int ret, rc; - - do - { - ret = ioctl(fd, DRM_IOCTL_WAIT_VBLANK, vbl); - vbl->request.type &= ~_DRM_VBLANK_RELATIVE; - rc = errno; - } - while (ret && rc == EINTR); - - return rc; -} -#endif /* HAVE_DRM */ - -static void -wait_for_vblank (ClutterBackendGLX *backend_glx) -{ - if (backend_glx->vblank_type == CLUTTER_VBLANK_NONE) - return; - - if (backend_glx->wait_video_sync) - { - unsigned int retraceCount; - - CLUTTER_NOTE (BACKEND, "Waiting for vblank (wait_video_sync)"); - backend_glx->get_video_sync (&retraceCount); - backend_glx->wait_video_sync (2, - (retraceCount + 1) % 2, - &retraceCount); - } - else - { -#ifdef HAVE_DRM - drm_wait_vblank_t blank; - - CLUTTER_NOTE (BACKEND, "Waiting for vblank (drm)"); - blank.request.type = _DRM_VBLANK_RELATIVE; - blank.request.sequence = 1; - blank.request.signal = 0; - drm_wait_vblank (backend_glx->dri_fd, &blank); -#else - CLUTTER_NOTE (BACKEND, "No vblank mechanism found"); -#endif /* HAVE_DRM */ - } -} - -void -_clutter_stage_glx_redraw (ClutterStageGLX *stage_glx, - ClutterStage *stage) -{ - ClutterBackend *backend; - ClutterBackendX11 *backend_x11; - ClutterBackendGLX *backend_glx; - ClutterStageX11 *stage_x11; - GLXDrawable drawable; - unsigned int video_sync_count; - gboolean may_use_clipped_redraw; - gboolean use_clipped_redraw; - CLUTTER_STATIC_TIMER (painting_timer, - "Redrawing", /* parent */ - "Painting actors", - "The time spent painting actors", - 0 /* no application private data */); - CLUTTER_STATIC_TIMER (swapbuffers_timer, - "Redrawing", /* parent */ - "glXSwapBuffers", - "The time spent blocked by glXSwapBuffers", - 0 /* no application private data */); - CLUTTER_STATIC_TIMER (blit_sub_buffer_timer, - "Redrawing", /* parent */ - "glx_blit_sub_buffer", - "The time spent in _glx_blit_sub_buffer", - 0 /* no application private data */); - - stage_x11 = CLUTTER_STAGE_X11 (stage_glx); - if (stage_x11->xwin == None) - return; - - backend = clutter_get_default_backend (); - backend_x11 = CLUTTER_BACKEND_X11 (backend); - backend_glx = CLUTTER_BACKEND_GLX (backend); - - CLUTTER_TIMER_START (_clutter_uprof_context, painting_timer); - - if (G_LIKELY (backend_glx->can_blit_sub_buffer) && - /* NB: a zero width redraw clip == full stage redraw */ - stage_glx->bounding_redraw_clip.width != 0 && - /* some drivers struggle to get going and produce some junk - * frames when starting up... */ - G_LIKELY (stage_glx->frame_count > 3) && - /* While resizing a window clipped redraws are disabled to avoid - * artefacts. See clutter-event-x11.c:event_translate for a - * detailed explanation */ - G_LIKELY (stage_x11->clipped_redraws_cool_off == 0)) - { - may_use_clipped_redraw = TRUE; - } - else - may_use_clipped_redraw = FALSE; - - if (may_use_clipped_redraw && - G_LIKELY (!(clutter_paint_debug_flags & - CLUTTER_DEBUG_DISABLE_CLIPPED_REDRAWS))) - use_clipped_redraw = TRUE; - else - use_clipped_redraw = FALSE; - - if (use_clipped_redraw) - { - cogl_clip_push_window_rectangle (stage_glx->bounding_redraw_clip.x, - stage_glx->bounding_redraw_clip.y, - stage_glx->bounding_redraw_clip.width, - stage_glx->bounding_redraw_clip.height); - _clutter_stage_do_paint (stage, &stage_glx->bounding_redraw_clip); - cogl_clip_pop (); - } - else - _clutter_stage_do_paint (stage, NULL); - - if ((clutter_paint_debug_flags & CLUTTER_DEBUG_REDRAWS) && - may_use_clipped_redraw) - { - ClutterGeometry *clip = &stage_glx->bounding_redraw_clip; - static CoglMaterial *outline = NULL; - CoglHandle vbo; - float x_1 = clip->x; - float x_2 = clip->x + clip->width; - float y_1 = clip->y; - float y_2 = clip->y + clip->height; - float quad[8] = { - x_1, y_1, - x_2, y_1, - x_2, y_2, - x_1, y_2 - }; - CoglMatrix modelview; - - if (outline == NULL) - { - outline = cogl_material_new (); - cogl_material_set_color4ub (outline, 0xff, 0x00, 0x00, 0xff); - } - - vbo = cogl_vertex_buffer_new (4); - cogl_vertex_buffer_add (vbo, - "gl_Vertex", - 2, /* n_components */ - COGL_ATTRIBUTE_TYPE_FLOAT, - FALSE, /* normalized */ - 0, /* stride */ - quad); - cogl_vertex_buffer_submit (vbo); - - cogl_push_matrix (); - cogl_matrix_init_identity (&modelview); - _clutter_actor_apply_modelview_transform (CLUTTER_ACTOR (stage), - &modelview); - cogl_set_modelview_matrix (&modelview); - cogl_set_source (outline); - cogl_vertex_buffer_draw (vbo, COGL_VERTICES_MODE_LINE_LOOP, - 0 , 4); - cogl_pop_matrix (); - cogl_object_unref (vbo); - } - - cogl_flush (); - CLUTTER_TIMER_STOP (_clutter_uprof_context, painting_timer); - - drawable = stage_glx->glxwin - ? stage_glx->glxwin - : stage_x11->xwin; - - /* If we might ever use _clutter_backend_glx_blit_sub_buffer then we - * always need to keep track of the video_sync_count so that we can - * throttle blits. - * - * Note: we get the count *before* we issue any glXCopySubBuffer or - * blit_sub_buffer request in case the count would go up before - * returning control to us. - */ - if (backend_glx->can_blit_sub_buffer && backend_glx->get_video_sync) - backend_glx->get_video_sync (&video_sync_count); - - /* push on the screen */ - if (use_clipped_redraw) - { - ClutterGeometry *clip = &stage_glx->bounding_redraw_clip; - ClutterGeometry copy_area; - - CLUTTER_NOTE (BACKEND, - "_glx_blit_sub_buffer (window: 0x%lx, " - "x: %d, y: %d, " - "width: %d, height: %d)", - (unsigned long) drawable, - stage_glx->bounding_redraw_clip.x, - stage_glx->bounding_redraw_clip.y, - stage_glx->bounding_redraw_clip.width, - stage_glx->bounding_redraw_clip.height); - - /* XXX: It seems there will be a race here in that the stage - * window may be resized before glXCopySubBufferMESA is handled - * and so we may copy the wrong region. I can't really see how - * we can handle this with the current state of X but at least - * in this case a full redraw should be queued by the resize - * anyway so it should only exhibit temporary artefacts. - */ - copy_area.y = clutter_actor_get_height (CLUTTER_ACTOR (stage)) - - clip->y - - clip->height; - copy_area.x = clip->x; - copy_area.width = clip->width; - copy_area.height = clip->height; - - /* glXCopySubBufferMESA and glBlitFramebuffer are not integrated - * with the glXSwapIntervalSGI mechanism which we usually use to - * throttle the Clutter framerate to the vertical refresh and so - * we have to manually wait for the vblank period... - */ - - /* Here 'is_synchronized' only means that the blit won't cause a - * tear, ie it won't prevent multiple blits per retrace if they - * can all be performed in the blanking period. If that's the - * case then we still want to use the vblank sync menchanism but - * we only need it to throttle redraws. - */ - if (!backend_glx->blit_sub_buffer_is_synchronized) - { - /* XXX: note that glXCopySubBuffer, at least for Intel, is - * synchronized with the vblank but glBlitFramebuffer may - * not be so we use the same scheme we do when calling - * glXSwapBuffers without the swap_control extension and - * call glFinish () before waiting for the vblank period. - * - * See where we call glXSwapBuffers for more details. - */ - glFinish (); - wait_for_vblank (CLUTTER_BACKEND_GLX (backend)); - } - else if (backend_glx->get_video_sync) - { - /* If we have the GLX_SGI_video_sync extension then we can - * be a bit smarter about how we throttle blits by avoiding - * any waits if we can see that the video sync count has - * already progressed. */ - if (backend_glx->last_video_sync_count == video_sync_count) - wait_for_vblank (CLUTTER_BACKEND_GLX (backend)); - } - else - wait_for_vblank (CLUTTER_BACKEND_GLX (backend)); - - CLUTTER_TIMER_START (_clutter_uprof_context, blit_sub_buffer_timer); - _clutter_backend_glx_blit_sub_buffer (backend_glx, - drawable, - copy_area.x, - copy_area.y, - copy_area.width, - copy_area.height); - CLUTTER_TIMER_STOP (_clutter_uprof_context, blit_sub_buffer_timer); - } - else - { - CLUTTER_NOTE (BACKEND, "glXSwapBuffers (display: %p, window: 0x%lx)", - backend_x11->xdpy, - (unsigned long) drawable); - - /* If we have GLX swap buffer events then glXSwapBuffers will return - * immediately and we need to track that there is a swap in - * progress... */ - if (clutter_feature_available (CLUTTER_FEATURE_SWAP_EVENTS)) - stage_glx->pending_swaps++; - - if (backend_glx->vblank_type != CLUTTER_VBLANK_GLX_SWAP && - backend_glx->vblank_type != CLUTTER_VBLANK_NONE) - { - /* If we are going to wait for VBLANK manually, we not only - * need to flush out pending drawing to the GPU before we - * sleep, we need to wait for it to finish. Otherwise, we - * may end up with the situation: - * - * - We finish drawing - GPU drawing continues - * - We go to sleep - GPU drawing continues - * VBLANK - We call glXSwapBuffers - GPU drawing continues - * - GPU drawing continues - * - Swap buffers happens - * - * Producing a tear. Calling glFinish() first will cause us - * to properly wait for the next VBLANK before we swap. This - * obviously does not happen when we use _GLX_SWAP and let - * the driver do the right thing - */ - glFinish (); - - wait_for_vblank (CLUTTER_BACKEND_GLX (backend)); - } - - CLUTTER_TIMER_START (_clutter_uprof_context, swapbuffers_timer); - glXSwapBuffers (backend_x11->xdpy, drawable); - CLUTTER_TIMER_STOP (_clutter_uprof_context, swapbuffers_timer); - _cogl_swap_buffers_notify (); - } - - backend_glx->last_video_sync_count = video_sync_count; - - /* reset the redraw clipping for the next paint... */ - stage_glx->initialized_redraw_clip = FALSE; - - stage_glx->frame_count++; -} diff --git a/clutter/glx/clutter-stage-glx.h b/clutter/glx/clutter-stage-glx.h index 0fdf1dcf6..54b3fccc1 100644 --- a/clutter/glx/clutter-stage-glx.h +++ b/clutter/glx/clutter-stage-glx.h @@ -69,9 +69,6 @@ struct _ClutterStageGLXClass GType _clutter_stage_glx_get_type (void) G_GNUC_CONST; -void _clutter_stage_glx_redraw (ClutterStageGLX *stage_glx, - ClutterStage *stage); - G_END_DECLS #endif /* __CLUTTER_STAGE_H__ */ diff --git a/clutter/osx/clutter-backend-osx.c b/clutter/osx/clutter-backend-osx.c index e4eb32461..fe83dafe2 100644 --- a/clutter/osx/clutter-backend-osx.c +++ b/clutter/osx/clutter-backend-osx.c @@ -191,30 +191,6 @@ clutter_backend_osx_ensure_context (ClutterBackend *backend, CLUTTER_OSX_POOL_RELEASE(); } -static void -clutter_backend_osx_redraw (ClutterBackend *backend, - ClutterStage *wrapper) -{ - ClutterStageWindow *impl; - ClutterStageOSX *stage_osx; - - if (CLUTTER_ACTOR_IN_DESTRUCTION (wrapper)) - return; - - impl = _clutter_stage_get_window (wrapper); - if (impl == NULL) - return; - - stage_osx = CLUTTER_STAGE_OSX (impl); - - CLUTTER_OSX_POOL_ALLOC(); - - if (stage_osx->view != NULL) - [stage_osx->view setNeedsDisplay: YES]; - - CLUTTER_OSX_POOL_RELEASE(); -} - /*************************************************************************/ static void @@ -267,7 +243,6 @@ clutter_backend_osx_class_init (ClutterBackendOSXClass *klass) backend_class->create_context = clutter_backend_osx_create_context; backend_class->ensure_context = clutter_backend_osx_ensure_context; backend_class->init_events = clutter_backend_osx_init_events; - backend_class->redraw = clutter_backend_osx_redraw; backend_class->get_device_manager = clutter_backend_osx_get_device_manager; } diff --git a/clutter/osx/clutter-stage-osx.c b/clutter/osx/clutter-stage-osx.c index 56408dc22..ac6d68b11 100644 --- a/clutter/osx/clutter-stage-osx.c +++ b/clutter/osx/clutter-stage-osx.c @@ -523,6 +523,19 @@ clutter_stage_osx_set_accept_focus (ClutterStageWindow *stage_window, CLUTTER_OSX_POOL_RELEASE(); } +static void +clutter_stage_osx_redraw (ClutterStageWindow *stage_window) +{ + ClutterStageOSX *stage_osx = CLUTTER_STAGE_OSX (stage_window); + + CLUTTER_OSX_POOL_ALLOC(); + + if (stage_osx->view != NULL) + [stage_osx->view setNeedsDisplay: YES]; + + CLUTTER_OSX_POOL_RELEASE(); +} + static void clutter_stage_window_iface_init (ClutterStageWindowIface *iface) { @@ -538,6 +551,7 @@ clutter_stage_window_iface_init (ClutterStageWindowIface *iface) iface->set_cursor_visible = clutter_stage_osx_set_cursor_visible; iface->set_user_resizable = clutter_stage_osx_set_user_resizable; iface->set_accept_focus = clutter_stage_osx_set_accept_focus; + iface->redraw = clutter_stage_osx_redraw; } /*************************************************************************/ diff --git a/clutter/win32/clutter-backend-win32.c b/clutter/win32/clutter-backend-win32.c index 1e132d1f7..4ab3f2709 100644 --- a/clutter/win32/clutter-backend-win32.c +++ b/clutter/win32/clutter-backend-win32.c @@ -478,32 +478,6 @@ clutter_backend_win32_ensure_context (ClutterBackend *backend, } } -static void -clutter_backend_win32_redraw (ClutterBackend *backend, - ClutterStage *stage) -{ - ClutterStageWin32 *stage_win32; - ClutterStageWindow *impl; - - impl = _clutter_stage_get_window (stage); - if (impl == NULL) - return; - - g_return_if_fail (CLUTTER_IS_STAGE_WIN32 (impl)); - - stage_win32 = CLUTTER_STAGE_WIN32 (impl); - - /* this will cause the stage implementation to be painted */ - _clutter_stage_do_paint (stage, NULL); - cogl_flush (); - - if (stage_win32->client_dc) - { - SwapBuffers (stage_win32->client_dc); - _cogl_swap_buffers_notify (); - } -} - static ClutterStageWindow * clutter_backend_win32_create_stage (ClutterBackend *backend, ClutterStage *wrapper, @@ -580,7 +554,6 @@ clutter_backend_win32_class_init (ClutterBackendWin32Class *klass) backend_class->create_stage = clutter_backend_win32_create_stage; backend_class->add_options = clutter_backend_win32_add_options; backend_class->get_features = clutter_backend_win32_get_features; - backend_class->redraw = clutter_backend_win32_redraw; backend_class->create_context = clutter_backend_win32_create_context; backend_class->ensure_context = clutter_backend_win32_ensure_context; backend_class->get_device_manager = clutter_backend_win32_get_device_manager; diff --git a/clutter/win32/clutter-stage-win32.c b/clutter/win32/clutter-stage-win32.c index 6d0588b00..540c68a7f 100644 --- a/clutter/win32/clutter-stage-win32.c +++ b/clutter/win32/clutter-stage-win32.c @@ -518,6 +518,22 @@ clutter_stage_win32_unrealize (ClutterStageWindow *stage_window) clutter_stage_win32_unprepare_window (stage_win32); } +static void +clutter_stage_win32_redraw (ClutterStageWindow *stage_window) +{ + ClutterStageWin32 *stage_win32 = CLUTTER_STAGE_WIN32 (stage_window); + + /* this will cause the stage implementation to be painted */ + _clutter_stage_do_paint (stage_win32->wrapper, NULL); + cogl_flush (); + + if (stage_win32->client_dc) + { + SwapBuffers (stage_win32->client_dc); + _cogl_swap_buffers_notify (); + } +} + static void clutter_stage_win32_dispose (GObject *gobject) { @@ -575,6 +591,7 @@ clutter_stage_window_iface_init (ClutterStageWindowIface *iface) iface->get_geometry = clutter_stage_win32_get_geometry; iface->realize = clutter_stage_win32_realize; iface->unrealize = clutter_stage_win32_unrealize; + iface->redraw = clutter_stage_win32_redraw; } /**