/* * Copyright (C) 2007,2008,2009,2010,2011 Intel Corporation. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . * Authors: * Matthew Allum * Robert Bragg * Neil Roberts * Emmanuele Bassi */ #include "config.h" #include "meta-stage-view-private.h" typedef struct _MetaStageViewPrivate { /* Damage history, in stage view render target framebuffer coordinate space. */ ClutterDamageHistory *damage_history; guint notify_presented_handle_id; CoglFrameClosure *frame_cb_closure; } MetaStageViewPrivate; G_DEFINE_TYPE_WITH_PRIVATE (MetaStageView, meta_stage_view, CLUTTER_TYPE_STAGE_VIEW) static void frame_cb (CoglOnscreen *onscreen, CoglFrameEvent frame_event, CoglFrameInfo *frame_info, void *user_data) { ClutterStageView *view = user_data; if (frame_event == COGL_FRAME_EVENT_SYNC) return; if (cogl_frame_info_get_is_symbolic (frame_info)) { clutter_stage_view_notify_ready (view); } else { ClutterFrameInfo clutter_frame_info; ClutterFrameInfoFlag flags = CLUTTER_FRAME_INFO_FLAG_NONE; if (cogl_frame_info_is_hw_clock (frame_info)) flags |= CLUTTER_FRAME_INFO_FLAG_HW_CLOCK; if (cogl_frame_info_is_zero_copy (frame_info)) flags |= CLUTTER_FRAME_INFO_FLAG_ZERO_COPY; if (cogl_frame_info_is_vsync (frame_info)) flags |= CLUTTER_FRAME_INFO_FLAG_VSYNC; clutter_frame_info = (ClutterFrameInfo) { .frame_counter = cogl_frame_info_get_global_frame_counter (frame_info), .refresh_rate = cogl_frame_info_get_refresh_rate (frame_info), .presentation_time = cogl_frame_info_get_presentation_time_us (frame_info), .flags = flags, .sequence = cogl_frame_info_get_sequence (frame_info), .gpu_rendering_duration_ns = cogl_frame_info_get_rendering_duration_ns (frame_info), .cpu_time_before_buffer_swap_us = cogl_frame_info_get_time_before_buffer_swap_us (frame_info), }; clutter_stage_view_notify_presented (view, &clutter_frame_info); } } static void meta_stage_view_dispose (GObject *object) { MetaStageView *view = META_STAGE_VIEW (object); MetaStageViewPrivate *priv = meta_stage_view_get_instance_private (view); ClutterStageView *stage_view = CLUTTER_STAGE_VIEW (view); g_clear_handle_id (&priv->notify_presented_handle_id, g_source_remove); g_clear_pointer (&priv->damage_history, clutter_damage_history_free); if (priv->frame_cb_closure) { CoglFramebuffer *framebuffer; framebuffer = clutter_stage_view_get_onscreen (stage_view); cogl_onscreen_remove_frame_callback (COGL_ONSCREEN (framebuffer), priv->frame_cb_closure); priv->frame_cb_closure = NULL; } G_OBJECT_CLASS (meta_stage_view_parent_class)->dispose (object); } static void meta_stage_view_constructed (GObject *object) { MetaStageView *view = META_STAGE_VIEW (object); MetaStageViewPrivate *priv = meta_stage_view_get_instance_private (view); ClutterStageView *stage_view = CLUTTER_STAGE_VIEW (view); CoglFramebuffer *framebuffer; framebuffer = clutter_stage_view_get_onscreen (stage_view); if (framebuffer && COGL_IS_ONSCREEN (framebuffer)) { priv->frame_cb_closure = cogl_onscreen_add_frame_callback (COGL_ONSCREEN (framebuffer), frame_cb, view, NULL); } G_OBJECT_CLASS (meta_stage_view_parent_class)->constructed (object); } static void meta_stage_view_init (MetaStageView *view) { MetaStageViewPrivate *priv = meta_stage_view_get_instance_private (view); priv->damage_history = clutter_damage_history_new (); } static void meta_stage_view_class_init (MetaStageViewClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->constructed = meta_stage_view_constructed; object_class->dispose = meta_stage_view_dispose; } ClutterDamageHistory * meta_stage_view_get_damage_history (MetaStageView *view) { MetaStageViewPrivate *priv = meta_stage_view_get_instance_private (view); return priv->damage_history; } typedef struct _NotifyPresentedClosure { ClutterStageView *view; ClutterFrameInfo frame_info; } NotifyPresentedClosure; static gboolean notify_presented_idle (gpointer user_data) { NotifyPresentedClosure *closure = user_data; MetaStageView *view = META_STAGE_VIEW (closure->view); MetaStageViewPrivate *priv = meta_stage_view_get_instance_private (view); priv->notify_presented_handle_id = 0; clutter_stage_view_notify_presented (closure->view, &closure->frame_info); return G_SOURCE_REMOVE; } void meta_stage_view_perform_fake_swap (MetaStageView *view, int64_t counter) { ClutterStageView *clutter_view = CLUTTER_STAGE_VIEW (view); MetaStageViewPrivate *priv = meta_stage_view_get_instance_private (view); NotifyPresentedClosure *closure; closure = g_new0 (NotifyPresentedClosure, 1); closure->view = clutter_view; closure->frame_info = (ClutterFrameInfo) { .frame_counter = counter, .refresh_rate = clutter_stage_view_get_refresh_rate (clutter_view), .presentation_time = g_get_monotonic_time (), .flags = CLUTTER_FRAME_INFO_FLAG_NONE, .sequence = 0, }; g_warn_if_fail (priv->notify_presented_handle_id == 0); priv->notify_presented_handle_id = g_idle_add_full (G_PRIORITY_DEFAULT, notify_presented_idle, closure, g_free); }