Home | History | Annotate | Download | only in src
      1 /*
      2  INTEL CONFIDENTIAL
      3  Copyright 2009 Intel Corporation All Rights Reserved.
      4  The source code contained or described herein and all documents related to the source code ("Material") are owned by Intel Corporation or its suppliers or licensors. Title to the Material remains with Intel Corporation or its suppliers and licensors. The Material contains trade secrets and proprietary and confidential information of Intel or its suppliers and licensors. The Material is protected by worldwide copyright and trade secret laws and treaty provisions. No part of the Material may be used, copied, reproduced, modified, published, uploaded, posted, transmitted, distributed, or disclosed in any way without Intels prior express written permission.
      5 
      6  No license under any patent, copyright, trade secret or other intellectual property right is granted to or conferred upon you by disclosure or delivery of the Materials, either expressly, by implication, inducement, estoppel or otherwise. Any license under such intellectual property rights must be express and approved by Intel in writing.
      7  */
      8 
      9 /**
     10  * SECTION:mixsurfacepool
     11  * @short_description: MI-X Video Surface Pool
     12  *
     13  * A data object which stores and manipulates a pool of video surfaces.
     14  */
     15 
     16 #include "mixvideolog.h"
     17 #include "mixsurfacepool.h"
     18 #include "mixvideoframe_private.h"
     19 
     20 #define MIX_LOCK(lock) g_mutex_lock(lock);
     21 #define MIX_UNLOCK(lock) g_mutex_unlock(lock);
     22 
     23 #define SAFE_FREE(p) if(p) { g_free(p); p = NULL; }
     24 
     25 static GType _mix_surfacepool_type = 0;
     26 static MixParamsClass *parent_class = NULL;
     27 
     28 #define _do_init { _mix_surfacepool_type = g_define_type_id; }
     29 
     30 gboolean mix_surfacepool_copy(MixParams * target, const MixParams * src);
     31 MixParams *mix_surfacepool_dup(const MixParams * obj);
     32 gboolean mix_surfacepool_equal(MixParams * first, MixParams * second);
     33 static void mix_surfacepool_finalize(MixParams * obj);
     34 
     35 G_DEFINE_TYPE_WITH_CODE (MixSurfacePool, mix_surfacepool, MIX_TYPE_PARAMS,
     36 		_do_init);
     37 
     38 static void mix_surfacepool_init(MixSurfacePool * self) {
     39 	/* initialize properties here */
     40 	self->free_list = NULL;
     41 	self->in_use_list = NULL;
     42 	self->free_list_max_size = 0;
     43 	self->free_list_cur_size = 0;
     44 	self->high_water_mark = 0;
     45 
     46 	self->reserved1 = NULL;
     47 	self->reserved2 = NULL;
     48 	self->reserved3 = NULL;
     49 	self->reserved4 = NULL;
     50 
     51 	// TODO: relocate this mutex allocation -we can't communicate failure in ctor.
     52 	// Note that g_thread_init() has already been called by mix_video_init()
     53 	self->objectlock = g_mutex_new();
     54 
     55 }
     56 
     57 static void mix_surfacepool_class_init(MixSurfacePoolClass * klass) {
     58 	MixParamsClass *mixparams_class = MIX_PARAMS_CLASS(klass);
     59 
     60 	/* setup static parent class */
     61 	parent_class = (MixParamsClass *) g_type_class_peek_parent(klass);
     62 
     63 	mixparams_class->finalize = mix_surfacepool_finalize;
     64 	mixparams_class->copy = (MixParamsCopyFunction) mix_surfacepool_copy;
     65 	mixparams_class->dup = (MixParamsDupFunction) mix_surfacepool_dup;
     66 	mixparams_class->equal = (MixParamsEqualFunction) mix_surfacepool_equal;
     67 }
     68 
     69 MixSurfacePool *
     70 mix_surfacepool_new(void) {
     71 	MixSurfacePool *ret = (MixSurfacePool *) g_type_create_instance(
     72 			MIX_TYPE_SURFACEPOOL);
     73 	return ret;
     74 }
     75 
     76 void mix_surfacepool_finalize(MixParams * obj) {
     77 	/* clean up here. */
     78 
     79 	MixSurfacePool *self = MIX_SURFACEPOOL(obj);
     80 
     81 	if (self->objectlock) {
     82 		g_mutex_free(self->objectlock);
     83 		self->objectlock = NULL;
     84 	}
     85 
     86 	/* Chain up parent */
     87 	if (parent_class->finalize) {
     88 		parent_class->finalize(obj);
     89 	}
     90 }
     91 
     92 MixSurfacePool *
     93 mix_surfacepool_ref(MixSurfacePool * mix) {
     94 	return (MixSurfacePool *) mix_params_ref(MIX_PARAMS(mix));
     95 }
     96 
     97 /**
     98  * mix_surfacepool_dup:
     99  * @obj: a #MixSurfacePool object
    100  * @returns: a newly allocated duplicate of the object.
    101  *
    102  * Copy duplicate of the object.
    103  */
    104 MixParams *
    105 mix_surfacepool_dup(const MixParams * obj) {
    106 	MixParams *ret = NULL;
    107 
    108 	if (MIX_IS_SURFACEPOOL(obj)) {
    109 
    110 		MIX_LOCK(MIX_SURFACEPOOL(obj)->objectlock);
    111 
    112 		MixSurfacePool *duplicate = mix_surfacepool_new();
    113 		if (mix_surfacepool_copy(MIX_PARAMS(duplicate), MIX_PARAMS(obj))) {
    114 			ret = MIX_PARAMS(duplicate);
    115 		} else {
    116 			mix_surfacepool_unref(duplicate);
    117 		}
    118 
    119 		MIX_UNLOCK(MIX_SURFACEPOOL(obj)->objectlock);
    120 
    121 	}
    122 	return ret;
    123 }
    124 
    125 /**
    126  * mix_surfacepool_copy:
    127  * @target: copy to target
    128  * @src: copy from src
    129  * @returns: boolean indicates if copy is successful.
    130  *
    131  * Copy instance data from @src to @target.
    132  */
    133 gboolean mix_surfacepool_copy(MixParams * target, const MixParams * src) {
    134 	MixSurfacePool *this_target, *this_src;
    135 
    136 	if (MIX_IS_SURFACEPOOL(target) && MIX_IS_SURFACEPOOL(src)) {
    137 
    138 		MIX_LOCK(MIX_SURFACEPOOL(src)->objectlock);
    139 		MIX_LOCK(MIX_SURFACEPOOL(target)->objectlock);
    140 
    141 		// Cast the base object to this child object
    142 		this_target = MIX_SURFACEPOOL(target);
    143 		this_src = MIX_SURFACEPOOL(src);
    144 
    145 		// Free the existing properties
    146 
    147 		// Duplicate string
    148 		this_target->free_list = this_src->free_list;
    149 		this_target->in_use_list = this_src->in_use_list;
    150 		this_target->free_list_max_size = this_src->free_list_max_size;
    151 		this_target->free_list_cur_size = this_src->free_list_cur_size;
    152 		this_target->high_water_mark = this_src->high_water_mark;
    153 
    154 		MIX_UNLOCK(MIX_SURFACEPOOL(src)->objectlock);
    155 		MIX_UNLOCK(MIX_SURFACEPOOL(target)->objectlock);
    156 
    157 		// Now chainup base class
    158 		if (parent_class->copy) {
    159 			return parent_class->copy(MIX_PARAMS_CAST(target), MIX_PARAMS_CAST(
    160 					src));
    161 		} else {
    162 			return TRUE;
    163 		}
    164 	}
    165 	return FALSE;
    166 }
    167 
    168 /**
    169  * mix_surfacepool_equal:
    170  * @first: first object to compare
    171  * @second: seond object to compare
    172  * @returns: boolean indicates if instance are equal.
    173  *
    174  * Copy instance data from @src to @target.
    175  */
    176 gboolean mix_surfacepool_equal(MixParams * first, MixParams * second) {
    177 	gboolean ret = FALSE;
    178 	MixSurfacePool *this_first, *this_second;
    179 
    180 	if (MIX_IS_SURFACEPOOL(first) && MIX_IS_SURFACEPOOL(second)) {
    181 		// Deep compare
    182 		// Cast the base object to this child object
    183 
    184 		MIX_LOCK(MIX_SURFACEPOOL(first)->objectlock);
    185 		MIX_LOCK(MIX_SURFACEPOOL(second)->objectlock);
    186 
    187 		this_first = MIX_SURFACEPOOL(first);
    188 		this_second = MIX_SURFACEPOOL(second);
    189 
    190 		/* TODO: add comparison for other properties */
    191 		if (this_first->free_list == this_second->free_list
    192 				&& this_first->in_use_list == this_second->in_use_list
    193 				&& this_first->free_list_max_size
    194 						== this_second->free_list_max_size
    195 				&& this_first->free_list_cur_size
    196 						== this_second->free_list_cur_size
    197 				&& this_first->high_water_mark == this_second->high_water_mark) {
    198 			// members within this scope equal. chaining up.
    199 			MixParamsClass *klass = MIX_PARAMS_CLASS(parent_class);
    200 			if (klass->equal)
    201 				ret = klass->equal(first, second);
    202 			else
    203 				ret = TRUE;
    204 		}
    205 
    206 		MIX_LOCK(MIX_SURFACEPOOL(first)->objectlock);
    207 		MIX_LOCK(MIX_SURFACEPOOL(second)->objectlock);
    208 
    209 	}
    210 
    211 	return ret;
    212 }
    213 
    214 /*  Class Methods  */
    215 
    216 /**
    217  * mix_surfacepool_initialize:
    218  * @returns: MIX_RESULT_SUCCESS if successful in creating the surface pool
    219  *
    220  * Use this method to create a new surface pool, consisting of a GSList of
    221  * frame objects that represents a pool of surfaces.
    222  */
    223 MIX_RESULT mix_surfacepool_initialize(MixSurfacePool * obj,
    224 		VASurfaceID *surfaces, guint num_surfaces) {
    225 
    226 	LOG_V( "Begin\n");
    227 
    228 	if (obj == NULL || surfaces == NULL) {
    229 
    230 		LOG_E(
    231 				"Error NULL ptrs, obj %x, surfaces %x\n", (guint) obj,
    232 				(guint) surfaces);
    233 
    234 		return MIX_RESULT_NULL_PTR;
    235 	}
    236 
    237 	MIX_LOCK(obj->objectlock);
    238 
    239 	if ((obj->free_list != NULL) || (obj->in_use_list != NULL)) {
    240 		//surface pool is in use; return error; need proper cleanup
    241 		//TODO need cleanup here?
    242 
    243 		MIX_UNLOCK(obj->objectlock);
    244 
    245 		return MIX_RESULT_ALREADY_INIT;
    246 	}
    247 
    248 	if (num_surfaces == 0) {
    249 		obj->free_list = NULL;
    250 
    251 		obj->in_use_list = NULL;
    252 
    253 		obj->free_list_max_size = num_surfaces;
    254 
    255 		obj->free_list_cur_size = num_surfaces;
    256 
    257 		obj->high_water_mark = 0;
    258 
    259 		MIX_UNLOCK(obj->objectlock);
    260 
    261 		return MIX_RESULT_SUCCESS;
    262 	}
    263 
    264 	// Initialize the free pool with frame objects
    265 
    266 	gint i = 0;
    267 	MixVideoFrame *frame = NULL;
    268 
    269 	for (; i < num_surfaces; i++) {
    270 
    271 		//Create a frame object for each surface ID
    272 		frame = mix_videoframe_new();
    273 
    274 		if (frame == NULL) {
    275 			//TODO need to log an error here and do cleanup
    276 
    277 			MIX_UNLOCK(obj->objectlock);
    278 
    279 			return MIX_RESULT_NO_MEMORY;
    280 		}
    281 
    282 		// Set the frame ID to the surface ID
    283 		mix_videoframe_set_frame_id(frame, surfaces[i]);
    284 		// Set the ci frame index to the surface ID
    285 		mix_videoframe_set_ci_frame_idx (frame, i);
    286 		// Leave timestamp for each frame object as zero
    287 		// Set the pool reference in the private data of the frame object
    288 		mix_videoframe_set_pool(frame, obj);
    289 
    290 		//Add each frame object to the pool list
    291 		obj->free_list = g_slist_append(obj->free_list, frame);
    292 
    293 	}
    294 
    295 	obj->in_use_list = NULL;
    296 
    297 	obj->free_list_max_size = num_surfaces;
    298 
    299 	obj->free_list_cur_size = num_surfaces;
    300 
    301 	obj->high_water_mark = 0;
    302 
    303 	MIX_UNLOCK(obj->objectlock);
    304 
    305 	LOG_V( "End\n");
    306 
    307 	return MIX_RESULT_SUCCESS;
    308 }
    309 
    310 /**
    311  * mix_surfacepool_put:
    312  * @returns: SUCCESS or FAILURE
    313  *
    314  * Use this method to return a surface to the free pool
    315  */
    316 MIX_RESULT mix_surfacepool_put(MixSurfacePool * obj, MixVideoFrame * frame) {
    317 
    318 	LOG_V( "Begin\n");
    319 	if (obj == NULL || frame == NULL)
    320 		return MIX_RESULT_NULL_PTR;
    321 
    322 	LOG_V( "Frame id: %d\n", frame->frame_id);
    323 	MIX_LOCK(obj->objectlock);
    324 
    325 	if (obj->in_use_list == NULL) {
    326 		//in use list cannot be empty if a frame is in use
    327 		//TODO need better error code for this
    328 
    329 		MIX_UNLOCK(obj->objectlock);
    330 
    331 		return MIX_RESULT_FAIL;
    332 	}
    333 
    334 	GSList *element = g_slist_find(obj->in_use_list, frame);
    335 	if (element == NULL) {
    336 		//Integrity error; frame not found in in use list
    337 		//TODO need better error code and handling for this
    338 
    339 		MIX_UNLOCK(obj->objectlock);
    340 
    341 		return MIX_RESULT_FAIL;
    342 	} else {
    343 		//Remove this element from the in_use_list
    344 		obj->in_use_list = g_slist_remove_link(obj->in_use_list, element);
    345 
    346 		//Concat the element to the free_list and reset the timestamp of the frame
    347 		//Note that the surface ID stays valid
    348 		mix_videoframe_set_timestamp(frame, 0);
    349 		obj->free_list = g_slist_concat(obj->free_list, element);
    350 
    351 		//increment the free list count
    352 		obj->free_list_cur_size++;
    353 	}
    354 
    355 	//Note that we do nothing with the ref count for this.  We want it to
    356 	//stay at 1, which is what triggered it to be added back to the free list.
    357 
    358 	MIX_UNLOCK(obj->objectlock);
    359 
    360 	LOG_V( "End\n");
    361 	return MIX_RESULT_SUCCESS;
    362 }
    363 
    364 /**
    365  * mix_surfacepool_get:
    366  * @returns: SUCCESS or FAILURE
    367  *
    368  * Use this method to get a surface from the free pool
    369  */
    370 MIX_RESULT mix_surfacepool_get(MixSurfacePool * obj, MixVideoFrame ** frame) {
    371 
    372 	LOG_V( "Begin\n");
    373 
    374 	if (obj == NULL || frame == NULL)
    375 		return MIX_RESULT_NULL_PTR;
    376 
    377 	MIX_LOCK(obj->objectlock);
    378 
    379 #if 0
    380 	if (obj->free_list == NULL) {
    381 #else
    382 	if (obj->free_list_cur_size <= 1) {  //Keep one surface free at all times for VBLANK bug
    383 #endif
    384 		//We are out of surfaces
    385 		//TODO need to log this as well
    386 
    387 		MIX_UNLOCK(obj->objectlock);
    388 
    389 		LOG_E( "out of surfaces\n");
    390 
    391 		return MIX_RESULT_NO_MEMORY;
    392 	}
    393 
    394 	//Remove a frame from the free pool
    395 
    396 	//We just remove the one at the head, since it's convenient
    397 	GSList *element = obj->free_list;
    398 	obj->free_list = g_slist_remove_link(obj->free_list, element);
    399 	if (element == NULL) {
    400 		//Unexpected behavior
    401 		//TODO need better error code and handling for this
    402 
    403 		MIX_UNLOCK(obj->objectlock);
    404 
    405 		LOG_E( "Element is null\n");
    406 
    407 		return MIX_RESULT_FAIL;
    408 	} else {
    409 		//Concat the element to the in_use_list
    410 		obj->in_use_list = g_slist_concat(obj->in_use_list, element);
    411 
    412 		//TODO replace with proper logging
    413 
    414 		LOG_I( "frame refcount%d\n",
    415 				MIX_PARAMS(element->data)->refcount);
    416 
    417 		//Set the out frame pointer
    418 		*frame = (MixVideoFrame *) element->data;
    419 
    420 		LOG_V( "Frame id: %d\n", (*frame)->frame_id);
    421 
    422 		//decrement the free list count
    423 		obj->free_list_cur_size--;
    424 
    425 		//Check the high water mark for surface use
    426 		guint size = g_slist_length(obj->in_use_list);
    427 		if (size > obj->high_water_mark)
    428 			obj->high_water_mark = size;
    429 		//TODO Log this high water mark
    430 	}
    431 
    432 	//Increment the reference count for the frame
    433 	mix_videoframe_ref(*frame);
    434 
    435 	MIX_UNLOCK(obj->objectlock);
    436 
    437 	LOG_V( "End\n");
    438 
    439 	return MIX_RESULT_SUCCESS;
    440 }
    441 
    442 
    443 gint mixframe_compare_index (MixVideoFrame * a, MixVideoFrame * b)
    444 {
    445     if (a == NULL || b == NULL)
    446 	 return -1;
    447     if (a->ci_frame_idx == b->ci_frame_idx)
    448         return 0;
    449     else
    450         return -1;
    451 }
    452 
    453 /**
    454  * mix_surfacepool_get:
    455  * @returns: SUCCESS or FAILURE
    456  *
    457  * Use this method to get a surface from the free pool according to the CI frame idx
    458  */
    459 
    460 MIX_RESULT mix_surfacepool_get_frame_with_ci_frameidx (MixSurfacePool * obj, MixVideoFrame ** frame, MixVideoFrame *in_frame) {
    461 
    462 	LOG_V( "Begin\n");
    463 
    464 	if (obj == NULL || frame == NULL)
    465 		return MIX_RESULT_NULL_PTR;
    466 
    467 	MIX_LOCK(obj->objectlock);
    468 
    469 	if (obj->free_list == NULL) {
    470 		//We are out of surfaces
    471 		//TODO need to log this as well
    472 
    473 		MIX_UNLOCK(obj->objectlock);
    474 
    475 		LOG_E( "out of surfaces\n");
    476 
    477 		return MIX_RESULT_NO_MEMORY;
    478 	}
    479 
    480 	//Remove a frame from the free pool
    481 
    482 	//We just remove the one at the head, since it's convenient
    483 	GSList *element = g_slist_find_custom (obj->free_list, in_frame, (GCompareFunc) mixframe_compare_index);
    484 	obj->free_list = g_slist_remove_link(obj->free_list, element);
    485 	if (element == NULL) {
    486 		//Unexpected behavior
    487 		//TODO need better error code and handling for this
    488 
    489 		MIX_UNLOCK(obj->objectlock);
    490 
    491 		LOG_E( "Element is null\n");
    492 
    493 		return MIX_RESULT_FAIL;
    494 	} else {
    495 		//Concat the element to the in_use_list
    496 		obj->in_use_list = g_slist_concat(obj->in_use_list, element);
    497 
    498 		//TODO replace with proper logging
    499 
    500 		LOG_I( "frame refcount%d\n",
    501 				MIX_PARAMS(element->data)->refcount);
    502 
    503 		//Set the out frame pointer
    504 		*frame = (MixVideoFrame *) element->data;
    505 
    506 		//Check the high water mark for surface use
    507 		guint size = g_slist_length(obj->in_use_list);
    508 		if (size > obj->high_water_mark)
    509 			obj->high_water_mark = size;
    510 		//TODO Log this high water mark
    511 	}
    512 
    513 	//Increment the reference count for the frame
    514 	mix_videoframe_ref(*frame);
    515 
    516 	MIX_UNLOCK(obj->objectlock);
    517 
    518 	LOG_V( "End\n");
    519 
    520 	return MIX_RESULT_SUCCESS;
    521 }
    522 /**
    523  * mix_surfacepool_check_available:
    524  * @returns: SUCCESS or FAILURE
    525  *
    526  * Use this method to check availability of getting a surface from the free pool
    527  */
    528 MIX_RESULT mix_surfacepool_check_available(MixSurfacePool * obj) {
    529 
    530 	LOG_V( "Begin\n");
    531 
    532 	if (obj == NULL)
    533 		return MIX_RESULT_NULL_PTR;
    534 
    535 	MIX_LOCK(obj->objectlock);
    536 
    537 #if 0
    538 	if (obj->free_list == NULL) {
    539 #else
    540 	if (obj->free_list_cur_size <= 1) {  //Keep one surface free at all times for VBLANK bug
    541 #endif
    542 		//We are out of surfaces
    543 
    544 		MIX_UNLOCK(obj->objectlock);
    545 
    546 		LOG_W(
    547 				"Returning MIX_RESULT_POOLEMPTY because out of surfaces\n");
    548 
    549 		return MIX_RESULT_POOLEMPTY;
    550 	} else {
    551 		//Pool is not empty
    552 
    553 		MIX_UNLOCK(obj->objectlock);
    554 
    555 		LOG_I(
    556 				"Returning MIX_RESULT_SUCCESS because surfaces are available\n");
    557 
    558 		return MIX_RESULT_SUCCESS;
    559 	}
    560 
    561 }
    562 
    563 /**
    564  * mix_surfacepool_deinitialize:
    565  * @returns: SUCCESS or FAILURE
    566  *
    567  * Use this method to teardown a surface pool
    568  */
    569 MIX_RESULT mix_surfacepool_deinitialize(MixSurfacePool * obj) {
    570 	if (obj == NULL)
    571 		return MIX_RESULT_NULL_PTR;
    572 
    573 	MIX_LOCK(obj->objectlock);
    574 
    575 	if ((obj->in_use_list != NULL) || (g_slist_length(obj->free_list)
    576 			!= obj->free_list_max_size)) {
    577 		//TODO better error code
    578 		//We have outstanding frame objects in use and they need to be
    579 		//freed before we can deinitialize.
    580 
    581 		MIX_UNLOCK(obj->objectlock);
    582 
    583 		return MIX_RESULT_FAIL;
    584 	}
    585 
    586 	//Now remove frame objects from the list
    587 
    588 	MixVideoFrame *frame = NULL;
    589 
    590 	while (obj->free_list != NULL) {
    591 		//Get the frame object from the head of the list
    592 		frame = obj->free_list->data;
    593 		//frame = g_slist_nth_data(obj->free_list, 0);
    594 
    595 		//Release it
    596 		mix_videoframe_unref(frame);
    597 
    598 		//Delete the head node of the list and store the new head
    599 		obj->free_list = g_slist_delete_link(obj->free_list, obj->free_list);
    600 
    601 		//Repeat until empty
    602 	}
    603 
    604 	obj->free_list_max_size = 0;
    605 	obj->free_list_cur_size = 0;
    606 
    607 	//May want to log this information for tuning
    608 	obj->high_water_mark = 0;
    609 
    610 	MIX_UNLOCK(obj->objectlock);
    611 
    612 	return MIX_RESULT_SUCCESS;
    613 }
    614 
    615 #define MIX_SURFACEPOOL_SETTER_CHECK_INPUT(obj) \
    616 	if(!obj) return MIX_RESULT_NULL_PTR; \
    617 	if(!MIX_IS_SURFACEPOOL(obj)) return MIX_RESULT_FAIL; \
    618 
    619 #define MIX_SURFACEPOOL_GETTER_CHECK_INPUT(obj, prop) \
    620 	if(!obj || !prop) return MIX_RESULT_NULL_PTR; \
    621 	if(!MIX_IS_SURFACEPOOL(obj)) return MIX_RESULT_FAIL; \
    622 
    623 
    624 MIX_RESULT
    625 mix_surfacepool_dumpframe(MixVideoFrame *frame)
    626 {
    627 	LOG_I( "\tFrame %x, id %lu, refcount %d, ts %lu\n", (guint)frame,
    628 			frame->frame_id, MIX_PARAMS(frame)->refcount, (gulong) frame->timestamp);
    629 
    630 	return MIX_RESULT_SUCCESS;
    631 }
    632 
    633 MIX_RESULT
    634 mix_surfacepool_dumpprint (MixSurfacePool * obj)
    635 {
    636 	//TODO replace this with proper logging later
    637 
    638 	LOG_I( "SURFACE POOL DUMP:\n");
    639 	LOG_I( "Free list size is %d\n", obj->free_list_cur_size);
    640 	LOG_I( "In use list size is %d\n", g_slist_length(obj->in_use_list));
    641 	LOG_I( "High water mark is %lu\n", obj->high_water_mark);
    642 
    643 	//Walk the free list and report the contents
    644 	LOG_I( "Free list contents:\n");
    645 	g_slist_foreach(obj->free_list, (GFunc) mix_surfacepool_dumpframe, NULL);
    646 
    647 	//Walk the in_use list and report the contents
    648 	LOG_I( "In Use list contents:\n");
    649 	g_slist_foreach(obj->in_use_list, (GFunc) mix_surfacepool_dumpframe, NULL);
    650 
    651 	return MIX_RESULT_SUCCESS;
    652 }
    653