serialize upload of asyncronously loaded textures

Rate limit the uploading of textures to stop if it uses more than 5ms
during one master clock iteration.
This commit is contained in:
pippin 2009-07-09 15:45:08 -04:00 committed by Øyvind Kolås
parent 211bf79854
commit 8fb3a48ae2

View File

@ -119,12 +119,17 @@ struct _ClutterTextureAsyncData
/* Source ID of the idle handler for loading. If this is zero then /* Source ID of the idle handler for loading. If this is zero then
the data is being loaded in a thread from the thread pool. Once the data is being loaded in a thread from the thread pool. Once
the thread is finished it will be converted to idle load handler the thread is finished it will be converted to idle load handler
and load_idle will be nonzero. If load_idle is nonzero then the and load_idle will be nonzero. If load_idle is nonzero, and
rest of the load can safely be aborted by just removing the upload_queued is FALSE then the rest of the load can safely be
source, otherwise the abort flag needs to be set and the data aborted by just removing the source, otherwise the abort flag
should be disowned */ needs to be set and the data should be disowned */
guint load_idle; guint load_idle;
/* Set when the texture is queued for GPU upload, used to determine
* what to do with the texture data when load_idle is zero.
*/
gboolean upload_queued;
gchar *load_filename; gchar *load_filename;
CoglHandle load_bitmap; CoglHandle load_bitmap;
GError *load_error; GError *load_error;
@ -160,6 +165,9 @@ enum
static int texture_signals[LAST_SIGNAL] = { 0 }; static int texture_signals[LAST_SIGNAL] = { 0 };
static GThreadPool *async_thread_pool = NULL; static GThreadPool *async_thread_pool = NULL;
static guint repaint_upload_func = 0;
static GList *upload_list = NULL;
static GStaticMutex upload_list_mutex = G_STATIC_MUTEX_INIT;
static void static void
texture_fbo_free_resources (ClutterTexture *texture); texture_fbo_free_resources (ClutterTexture *texture);
@ -647,8 +655,8 @@ clutter_texture_async_data_free (ClutterTextureAsyncData *data)
{ {
/* This function should only be called either from the main thread /* This function should only be called either from the main thread
once it is known that the load thread has completed or from the once it is known that the load thread has completed or from the
load thread itself if the abort flag is true (in which case the load thread/upload function itself if the abort flag is true (in
main thread has disowned the data) */ which case the main thread has disowned the data) */
if (data->load_filename) if (data->load_filename)
g_free (data->load_filename); g_free (data->load_filename);
@ -702,7 +710,8 @@ clutter_texture_async_load_cancel (ClutterTexture *texture)
else else
{ {
/* Otherwise we need to tell the thread to abort and disown /* Otherwise we need to tell the thread to abort and disown
the data */ the data, if the data has been loaded and decoded the data
is now waiting for a master clock iteration to be repainted */
priv->async_data->abort = TRUE; priv->async_data->abort = TRUE;
if (mutex) if (mutex)
@ -1682,6 +1691,12 @@ clutter_texture_thread_idle_func (gpointer user_data)
/* Grab the mutex so we can be sure the thread has unlocked it /* Grab the mutex so we can be sure the thread has unlocked it
before we destroy it */ before we destroy it */
g_mutex_lock (data->mutex); g_mutex_lock (data->mutex);
if (data->abort)
{
g_mutex_unlock (data->mutex);
clutter_texture_async_data_free (data);
return FALSE;
}
g_mutex_unlock (data->mutex); g_mutex_unlock (data->mutex);
clutter_texture_async_load_complete (data->texture, data->load_bitmap, clutter_texture_async_load_complete (data->texture, data->load_bitmap,
@ -1692,6 +1707,36 @@ clutter_texture_thread_idle_func (gpointer user_data)
return FALSE; return FALSE;
} }
static gboolean
clutter_texture_repaint_upload_func (gpointer user_data)
{
gulong start_time;
g_static_mutex_lock (&upload_list_mutex);
if (upload_list)
{
start_time = clutter_get_timestamp ();
do
{
ClutterTextureAsyncData *data = upload_list->data;
clutter_texture_thread_idle_func (data);
upload_list = g_list_remove (upload_list, data);
}
/* continue uploading textures as long as we havent spent more
* then 5ms doing so this stage redraw cycle.
*/
while (upload_list && clutter_get_timestamp () < start_time + 5 * 1000);
}
if (upload_list)
{
_clutter_master_clock_ensure_next_iteration (
_clutter_master_clock_get_default());
}
g_static_mutex_unlock (&upload_list_mutex);
return TRUE;
}
static void static void
clutter_texture_thread_func (gpointer user_data, gpointer pool_data) clutter_texture_thread_func (gpointer user_data, gpointer pool_data)
{ {
@ -1732,10 +1777,21 @@ clutter_texture_thread_func (gpointer user_data, gpointer pool_data)
* set it while we're holding the mutex so we can safely start the * set it while we're holding the mutex so we can safely start the
* idle handler now without the possibility of calling the * idle handler now without the possibility of calling the
* callback after it is aborted */ * callback after it is aborted */
data->load_idle = g_static_mutex_lock (&upload_list_mutex);
clutter_threads_add_idle_full (G_PRIORITY_LOW, clutter_texture_thread_idle_func, data, NULL); if (repaint_upload_func == 0)
{
repaint_upload_func = clutter_threads_add_repaint_func (
clutter_texture_repaint_upload_func,
NULL, NULL);
}
upload_list = g_list_append (upload_list, data);
data->upload_queued = TRUE;
g_static_mutex_unlock (&upload_list_mutex);
g_mutex_unlock (data->mutex); g_mutex_unlock (data->mutex);
_clutter_master_clock_ensure_next_iteration (
_clutter_master_clock_get_default());
} }
return; return;