3
0
mirror of https://github.com/Qortal/Brooklyn.git synced 2025-02-12 02:05:54 +00:00

2598 lines
80 KiB
C
Raw Blame History

/*
Copyright (c) 2012, Broadcom Europe Ltd
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#define VCOS_VERIFY_BKPTS 1
#define VCOS_LOG_CATEGORY (&log_cat)
#include <stdlib.h>
#include <stddef.h>
#include "interface/khronos/include/WF/wfc.h"
#include "interface/khronos/wf/wfc_client_stream.h"
#include "interface/khronos/wf/wfc_server_api.h"
//#define WFC_FULL_LOGGING
#ifdef WFC_FULL_LOGGING
#define WFC_LOG_LEVEL VCOS_LOG_TRACE
#else
#define WFC_LOG_LEVEL VCOS_LOG_WARN
#endif
//==============================================================================
//!@name
//! Values used in wfcEnumerateDevices().
//!@{
#define WFC_NUM_OF_DEVICES 1
#define WFC_OUR_DEVICE_ID 1
//!@}
//!@name
//! Global mutex
//!@{
#define WFC_LOCK() do {vcos_mutex_lock(&wfc_client_state.mutex);} while (0)
#define WFC_UNLOCK() do {vcos_mutex_unlock(&wfc_client_state.mutex);} while (0)
//!@}
//!@name
//! Values for wfc_source_or_mask_create()
//!@{
#define WFC_IS_SOURCE 1
#define WFC_IS_MASK 0
//!@}
//==============================================================================
//! Simple doubly-linked list.
typedef struct _WFC_LINK
{
struct _WFC_LINK *prev;
struct _WFC_LINK *next;
} WFC_LINK_T;
//! Function pointer type, used when iterating through the linked list in wfc_link_iterate().
typedef void (*WFC_LINK_CALLBACK_T)(WFC_LINK_T *link, void *arg);
//------------------------------------------------------------------------------
//! WF-C device
typedef struct
{
WFCErrorCode error; //!< Error code returned by wfcGetError().
WFC_LINK_T contexts; //!< Contexts belonging to this device.
} WFC_DEVICE_T;
#define DEVICE_POOL_COUNT 4
#define DEVICE_POOL_MAX_SUBPOOLS 4
//! WFCDevice handle modifier
#define WFC_DEVICE_MOD 0xD0000000
//! WF-C context
typedef struct
{
WFC_LINK_T link; //!< Handle of this context within the contexts list.
WFC_DEVICE_T *device_ptr; //!< Parent device
WFC_LINK_T sources; //!< List of sources belonging to this context
WFC_LINK_T masks; //!< List of masks belonging to this context
WFCNativeStreamType output_stream; //!< For off-screen contexts only, stream to compose into.
WFC_LINK_T elements_not_in_scene; //!< List of elements belonging to this context, but not on screen.
WFC_LINK_T elements_in_scene; //!< List of elements belonging to this context and on screen.
bool active; //!< True if this context has had autonomous composition enabled with wfcActivate().
WFC_CONTEXT_STATIC_ATTRIB_T static_attributes; //!< Attributes associated with the context which are fixed on creation.
WFC_CONTEXT_DYNAMIC_ATTRIB_T dynamic_attributes;//!< Attributes associated with the context which may change.
uint32_t commit_count; //!< Count of commits made
WFC_SCENE_T committed_scene; //!< Last committed scene
} WFC_CONTEXT_T;
#define CONTEXT_POOL_COUNT 4
#define CONTEXT_POOL_MAX_SUBPOOLS 4
//! WFCContext handle modifier
#define WFC_CONTEXT_MOD 0xC0000000
//! WF-C image provider (source or mask)
typedef struct
{
WFC_LINK_T link; //!< Handle of this source/mask within the source/mask list.
bool is_source; //!< Indicates if this is a source or a mask.
WFC_CONTEXT_T *context_ptr; //!< Parent context
//!@brief Number of elements using this source/mask.
//! Required to ensure that it won't be destroyed while it's still in use.
uint32_t refcount;
WFCNativeStreamType stream; //!< Stream associated with this source/mask.
//!@brief Destruction requested.
//! Indicates that the source/mask will be destroyed at the earliest opportunity.
bool destroy_pending;
} WFC_SOURCE_OR_MASK_T;
#define SOURCE_POOL_COUNT 16
#define SOURCE_POOL_MAX_SUBPOOLS 8
//! WFCSource handle modifier
#define WFC_SOURCE_MOD 0x50000000
//! WF-C element
typedef struct
{
WFC_LINK_T link; //!< Handle of this element within the element list.
WFC_CONTEXT_T *context_ptr; //!< Parent context.
WFC_SOURCE_OR_MASK_T *source_ptr; //!< Source associated with this element.
WFC_SOURCE_OR_MASK_T *mask_ptr; //!< Mask associated with this element.
bool is_in_scene; //!< Indicates if this element is within the scene.
WFC_ELEMENT_ATTRIB_T attributes; //!< Element attributes.
} WFC_ELEMENT_T;
#define ELEMENT_POOL_COUNT 16
#define ELEMENT_POOL_MAX_SUBPOOLS 8
//! WFCElement handle modifier
#define WFC_ELEMENT_MOD 0xE0000000
//! Global state
typedef struct
{
bool is_initialised; //!< Set the first time wfcCreateDevice() is called.
VCOS_MUTEX_T mutex; //!< Global mutex.
VCOS_UNSIGNED handle_mod; //!< Process specific handle modifier
VCOS_BLOCKPOOL_T device_pool; //!< Devices allocated by this process
VCOS_BLOCKPOOL_T context_pool; //!< Contexts allocated by this process
VCOS_BLOCKPOOL_T element_pool; //!< Elements allocated by this process
VCOS_BLOCKPOOL_T source_pool; //!< Sources allocated by this process
} WFC_CLIENT_STATE_T;
//! Blockpool information for initialisation
typedef struct WFC_BLOCKPOOL_INFO_tag
{
VCOS_BLOCKPOOL_T *pool;
VCOS_UNSIGNED size;
VCOS_UNSIGNED count;
VCOS_UNSIGNED max_subpools;
const char *name;
} WFC_BLOCKPOOL_INFO_T;
//==============================================================================
static VCOS_ONCE_T wfc_client_once; //!< For initialisation
static WFC_CLIENT_STATE_T wfc_client_state; //!< Global state
//! Initialisation data for the client blockpools
static const WFC_BLOCKPOOL_INFO_T wfc_client_blockpool_info[] = {
{ &wfc_client_state.device_pool, sizeof(WFC_DEVICE_T), DEVICE_POOL_COUNT, DEVICE_POOL_MAX_SUBPOOLS, "WFC device pool" },
{ &wfc_client_state.context_pool, sizeof(WFC_CONTEXT_T), CONTEXT_POOL_COUNT, CONTEXT_POOL_MAX_SUBPOOLS, "WFC context pool" },
{ &wfc_client_state.element_pool, sizeof(WFC_ELEMENT_T), ELEMENT_POOL_COUNT, ELEMENT_POOL_MAX_SUBPOOLS, "WFC element pool" },
{ &wfc_client_state.source_pool, sizeof(WFC_SOURCE_OR_MASK_T), SOURCE_POOL_COUNT, SOURCE_POOL_MAX_SUBPOOLS, "WFC source pool" },
};
static VCOS_LOG_CAT_T log_cat = VCOS_LOG_INIT("wfc_client_func", WFC_LOG_LEVEL);
//==============================================================================
//!@name Static functions
//!@{
static void wfc_initialise_client_state(void);
static WFC_DEVICE_T *wfc_device_from_handle(WFCDevice dev);
static WFCDevice wfc_device_to_handle(WFC_DEVICE_T *device_ptr);
static WFC_CONTEXT_T *wfc_context_from_handle(WFCContext ctx);
static WFCContext wfc_context_to_handle(WFC_CONTEXT_T *context_ptr);
static WFC_ELEMENT_T *wfc_element_from_handle(WFCElement element);
static WFCElement wfc_element_to_handle(WFC_ELEMENT_T *element_ptr);
static WFCElement wfc_element_link_to_handle(WFC_LINK_T *element_link_ptr);
static WFC_SOURCE_OR_MASK_T *wfc_source_or_mask_from_handle(WFCHandle source_or_mask);
static WFCHandle wfc_source_or_mask_to_handle(WFC_SOURCE_OR_MASK_T *source_or_mask_ptr);
static WFC_CONTEXT_T *wfc_context_create
(WFC_DEVICE_T *device_ptr, WFCContextType context_type,
uint32_t screen_or_stream_num, WFCErrorCode *error);
static void wfc_context_destroy(WFC_CONTEXT_T *context_ptr);
static WFCHandle wfc_source_or_mask_create(bool is_source, WFCDevice dev, WFCContext ctx,
WFCNativeStreamType stream, const WFCint *attribList);
static void wfc_source_or_mask_destroy(WFCDevice dev, WFCHandle source_or_mask);
static void wfc_source_or_mask_acquire(WFC_SOURCE_OR_MASK_T *source_or_mask_ptr);
static void wfc_source_or_mask_release(WFC_SOURCE_OR_MASK_T *source_or_mask_ptr);
static void wfc_element_destroy(WFC_ELEMENT_T *element_ptr, void *unused);
static void wfc_commit_iterator(WFC_ELEMENT_T *element_ptr, WFC_SCENE_T *scene);
static void wfc_set_error_with_location(WFC_DEVICE_T *device, WFCErrorCode error, const char *func, int line);
static bool wfc_check_no_attribs(const WFCint *attribList);
static bool wfc_is_rotation(WFCint value);
static bool wfc_is_scale_filter(WFCint value);
static bool wfc_are_transparency_types(WFCint value);
static int32_t wfc_round(float f);
static void wfc_link_detach(WFC_LINK_T *link);
static void wfc_link_attach(WFC_LINK_T *link, WFC_LINK_T *prev);
static void wfc_link_init_null(WFC_LINK_T *link);
static void wfc_link_init_empty(WFC_LINK_T *link);
static void wfc_link_iterate(WFC_LINK_T *link, WFC_LINK_CALLBACK_T func, void *arg);
static void wfc_source_or_mask_destroy_actual
(WFC_SOURCE_OR_MASK_T *source_or_mask_ptr, void *unused);
static void wfc_client_scene_taken_cb(void *cb_data);
static void wfc_client_wait_for_scene_taken(VCOS_SEMAPHORE_T *wait_sem, WFCContext ctx,
const char *calling_function);
#define wfc_set_error(D, E) wfc_set_error_with_location(D, E, __FILE__, __LINE__)
//!@} // (Static functions)
//!@name OpenWF-C API functions
//! Refer to the <a href="http://www.khronos.org/registry/wf/">OpenWF-C specification</a> for details.
//!@{
//==============================================================================
// Device functions
WFC_API_CALL WFCint WFC_APIENTRY
wfcEnumerateDevices(WFCint *deviceIds, WFCint deviceIdsCount,
const WFCint *filterList) WFC_APIEXIT
{
bool filters_valid = true;
// Check for valid filter list. Somewhat redundant, as there is only one device,
// and it supports all screens.
if(filterList != NULL)
{
filters_valid &= (*filterList == WFC_DEVICE_FILTER_SCREEN_NUMBER);
filterList++;
filters_valid &= ((*filterList >= 0) && (*filterList <= WFC_ID_MAX_SCREENS));
filterList++;
filters_valid &= (*filterList == WFC_NONE);
} // if
if(vcos_verify(filters_valid))
{
if(deviceIds != NULL)
{
if(deviceIdsCount > 0)
{
*deviceIds = WFC_OUR_DEVICE_ID;
return WFC_NUM_OF_DEVICES;
} // if
else
{return 0;}
} // if
else
{return WFC_NUM_OF_DEVICES;}
} // if
return 0;
} // wfcEnumerateDevices()
//------------------------------------------------------------------------------
WFC_API_CALL WFCDevice WFC_APIENTRY
wfcCreateDevice(WFCint deviceId, const WFCint *attribList) WFC_APIEXIT
{
WFCDevice result = WFC_INVALID_HANDLE;
// This function will be called before anything else can be created, so is
// a good place to initialise the state.
vcos_once(&wfc_client_once, wfc_initialise_client_state);
if (!wfc_client_state.is_initialised)
return WFC_INVALID_HANDLE;
WFC_LOCK();
if ((deviceId == WFC_DEFAULT_DEVICE_ID || deviceId == WFC_OUR_DEVICE_ID)
&& wfc_check_no_attribs(attribList))
{
WFC_DEVICE_T *device = vcos_blockpool_calloc(&wfc_client_state.device_pool);
if(vcos_verify(device != NULL))
{
if (wfc_server_connect() != VCOS_SUCCESS)
{
vcos_blockpool_free(device);
vcos_log_error("%s: failed to connect to server", VCOS_FUNCTION);
}
else
{
device->error = WFC_ERROR_NONE;
wfc_link_init_empty(&device->contexts);
result = wfc_device_to_handle(device);
}
} // if
} // if
WFC_UNLOCK();
return result;
} // wfcCreateDevice()
//------------------------------------------------------------------------------
WFC_API_CALL WFCErrorCode WFC_APIENTRY
wfcGetError(WFCDevice dev) WFC_APIEXIT
{
WFCErrorCode result;
WFC_LOCK();
WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
if(vcos_verify(device_ptr != NULL))
{
result = device_ptr->error;
device_ptr->error = WFC_ERROR_NONE;
} // if
else
{result = WFC_ERROR_BAD_DEVICE;}
WFC_UNLOCK();
return result;
} // wfcGetError()
//------------------------------------------------------------------------------
WFC_API_CALL WFCint WFC_APIENTRY
wfcGetDeviceAttribi(WFCDevice dev, WFCDeviceAttrib attrib) WFC_APIEXIT
{
WFC_LOCK();
WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
if (!vcos_verify(device_ptr != NULL))
{
// Behaviour is unspecified if dev is null, so do something sensible.
vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
WFC_UNLOCK();
return 0;
}
WFCint result = 0;
switch (attrib)
{
case WFC_DEVICE_CLASS:
result = WFC_DEVICE_CLASS_FULLY_CAPABLE;
break;
case WFC_DEVICE_ID:
result = WFC_OUR_DEVICE_ID;
break;
default:
wfc_set_error(device_ptr, WFC_ERROR_BAD_ATTRIBUTE);
} // switch
WFC_UNLOCK();
return result;
} // wfcGetDeviceAttribi()
//------------------------------------------------------------------------------
WFC_API_CALL WFCErrorCode WFC_APIENTRY
wfcDestroyDevice(WFCDevice dev) WFC_APIEXIT
{
WFCErrorCode result;
WFC_LOCK();
WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
if(vcos_verify(device_ptr != NULL))
{
// Destroy all of the contexts associated with the device. This will in turn
// destroy all of the sources, masks and elements associated with each context.
wfc_link_iterate(&device_ptr->contexts, (WFC_LINK_CALLBACK_T) wfc_context_destroy, NULL);
vcos_blockpool_free(device_ptr);
wfc_server_disconnect();
result = WFC_ERROR_NONE;
} // if
else
{result = WFC_ERROR_BAD_DEVICE;}
WFC_UNLOCK();
return result;
} // wfcDestroyDevice()
//==============================================================================
// Context functions
WFC_API_CALL WFCContext WFC_APIENTRY
wfcCreateOnScreenContext(WFCDevice dev,
WFCint screenNumber,
const WFCint *attribList) WFC_APIEXIT
{
WFC_LOCK();
WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
if (!vcos_verify(device_ptr != NULL))
{
vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
WFC_UNLOCK();
return WFC_INVALID_HANDLE;
}
WFCContext context = WFC_INVALID_HANDLE;
if (screenNumber < 0 || screenNumber >= WFC_ID_MAX_SCREENS)
{wfc_set_error(device_ptr, WFC_ERROR_UNSUPPORTED);}
else if (!wfc_check_no_attribs(attribList))
{wfc_set_error(device_ptr, WFC_ERROR_BAD_ATTRIBUTE);}
else
{
WFC_CONTEXT_T *context_ptr;
WFCErrorCode error;
// Create on-screen context_ptr
context_ptr = wfc_context_create
(device_ptr, WFC_CONTEXT_TYPE_ON_SCREEN, screenNumber, &error);
// Insert new context_ptr into list of contexts
if(context_ptr)
{
wfc_link_attach(&context_ptr->link, &device_ptr->contexts);
context = wfc_context_to_handle(context_ptr);
} // if
else
{wfc_set_error(device_ptr, error);}
} // else
WFC_UNLOCK();
return context;
} // wfcCreateOnScreenContext()
//------------------------------------------------------------------------------
WFC_API_CALL WFCContext WFC_APIENTRY
wfcCreateOffScreenContext(WFCDevice dev,
WFCNativeStreamType stream,
const WFCint *attribList) WFC_APIEXIT
{
WFC_LOCK();
WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
if (!vcos_verify(device_ptr != NULL))
{
vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
WFC_UNLOCK();
return WFC_INVALID_HANDLE;
}
WFCContext context = WFC_INVALID_HANDLE;
if(stream == WFC_INVALID_HANDLE)
{wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);}
else if(wfc_stream_used_for_off_screen(stream))
{wfc_set_error(device_ptr, WFC_ERROR_IN_USE);}
else if (!wfc_check_no_attribs(attribList))
{wfc_set_error(device_ptr, WFC_ERROR_BAD_ATTRIBUTE);}
else
{
WFC_CONTEXT_T *context_ptr;
WFCErrorCode error;
// Create on-screen context_ptr
context_ptr = wfc_context_create
(device_ptr, WFC_CONTEXT_TYPE_OFF_SCREEN, stream, &error);
// Insert new context_ptr into list of contexts
if(context_ptr)
{
wfc_link_attach(&context_ptr->link, &device_ptr->contexts);
context = wfc_context_to_handle(context_ptr);
wfc_stream_register_off_screen(stream, true);
} // if
else
{wfc_set_error(device_ptr, error);}
} // else
WFC_UNLOCK();
return context;
} // wfcCreateOffScreenContext()
//------------------------------------------------------------------------------
WFC_API_CALL void WFC_APIENTRY
wfcCommit(WFCDevice dev, WFCContext ctx, WFCboolean wait) WFC_APIEXIT
{
WFC_LOCK();
WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
WFC_CONTEXT_T *context_ptr = wfc_context_from_handle(ctx);
VCOS_STATUS_T status = VCOS_ENOSYS;
VCOS_SEMAPHORE_T wait_sem;
WFCboolean wait_for_sem = WFC_FALSE;
if (!vcos_verify(device_ptr != NULL))
{
vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
WFC_UNLOCK();
return;
}
// Send data for all elements
if(vcos_verify((context_ptr != NULL) && (context_ptr->device_ptr == device_ptr)))
{
WFC_SCENE_T *scene = &context_ptr->committed_scene;
memset(scene, 0, sizeof(*scene));
// Store scene in committed_scene structure
memcpy(&scene->context, &context_ptr->dynamic_attributes, sizeof(WFC_CONTEXT_DYNAMIC_ATTRIB_T));
scene->element_count = 0;
scene->commit_count = context_ptr->commit_count++;
wfc_link_iterate(&context_ptr->elements_in_scene,
(WFC_LINK_CALLBACK_T) wfc_commit_iterator, scene);
vcos_log_info("%s: dev 0x%X, ctx 0x%X commit %u", VCOS_FUNCTION, dev, ctx, context_ptr->committed_scene.commit_count);
if (context_ptr->active)
{
uint32_t commit_flags = WFC_SERVER_COMMIT_COMPOSE;
if (wait)
{
commit_flags |= WFC_SERVER_COMMIT_WAIT;
// Long running operation, so keep VC alive until it completes.
wfc_server_use_keep_alive();
status = vcos_semaphore_create(&wait_sem, "WFC commit", 0);
vcos_assert(status == VCOS_SUCCESS); // On platforms we care about.
wait_for_sem = WFC_TRUE;
do
{
status = wfc_server_commit_scene(ctx, &context_ptr->committed_scene,
commit_flags, wfc_client_scene_taken_cb, &wait_sem);
if (status == VCOS_EAGAIN)
{
// Another thread is competing for access to the context, so
// wait a little and try again.
vcos_sleep(1);
}
}
while (status == VCOS_EAGAIN);
if (status != VCOS_SUCCESS)
{
wait_for_sem = WFC_FALSE;
wfc_server_release_keep_alive();
vcos_semaphore_delete(&wait_sem);
}
}
else
{
status = wfc_server_commit_scene(ctx, &context_ptr->committed_scene,
commit_flags, NULL, NULL);
}
if (status != VCOS_SUCCESS)
{
vcos_log_info("%s: failed to compose scene: %d", VCOS_FUNCTION, status);
wfc_set_error(device_ptr, WFC_ERROR_BUSY);
}
}
} // if
else
{wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);}
WFC_UNLOCK();
// Wait for the scene to be taken outside the lock
if (wait_for_sem)
{
wfc_client_wait_for_scene_taken(&wait_sem, ctx, VCOS_FUNCTION);
}
vcos_log_trace("%s: complete", VCOS_FUNCTION);
} // wfcCommit()
//------------------------------------------------------------------------------
WFC_API_CALL WFCint WFC_APIENTRY
wfcGetContextAttribi(WFCDevice dev, WFCContext ctx,
WFCContextAttrib attrib) WFC_APIEXIT
{
WFC_LOCK();
WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
WFC_CONTEXT_T *context_ptr = wfc_context_from_handle(ctx);
WFCint result = 0;
if (!vcos_verify(device_ptr != NULL))
{
vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
WFC_UNLOCK();
return result;
}
if(vcos_verify((context_ptr != NULL) && (context_ptr->device_ptr == device_ptr)))
{
switch (attrib)
{
case WFC_CONTEXT_TYPE:
result = context_ptr->static_attributes.type;
break;
case WFC_CONTEXT_TARGET_WIDTH:
result = context_ptr->static_attributes.width;
break;
case WFC_CONTEXT_TARGET_HEIGHT:
result = context_ptr->static_attributes.height;
break;
case WFC_CONTEXT_LOWEST_ELEMENT:
{
WFC_LINK_T *first = &context_ptr->elements_in_scene;
WFC_LINK_T *current = first;
if(first->next == first)
{
// List is empty.
result = WFC_INVALID_HANDLE;
} // if
else
{
// First element in list is the lowest.
result = (WFCint) wfc_element_link_to_handle(current->next);
} // else
break;
}
case WFC_CONTEXT_ROTATION:
result = context_ptr->dynamic_attributes.rotation;
break;
case WFC_CONTEXT_BG_COLOR:
result = (WFCint) (context_ptr->dynamic_attributes.background_clr[WFC_BG_CLR_RED] * 255.0f) << 24 |
(WFCint) (context_ptr->dynamic_attributes.background_clr[WFC_BG_CLR_GREEN] * 255.0f) << 16 |
(WFCint) (context_ptr->dynamic_attributes.background_clr[WFC_BG_CLR_BLUE] * 255.0f) << 8 |
(WFCint) (context_ptr->dynamic_attributes.background_clr[WFC_BG_CLR_ALPHA] * 255.0f);
break;
default:
wfc_set_error(device_ptr, WFC_ERROR_BAD_ATTRIBUTE);
break;
} // switch
} // if
else
{wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);}
WFC_UNLOCK();
return result;
} // wfcGetContextAttribi()
//------------------------------------------------------------------------------
WFC_API_CALL void WFC_APIENTRY
wfcGetContextAttribfv(WFCDevice dev, WFCContext ctx,
WFCContextAttrib attrib, WFCint count, WFCfloat *values) WFC_APIEXIT
{
WFC_LOCK();
WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
WFC_CONTEXT_T *context_ptr = wfc_context_from_handle(ctx);
if (!vcos_verify(device_ptr != NULL))
{
vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
WFC_UNLOCK();
return;
}
if(vcos_verify((context_ptr != NULL) && (context_ptr->device_ptr == device_ptr)))
{
uint32_t i;
switch (attrib)
{
case WFC_CONTEXT_BG_COLOR:
if(vcos_verify(values != NULL) &&
vcos_verify(((uint32_t) values & 0x3) == 0) &&
vcos_verify(count == WFC_BG_CLR_SIZE))
{
for (i = 0; i < WFC_BG_CLR_SIZE; i++)
{values[i] = context_ptr->dynamic_attributes.background_clr[i];}
} // if
else
{wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);}
break;
default:
wfc_set_error(device_ptr, WFC_ERROR_BAD_ATTRIBUTE);
break;
} // switch
}
else
{wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);}
WFC_UNLOCK();
} // wfcGetContextAttribfv()
//------------------------------------------------------------------------------
WFC_API_CALL void WFC_APIENTRY
wfcSetContextAttribi(WFCDevice dev, WFCContext ctx,
WFCContextAttrib attrib, WFCint value) WFC_APIEXIT
{
WFC_LOCK();
WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
WFC_CONTEXT_T *context_ptr = wfc_context_from_handle(ctx);
if (!vcos_verify(device_ptr != NULL))
{
vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
WFC_UNLOCK();
return;
}
if(vcos_verify((context_ptr != NULL) && (context_ptr->device_ptr == device_ptr)))
{
switch(attrib)
{
case WFC_CONTEXT_ROTATION:
if(wfc_is_rotation(value))
{context_ptr->dynamic_attributes.rotation = value;}
else
{wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);}
break;
case WFC_CONTEXT_BG_COLOR:
{
int32_t i;
for(i = WFC_BG_CLR_SIZE - 1; i >= 0; i--)
{
context_ptr->dynamic_attributes.background_clr[i]
= ((float) (value & 0xff)) / 255.0f;
value >>= 8;
} // for
break;
}
default:
wfc_set_error(device_ptr, WFC_ERROR_BAD_ATTRIBUTE);
break;
} // switch
} // if
else
{wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);}
WFC_UNLOCK();
} // wfcSetContextAttribi()
//------------------------------------------------------------------------------
WFC_API_CALL void WFC_APIENTRY
wfcSetContextAttribfv(WFCDevice dev, WFCContext ctx,
WFCContextAttrib attrib,
WFCint count, const WFCfloat *values) WFC_APIEXIT
{
WFC_LOCK();
WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
WFC_CONTEXT_T *context_ptr = wfc_context_from_handle(ctx);
if (!vcos_verify(device_ptr != NULL))
{
vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
WFC_UNLOCK();
return;
}
if(vcos_verify((context_ptr != NULL) && (context_ptr->device_ptr == device_ptr)))
{
int i;
switch (attrib)
{
case WFC_CONTEXT_BG_COLOR:
if(vcos_verify((values != NULL) && (((uint32_t) values & 0x3) == 0)
&& (count == WFC_BG_CLR_SIZE)))
{
for (i = 0; i < WFC_BG_CLR_SIZE; i++)
{context_ptr->dynamic_attributes.background_clr[i] = values[i];}
} // if
else
{wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);}
break;
default:
wfc_set_error(device_ptr, WFC_ERROR_BAD_ATTRIBUTE);
break;
} // switch
} // if
else
{wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);}
WFC_UNLOCK();
} // wfcSetContextAttribfv()
//------------------------------------------------------------------------------
WFC_API_CALL void WFC_APIENTRY
wfcDestroyContext(WFCDevice dev, WFCContext ctx) WFC_APIEXIT
{
WFC_LOCK();
WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
WFC_CONTEXT_T *context_ptr = wfc_context_from_handle(ctx);
vcos_log_trace("%s: context = 0x%X", VCOS_FUNCTION, ctx);
if (!vcos_verify(device_ptr != NULL))
{
vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
WFC_UNLOCK();
return;
}
if(vcos_verify((context_ptr != NULL) && (context_ptr->device_ptr == device_ptr)))
{
wfc_context_destroy(context_ptr);
}
else
{wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);}
WFC_UNLOCK();
} // wfcDestroyContext()
//==============================================================================
// Source functions
WFC_API_CALL WFCSource WFC_APIENTRY wfcCreateSourceFromStream(WFCDevice dev, WFCContext ctx,
WFCNativeStreamType stream,
const WFCint *attribList) WFC_APIEXIT
{
WFCSource source;
WFC_LOCK();
source = (WFCSource) wfc_source_or_mask_create(WFC_IS_SOURCE, dev, ctx, stream, attribList);
WFC_UNLOCK();
return source;
} // wfcCreateSourceFromStream()
//------------------------------------------------------------------------------
WFC_API_CALL void WFC_APIENTRY
wfcDestroySource(WFCDevice dev, WFCSource src) WFC_APIEXIT
{
vcos_log_trace("%s: source = 0x%X", VCOS_FUNCTION, src);
WFC_LOCK();
wfc_source_or_mask_destroy(dev, (WFCHandle) src);
WFC_UNLOCK();
} // wfcDestroySource()
//==============================================================================
// Mask functions
WFC_API_CALL WFCMask WFC_APIENTRY
wfcCreateMaskFromStream(WFCDevice dev, WFCContext ctx,
WFCNativeStreamType stream,
const WFCint *attribList) WFC_APIEXIT
{
WFCMask mask;
WFC_LOCK();
mask = (WFCMask) wfc_source_or_mask_create(WFC_IS_MASK, dev, ctx, stream, attribList);
WFC_UNLOCK();
return mask;
} // wfcCreateMaskFromStream()
//------------------------------------------------------------------------------
WFC_API_CALL void WFC_APIENTRY
wfcDestroyMask(WFCDevice dev, WFCMask msk) WFC_APIEXIT
{
WFC_LOCK();
wfc_source_or_mask_destroy(dev, (WFCHandle) msk);
WFC_UNLOCK();
} // wfcDestroyMask()
//==============================================================================
// Element functions
WFC_API_CALL WFCElement WFC_APIENTRY
wfcCreateElement(WFCDevice dev, WFCContext ctx,
const WFCint *attribList) WFC_APIEXIT
{
WFC_LOCK();
WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
WFC_CONTEXT_T *context_ptr = wfc_context_from_handle(ctx);
WFCElement element = WFC_INVALID_HANDLE;
if (!vcos_verify(device_ptr != NULL))
{
vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
WFC_UNLOCK();
return WFC_INVALID_HANDLE;
}
if(vcos_verify((context_ptr != NULL) && (context_ptr->device_ptr == device_ptr)))
{
if(wfc_check_no_attribs(attribList))
{
WFC_ELEMENT_T *element_ptr = vcos_blockpool_calloc(&wfc_client_state.element_pool);
const WFC_ELEMENT_ATTRIB_T element_attrib_default = WFC_ELEMENT_ATTRIB_DEFAULT;
if(element_ptr != NULL)
{
wfc_link_init_null(&element_ptr->link);
element_ptr->context_ptr = context_ptr;
element_ptr->attributes = element_attrib_default;
wfc_link_attach(&element_ptr->link, &context_ptr->elements_not_in_scene);
element = wfc_element_to_handle(element_ptr);
} // if
else
{wfc_set_error(device_ptr, WFC_ERROR_OUT_OF_MEMORY);}
} // if
else
{wfc_set_error(device_ptr, WFC_ERROR_BAD_ATTRIBUTE);}
} // if
else
{wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);}
WFC_UNLOCK();
return element;
} // wfcCreateElement()
//------------------------------------------------------------------------------
WFC_API_CALL WFCint WFC_APIENTRY
wfcGetElementAttribi(WFCDevice dev, WFCElement elm,
WFCElementAttrib attrib) WFC_APIEXIT
{
WFC_LOCK();
WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
WFC_ELEMENT_T *element_ptr = wfc_element_from_handle(elm);
WFCint result = 0;
if (!vcos_verify(device_ptr != NULL))
{
vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
WFC_UNLOCK();
return result;
}
if(vcos_verify((element_ptr != NULL) && (element_ptr->context_ptr != NULL)
&& (element_ptr->context_ptr->device_ptr == device_ptr)))
{
switch (attrib)
{
case WFC_ELEMENT_SOURCE:
result = (WFCint)wfc_source_or_mask_to_handle(element_ptr->source_ptr);
break;
case WFC_ELEMENT_SOURCE_FLIP:
result = element_ptr->attributes.flip;
break;
case WFC_ELEMENT_SOURCE_ROTATION:
result = element_ptr->attributes.rotation;
break;
case WFC_ELEMENT_SOURCE_SCALE_FILTER:
result = element_ptr->attributes.scale_filter;
break;
case WFC_ELEMENT_TRANSPARENCY_TYPES:
result = element_ptr->attributes.transparency_types;
break;
case WFC_ELEMENT_GLOBAL_ALPHA:
result = wfc_round(element_ptr->attributes.global_alpha * 255.0f);
break;
case WFC_ELEMENT_MASK:
result = (WFCint)wfc_source_or_mask_to_handle(element_ptr->mask_ptr);
break;
default:
wfc_set_error(device_ptr, WFC_ERROR_BAD_ATTRIBUTE);
break;
} // switch
} // if
else
{wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);}
WFC_UNLOCK();
return result;
} // wfcGetElementAttribi()
//------------------------------------------------------------------------------
WFC_API_CALL WFCfloat WFC_APIENTRY
wfcGetElementAttribf(WFCDevice dev, WFCElement elm,
WFCElementAttrib attrib) WFC_APIEXIT
{
WFC_LOCK();
WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
WFC_ELEMENT_T *element_ptr = wfc_element_from_handle(elm);
WFCfloat result = 0;
if (!vcos_verify(device_ptr != NULL))
{
vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
WFC_UNLOCK();
return result;
}
if(vcos_verify((element_ptr != NULL) && (element_ptr->context_ptr != NULL)
&& (element_ptr->context_ptr->device_ptr == device_ptr)))
{
switch (attrib) {
case WFC_ELEMENT_GLOBAL_ALPHA:
result = element_ptr->attributes.global_alpha;
break;
default:
wfc_set_error(device_ptr, WFC_ERROR_BAD_ATTRIBUTE);
break;
}
}
else
{wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);}
WFC_UNLOCK();
return result;
} // wfcGetElementAttribf()
//------------------------------------------------------------------------------
WFC_API_CALL void WFC_APIENTRY
wfcGetElementAttribiv(WFCDevice dev, WFCElement elm,
WFCElementAttrib attrib, WFCint count, WFCint *values) WFC_APIEXIT
{
WFC_LOCK();
WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
WFC_ELEMENT_T *element_ptr = wfc_element_from_handle(elm);
if (!vcos_verify(device_ptr != NULL))
{
vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
WFC_UNLOCK();
return;
}
if(vcos_verify((element_ptr != NULL) && (element_ptr->context_ptr != NULL)
&& (element_ptr->context_ptr->device_ptr == device_ptr)))
{
int i;
switch (attrib) {
case WFC_ELEMENT_DESTINATION_RECTANGLE:
if (values && count == WFC_RECT_SIZE)
for (i = 0; i < WFC_RECT_SIZE; i++)
values[i] = element_ptr->attributes.dest_rect[i];
else
wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);
break;
case WFC_ELEMENT_SOURCE_RECTANGLE:
if (values && !((size_t)values & 3) && count == WFC_RECT_SIZE)
{
for (i = 0; i < WFC_RECT_SIZE; i++)
values[i] = (WFCint) element_ptr->attributes.src_rect[i];
} // if
else
wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);
break;
default:
wfc_set_error(device_ptr, WFC_ERROR_BAD_ATTRIBUTE);
break;
}
}
else
{wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);}
WFC_UNLOCK();
} // wfcGetElementAttribiv()
//------------------------------------------------------------------------------
WFC_API_CALL void WFC_APIENTRY
wfcGetElementAttribfv(WFCDevice dev, WFCElement elm,
WFCElementAttrib attrib, WFCint count, WFCfloat *values) WFC_APIEXIT
{
WFC_LOCK();
WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
WFC_ELEMENT_T *element_ptr = wfc_element_from_handle(elm);
if (!vcos_verify(device_ptr != NULL))
{
vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
WFC_UNLOCK();
return;
}
if(vcos_verify((element_ptr != NULL) && (element_ptr->context_ptr != NULL)
&& (element_ptr->context_ptr->device_ptr == device_ptr)))
{
uint32_t i;
switch(attrib)
{
case WFC_ELEMENT_DESTINATION_RECTANGLE:
if(values && !((size_t)values & 3) && (count == WFC_RECT_SIZE))
{
for (i = 0; i < WFC_RECT_SIZE; i++)
{values[i] = (WFCfloat) element_ptr->attributes.dest_rect[i];}
} // if
else
{wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);}
break;
case WFC_ELEMENT_SOURCE_RECTANGLE:
if(values && !((size_t)values & 3) && (count == WFC_RECT_SIZE))
{
for (i = 0; i < WFC_RECT_SIZE; i++)
{values[i] = element_ptr->attributes.src_rect[i];}
} // if
else
{wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);}
break;
default:
wfc_set_error(device_ptr, WFC_ERROR_BAD_ATTRIBUTE);
break;
} // switch
} // if
else
{wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);}
WFC_UNLOCK();
} // wfcGetElementAttribfv()
//------------------------------------------------------------------------------
WFC_API_CALL void WFC_APIENTRY
wfcSetElementAttribi(WFCDevice dev, WFCElement elm,
WFCElementAttrib attrib, WFCint value) WFC_APIEXIT
{
WFC_LOCK();
WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
WFC_ELEMENT_T *element_ptr = wfc_element_from_handle(elm);
if (!vcos_verify(device_ptr != NULL))
{
vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
WFC_UNLOCK();
return;
}
if(vcos_verify((element_ptr != NULL) && (element_ptr->context_ptr != NULL)
&& (element_ptr->context_ptr->device_ptr == device_ptr)))
{
switch (attrib)
{
case WFC_ELEMENT_SOURCE:
{
WFC_SOURCE_OR_MASK_T *new_source_ptr = wfc_source_or_mask_from_handle(value);
if
(
((new_source_ptr != NULL) && (element_ptr->context_ptr == new_source_ptr->context_ptr))
|| (new_source_ptr == NULL)
)
{
wfc_source_or_mask_acquire(new_source_ptr);
wfc_source_or_mask_release(element_ptr->source_ptr);
element_ptr->source_ptr = new_source_ptr;
element_ptr->attributes.source_stream =
element_ptr->source_ptr ? element_ptr->source_ptr->stream : WFC_INVALID_HANDLE;
} // if
else
{wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);}
break;
}
case WFC_ELEMENT_SOURCE_FLIP:
{
if (value == WFC_FALSE || value == WFC_TRUE)
element_ptr->attributes.flip = value;
else
wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);
break;
}
case WFC_ELEMENT_SOURCE_ROTATION:
{
if (wfc_is_rotation(value))
element_ptr->attributes.rotation = value;
else
wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);
break;
}
case WFC_ELEMENT_SOURCE_SCALE_FILTER:
{
if (wfc_is_scale_filter(value))
element_ptr->attributes.scale_filter = value;
else
wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);
break;
}
case WFC_ELEMENT_TRANSPARENCY_TYPES:
{
if (wfc_are_transparency_types(value))
element_ptr->attributes.transparency_types = value;
else
wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);
break;
}
case WFC_ELEMENT_GLOBAL_ALPHA:
{
if (value >= 0 && value <= 255)
element_ptr->attributes.global_alpha = (float)value / 255.0f;
else
wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);
break;
}
case WFC_ELEMENT_MASK:
{
WFC_SOURCE_OR_MASK_T *new_mask_ptr = wfc_source_or_mask_from_handle(value);
if
(
((new_mask_ptr != NULL) && (element_ptr->context_ptr == new_mask_ptr->context_ptr))
|| (new_mask_ptr == NULL)
)
{
wfc_source_or_mask_release(element_ptr->mask_ptr);
element_ptr->mask_ptr = new_mask_ptr;
wfc_source_or_mask_acquire(element_ptr->mask_ptr);
element_ptr->attributes.mask_stream =
element_ptr->mask_ptr ? element_ptr->mask_ptr->stream : WFC_INVALID_HANDLE;
} // if
else
{wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);}
break;
}
default:
wfc_set_error(device_ptr, WFC_ERROR_BAD_ATTRIBUTE);
break;
} // switch
} // if
else
{wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);}
WFC_UNLOCK();
} // wfcSetElementAttribi()
//------------------------------------------------------------------------------
WFC_API_CALL void WFC_APIENTRY
wfcSetElementAttribf(WFCDevice dev, WFCElement elm,
WFCElementAttrib attrib, WFCfloat value) WFC_APIEXIT
{
WFC_LOCK();
WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
WFC_ELEMENT_T *element_ptr = wfc_element_from_handle(elm);
if (!vcos_verify(device_ptr != NULL))
{
vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
WFC_UNLOCK();
return;
}
if(vcos_verify((element_ptr != NULL) && (element_ptr->context_ptr != NULL)
&& (element_ptr->context_ptr->device_ptr == device_ptr)))
{
switch(attrib)
{
case WFC_ELEMENT_GLOBAL_ALPHA:
if (value >= 0.0f && value <= 1.0f)
element_ptr->attributes.global_alpha = value;
else
wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);
break;
default:
wfc_set_error(device_ptr, WFC_ERROR_BAD_ATTRIBUTE);
break;
} // switch
} // if
else
wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);
WFC_UNLOCK();
} // wfcSetElementAttribf()
//------------------------------------------------------------------------------
WFC_API_CALL void WFC_APIENTRY
wfcSetElementAttribiv(WFCDevice dev, WFCElement elm,
WFCElementAttrib attrib,
WFCint count, const WFCint *values) WFC_APIEXIT
{
WFC_LOCK();
WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
WFC_ELEMENT_T *element_ptr = wfc_element_from_handle(elm);
if (!vcos_verify(device_ptr != NULL))
{
vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
WFC_UNLOCK();
return;
}
if(vcos_verify((element_ptr != NULL) && (element_ptr->context_ptr != NULL)
&& (element_ptr->context_ptr->device_ptr == device_ptr)))
{
uint32_t i;
switch (attrib) {
case WFC_ELEMENT_DESTINATION_RECTANGLE:
if (values && !((size_t)values & 3) && count == WFC_RECT_SIZE)
{
for (i = 0; i < WFC_RECT_SIZE; i++)
{element_ptr->attributes.dest_rect[i] = values[i];}
} // if
else
{wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);}
break;
case WFC_ELEMENT_SOURCE_RECTANGLE:
if (values && !((size_t)values & 3) && count == WFC_RECT_SIZE)
{
// TODO verify that source rectangle is within the source image.
for (i = 0; i < WFC_RECT_SIZE; i++)
{element_ptr->attributes.src_rect[i] = (float)values[i];}
} // if
else
{wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);}
break;
default:
wfc_set_error(device_ptr, WFC_ERROR_BAD_ATTRIBUTE);
break;
} // switch
} // if
else
{wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);}
WFC_UNLOCK();
} // wfcSetElementAttribiv()
//------------------------------------------------------------------------------
WFC_API_CALL void WFC_APIENTRY
wfcSetElementAttribfv(WFCDevice dev, WFCElement elm,
WFCElementAttrib attrib,
WFCint count, const WFCfloat *values) WFC_APIEXIT
{
WFC_LOCK();
WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
WFC_ELEMENT_T *element_ptr = wfc_element_from_handle(elm);
if (!vcos_verify(device_ptr != NULL))
{
vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
WFC_UNLOCK();
return;
}
if(vcos_verify((element_ptr != NULL) && (element_ptr->context_ptr != NULL)
&& (element_ptr->context_ptr->device_ptr == device_ptr)))
{
uint32_t i;
switch (attrib)
{
case WFC_ELEMENT_DESTINATION_RECTANGLE:
if (values && !((size_t)values & 3) && count == WFC_RECT_SIZE)
{
for (i = 0; i < WFC_RECT_SIZE; i++)
{element_ptr->attributes.dest_rect[i] = (int)values[i];}
} // if
else
{wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);}
break;
case WFC_ELEMENT_SOURCE_RECTANGLE:
if (values && !((size_t)values & 3) && count == WFC_RECT_SIZE)
{
// TODO verify that source rectangle is within the source image.
// Note that these are floats, so check if difference is < 0.00001,
// as per spec, p37 (PDF p42)
for (i = 0; i < WFC_RECT_SIZE; i++)
{element_ptr->attributes.src_rect[i] = values[i];}
} // if
else
{wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);}
break;
default:
wfc_set_error(device_ptr, WFC_ERROR_BAD_ATTRIBUTE);
break;
} // switch
} // if
else
{wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);}
WFC_UNLOCK();
} // wfcSetElementAttribfv()
//------------------------------------------------------------------------------
WFC_API_CALL void WFC_APIENTRY
wfcInsertElement(WFCDevice dev, WFCElement elm, WFCElement subordinate) WFC_APIEXIT
{
WFC_LOCK();
WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
WFC_ELEMENT_T *element_ptr = wfc_element_from_handle(elm);
WFC_ELEMENT_T *subordinate_ptr = wfc_element_from_handle(subordinate);
if (!vcos_verify(device_ptr != NULL))
{
vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
WFC_UNLOCK();
return;
}
if(vcos_verify
(
(element_ptr != NULL) && (element_ptr->context_ptr != NULL)
&& (element_ptr->context_ptr->device_ptr == device_ptr)
&&
(
(subordinate_ptr == NULL)
|| ((subordinate_ptr->context_ptr != NULL)
&& (subordinate_ptr->context_ptr->device_ptr == device_ptr))
)
))
{
if(subordinate_ptr != NULL)
{
// Insert element after subordinate.
if((element_ptr->context_ptr == subordinate_ptr->context_ptr) && subordinate_ptr->is_in_scene)
{
// Insert element in front of itself has no effect.
if (elm != subordinate)
{
wfc_link_attach(&element_ptr->link, &subordinate_ptr->link);
element_ptr->is_in_scene = true;
}
}
else
{wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);}
} // if
else
{
// Insert at the "bottom of the scene" - which is the end of the list.
wfc_link_attach(&element_ptr->link, &element_ptr->context_ptr->elements_in_scene);
element_ptr->is_in_scene = true;
} // else
}
else
{wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);}
WFC_UNLOCK();
} // wfcInsertElement()
//------------------------------------------------------------------------------
WFC_API_CALL void WFC_APIENTRY
wfcRemoveElement(WFCDevice dev, WFCElement elm) WFC_APIEXIT
{
WFC_LOCK();
WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
WFC_ELEMENT_T *element_ptr = wfc_element_from_handle(elm);
if (!vcos_verify(device_ptr != NULL))
{
vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
WFC_UNLOCK();
return;
}
if(vcos_verify((element_ptr != NULL) && (element_ptr->context_ptr != NULL)
&& (element_ptr->context_ptr->device_ptr == device_ptr)))
{
wfc_link_attach(&element_ptr->link, &element_ptr->context_ptr->elements_not_in_scene);
element_ptr->is_in_scene = false;
}
else
{wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);}
WFC_UNLOCK();
} // wfcRemoveElement()
//------------------------------------------------------------------------------
WFC_API_CALL WFCElement WFC_APIENTRY
wfcGetElementAbove(WFCDevice dev, WFCElement elm) WFC_APIEXIT
{
WFC_LOCK();
WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
WFC_ELEMENT_T *element_ptr = wfc_element_from_handle(elm);
WFCElement result = WFC_INVALID_HANDLE;
if (!vcos_verify(device_ptr != NULL))
{
vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
WFC_UNLOCK();
return result;
}
if(vcos_verify((element_ptr != NULL) && (element_ptr->context_ptr != NULL)
&& (element_ptr->context_ptr->device_ptr == device_ptr)))
{
if (element_ptr->is_in_scene)
{
if (element_ptr->link.next != &element_ptr->context_ptr->elements_in_scene)
{result = wfc_element_link_to_handle(element_ptr->link.next);}
}
else
{wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);}
}
else
{wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);}
WFC_UNLOCK();
return result;
} // wfcGetElementAbove()
//------------------------------------------------------------------------------
WFC_API_CALL WFCElement WFC_APIENTRY
wfcGetElementBelow(WFCDevice dev, WFCElement elm) WFC_APIEXIT
{
WFC_LOCK();
WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
WFC_ELEMENT_T *element_ptr = wfc_element_from_handle(elm);
WFCElement result = WFC_INVALID_HANDLE;
if (!vcos_verify(device_ptr != NULL))
{
vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
WFC_UNLOCK();
return result;
}
if(vcos_verify((element_ptr != NULL) && (element_ptr->context_ptr != NULL)
&& (element_ptr->context_ptr->device_ptr == device_ptr)))
{
if (element_ptr->is_in_scene)
{
if (element_ptr->link.prev != &element_ptr->context_ptr->elements_in_scene)
{result = wfc_element_link_to_handle(element_ptr->link.prev);}
}
else
{wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);}
}
else
{wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);}
WFC_UNLOCK();
return result;
} // wfcGetElementBelow()
//------------------------------------------------------------------------------
WFC_API_CALL void WFC_APIENTRY
wfcDestroyElement(WFCDevice dev, WFCElement elm) WFC_APIEXIT
{
vcos_log_trace("%s: element = 0x%X", VCOS_FUNCTION, elm);
WFC_LOCK();
WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
WFC_ELEMENT_T *element_ptr = wfc_element_from_handle(elm);
if (!vcos_verify(device_ptr != NULL))
{
vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
WFC_UNLOCK();
return;
}
if(vcos_verify((element_ptr != NULL) && (element_ptr->context_ptr != NULL)
&& (element_ptr->context_ptr->device_ptr == device_ptr)))
{wfc_element_destroy(element_ptr, NULL);}
else
{wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);}
WFC_UNLOCK();
} // wfcDestroyElement()
//==============================================================================
// Rendering
WFC_API_CALL void WFC_APIENTRY
wfcActivate(WFCDevice dev, WFCContext ctx) WFC_APIEXIT
{
WFC_LOCK();
WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
WFC_CONTEXT_T *context_ptr = wfc_context_from_handle(ctx);
VCOS_STATUS_T status = VCOS_ENOSYS;
if (!vcos_verify(device_ptr != NULL))
{
vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
WFC_UNLOCK();
return;
}
if(vcos_verify((context_ptr != NULL) && (context_ptr->device_ptr == device_ptr)))
{
wfc_server_activate(ctx);
context_ptr->active = true;
do
{
vcos_log_info("%s: dev 0x%X, ctx 0x%X commit %u", VCOS_FUNCTION, dev, ctx, context_ptr->committed_scene.commit_count);
status = wfc_server_commit_scene(ctx, &context_ptr->committed_scene,
0, NULL, NULL);
if (status == VCOS_EAGAIN)
{
// Another thread is competing for access to the context, so
// wait a little and try again.
vcos_sleep(1);
}
}
while (status == VCOS_EAGAIN);
if (status != VCOS_SUCCESS)
{
wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);
}
} //if
else
{wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);}
WFC_UNLOCK();
} // wfcActivate()
//------------------------------------------------------------------------------
WFC_API_CALL void WFC_APIENTRY
wfcDeactivate(WFCDevice dev, WFCContext ctx) WFC_APIEXIT
{
WFC_LOCK();
WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
WFC_CONTEXT_T *context_ptr = wfc_context_from_handle(ctx);
if (!vcos_verify(device_ptr != NULL))
{
vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
WFC_UNLOCK();
return;
}
if(vcos_verify((context_ptr != NULL) && (context_ptr->device_ptr == device_ptr)))
{
wfc_server_deactivate(ctx);
context_ptr->active = false;
} else
wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);
WFC_UNLOCK();
} // wfcDeactivate()
//------------------------------------------------------------------------------
WFC_API_CALL void WFC_APIENTRY
wfcCompose(WFCDevice dev, WFCContext ctx, WFCboolean wait) WFC_APIEXIT
{
WFC_LOCK();
WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
WFC_CONTEXT_T *context_ptr = wfc_context_from_handle(ctx);
VCOS_STATUS_T status = VCOS_ENOSYS;
VCOS_SEMAPHORE_T wait_sem;
if (!vcos_verify(device_ptr != NULL))
{
vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
WFC_UNLOCK();
return;
}
if(vcos_verify((context_ptr != NULL) && (context_ptr->device_ptr == device_ptr)))
{
// Only tell the server to compose if the context is not active, since it will
// be automatically composed on commit when active
if(!context_ptr->active)
{
uint32_t commit_flags = WFC_SERVER_COMMIT_COMPOSE;
vcos_log_info("%s: dev 0x%X, ctx 0x%X commit %u", VCOS_FUNCTION, dev, ctx, context_ptr->committed_scene.commit_count);
if (wait)
{
commit_flags |= WFC_SERVER_COMMIT_WAIT;
// Long running operation, so keep VC alive until it completes.
wfc_server_use_keep_alive();
status = vcos_semaphore_create(&wait_sem, "WFC compose", 0);
vcos_assert(status == VCOS_SUCCESS); // On platforms we care about.
do
{
status = wfc_server_commit_scene(ctx, &context_ptr->committed_scene,
commit_flags, wfc_client_scene_taken_cb, &wait_sem);
if (status == VCOS_EAGAIN)
{
// Another thread is competing for access to the context, so
// wait a little and try again.
vcos_sleep(1);
}
}
while (status == VCOS_EAGAIN);
if (status != VCOS_SUCCESS)
{
vcos_semaphore_delete(&wait_sem);
wfc_server_release_keep_alive();
}
}
else
{
status = wfc_server_commit_scene(ctx, &context_ptr->committed_scene,
commit_flags, NULL, NULL);
}
if (status != VCOS_SUCCESS)
{
vcos_log_info("%s: failed to compose scene: %d", VCOS_FUNCTION, status);
wfc_set_error(device_ptr, WFC_ERROR_BUSY);
}
} // if
else
{wfc_set_error(device_ptr, WFC_ERROR_UNSUPPORTED);}
}
else
{wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);}
WFC_UNLOCK();
// Wait for the scene to be taken outside the lock
if (wait && status == VCOS_SUCCESS)
{
wfc_client_wait_for_scene_taken(&wait_sem, ctx, VCOS_FUNCTION);
}
} // wfcCompose()
//------------------------------------------------------------------------------
WFC_API_CALL void WFC_APIENTRY
wfcFence(WFCDevice dev, WFCContext ctx, WFCEGLDisplay dpy,
WFCEGLSync sync) WFC_APIEXIT
{
vcos_unused(dpy);
vcos_unused(sync);
WFC_LOCK();
WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
WFC_CONTEXT_T *context_ptr = wfc_context_from_handle(ctx);
if (!vcos_verify(device_ptr != NULL))
{
vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
WFC_UNLOCK();
return;
}
// TODO wfcFence()
vcos_assert(0);
if(vcos_verify((context_ptr != NULL) && (context_ptr->device_ptr == device_ptr)))
{
/* Set error as WFC_ERROR_ILLEGAL_ARGUMENT
- if dpy is not a valid EGLDisplay
- if sync is not a valid sync object
- if sync<6E>s EGL_SYNC_TYPE_KHR is not EGL_SYNC_REUSABLE_KHR
*/
} // if
else
{wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);}
WFC_UNLOCK();
} // wfcFence()
//==============================================================================
// Renderer and extension information
WFC_API_CALL WFCint WFC_APIENTRY
wfcGetStrings(WFCDevice dev,
WFCStringID name,
const char **strings,
WFCint stringsCount) WFC_APIEXIT
{
WFC_LOCK();
WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
const char *name_string = NULL;
if (!vcos_verify(device_ptr != NULL))
{
vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
WFC_UNLOCK();
return 0;
}
switch(name)
{
case WFC_VENDOR:
name_string = "Broadcom";
break;
case WFC_RENDERER:
name_string = "VideoCore IV HW";
break;
case WFC_VERSION:
name_string = "1.0";
break;
case WFC_EXTENSIONS:
name_string = "";
break;
default:
wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);
WFC_UNLOCK();
return 0;
} // switch
WFCint num_of_strings = 0;
if(stringsCount >= 0)
{
num_of_strings = 1;
if((strings != NULL) && (stringsCount > 0))
{
*strings = name_string;
} // if
} // if
else
{
wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);
} // else
WFC_UNLOCK();
return num_of_strings;
} // wfcGetStrings()
//------------------------------------------------------------------------------
WFC_API_CALL WFCboolean WFC_APIENTRY
wfcIsExtensionSupported(WFCDevice dev, const char *string) WFC_APIEXIT
{
vcos_unused(string);
// TODO wfcIsExtensionSupported()
vcos_assert(0);
if(!vcos_verify(dev != WFC_INVALID_HANDLE))
{return WFC_FALSE;}
return WFC_FALSE;
}
//!@} // (OpenWF-C API functions)
//==============================================================================
static void wfc_initialise_client_state(void)
{
size_t pool_index;
const WFC_BLOCKPOOL_INFO_T *pool_info = wfc_client_blockpool_info;
uint64_t pid = vcos_process_id_current();
// Logging
vcos_log_set_level(&log_cat, WFC_LOG_LEVEL);
vcos_log_register("wfc_client_func", &log_cat);
vcos_log_error("%s: entered", VCOS_FUNCTION);
// Allocate all the pools
for (pool_index = 0; pool_index < countof(wfc_client_blockpool_info); pool_index++, pool_info++)
{
if (vcos_blockpool_create_on_heap(pool_info->pool, pool_info->count, pool_info->size,
VCOS_BLOCKPOOL_ALIGN_DEFAULT, 0, pool_info->name) != VCOS_SUCCESS)
goto fail;
vcos_blockpool_extend(pool_info->pool, pool_info->max_subpools - 1, pool_info->count);
}
vcos_mutex_create(&wfc_client_state.mutex, NULL);
// Set up a handle modifier that is generally process specific. The shifting
// around should put the ID on Linux in an otherwise fairly unused bit of the
// handle, which makes debugging easier.
wfc_client_state.handle_mod = (VCOS_UNSIGNED)((pid << 16) ^ (pid >> 16) ^ (pid >> 48));
wfc_client_state.is_initialised = true;
vcos_log_error("%s: success", VCOS_FUNCTION);
// Success
return;
fail:
vcos_log_error("%s: failed to allocate memory pools", VCOS_FUNCTION);
// pool_index and pool_info refer to the one that failed to allocate. Free
// any pools already allocated.
while (pool_index-- > 0)
{
pool_info--;
vcos_blockpool_delete(pool_info->pool);
}
}
//------------------------------------------------------------------------------
static WFC_DEVICE_T *wfc_device_from_handle(WFCDevice dev)
{
VCOS_UNSIGNED handle_mod = WFC_DEVICE_MOD ^ wfc_client_state.handle_mod;
if (dev == WFC_INVALID_HANDLE)
return NULL;
return vcos_blockpool_elem_from_handle(&wfc_client_state.device_pool, dev ^ handle_mod);
}
//------------------------------------------------------------------------------
static WFCDevice wfc_device_to_handle(WFC_DEVICE_T *device_ptr)
{
VCOS_UNSIGNED handle_mod = WFC_DEVICE_MOD ^ wfc_client_state.handle_mod;
VCOS_UNSIGNED handle = vcos_blockpool_elem_to_handle(device_ptr);
if (handle == VCOS_BLOCKPOOL_INVALID_HANDLE)
return WFC_INVALID_HANDLE;
return (WFCDevice)(handle ^ handle_mod);
}
//------------------------------------------------------------------------------
static WFC_CONTEXT_T *wfc_context_from_handle(WFCContext ctx)
{
VCOS_UNSIGNED handle_mod = WFC_CONTEXT_MOD ^ wfc_client_state.handle_mod;
if (ctx == WFC_INVALID_HANDLE)
return NULL;
return vcos_blockpool_elem_from_handle(&wfc_client_state.context_pool, ctx ^ handle_mod);
}
//------------------------------------------------------------------------------
static WFCContext wfc_context_to_handle(WFC_CONTEXT_T *context_ptr)
{
VCOS_UNSIGNED handle_mod = WFC_CONTEXT_MOD ^ wfc_client_state.handle_mod;
VCOS_UNSIGNED handle = vcos_blockpool_elem_to_handle(context_ptr);
if (handle == VCOS_BLOCKPOOL_INVALID_HANDLE)
return WFC_INVALID_HANDLE;
return (WFCContext)(handle ^ handle_mod);
}
//------------------------------------------------------------------------------
static WFC_ELEMENT_T *wfc_element_from_handle(WFCElement element)
{
VCOS_UNSIGNED handle_mod = WFC_ELEMENT_MOD ^ wfc_client_state.handle_mod;
if (element == WFC_INVALID_HANDLE)
return NULL;
return vcos_blockpool_elem_from_handle(&wfc_client_state.element_pool, element ^ handle_mod);
}
//------------------------------------------------------------------------------
static WFCElement wfc_element_to_handle(WFC_ELEMENT_T *element_ptr)
{
VCOS_UNSIGNED handle_mod = WFC_ELEMENT_MOD ^ wfc_client_state.handle_mod;
VCOS_UNSIGNED handle = vcos_blockpool_elem_to_handle(element_ptr);
if (handle == VCOS_BLOCKPOOL_INVALID_HANDLE)
return WFC_INVALID_HANDLE;
return (WFCElement)(handle ^ handle_mod);
}
//------------------------------------------------------------------------------
static WFCElement wfc_element_link_to_handle(WFC_LINK_T *element_link_ptr)
{
return wfc_element_to_handle((WFC_ELEMENT_T *)((char *)element_link_ptr - offsetof(WFC_ELEMENT_T, link)));
}
//------------------------------------------------------------------------------
static WFC_SOURCE_OR_MASK_T *wfc_source_or_mask_from_handle(WFCHandle source_or_mask)
{
VCOS_UNSIGNED handle_mod = WFC_SOURCE_MOD ^ wfc_client_state.handle_mod;
if (source_or_mask == WFC_INVALID_HANDLE)
return NULL;
return vcos_blockpool_elem_from_handle(&wfc_client_state.source_pool, source_or_mask ^ handle_mod);
}
//------------------------------------------------------------------------------
static WFCHandle wfc_source_or_mask_to_handle(WFC_SOURCE_OR_MASK_T *source_or_mask_ptr)
{
VCOS_UNSIGNED handle_mod = WFC_SOURCE_MOD ^ wfc_client_state.handle_mod;
VCOS_UNSIGNED handle = vcos_blockpool_elem_to_handle(source_or_mask_ptr);
if (handle == VCOS_BLOCKPOOL_INVALID_HANDLE)
return WFC_INVALID_HANDLE;
return (WFCHandle)(handle ^ handle_mod);
}
//------------------------------------------------------------------------------
//!@name
//! Macros used in wfc_context_create() to extract data returned from wfc_server_create_context().
//!@{
#define WFC_CONTEXT_WIDTH(data) ((data) >> 16)
#define WFC_CONTEXT_HEIGHT_OR_ERR(data) ((data) & 0xFFFF)
//!@}
static WFC_CONTEXT_T *wfc_context_create
(WFC_DEVICE_T *device_ptr, WFCContextType context_type,
uint32_t screen_or_stream_num, WFCErrorCode *error)
{
WFC_CONTEXT_T *context_ptr = vcos_blockpool_calloc(&wfc_client_state.context_pool);
const WFC_CONTEXT_DYNAMIC_ATTRIB_T ctx_dyn_attrib_default = WFC_CONTEXT_DYNAMIC_ATTRIB_DEFAULT;
if(context_ptr != NULL)
{
uint64_t pid = vcos_process_id_current();
uint32_t pid_lo = (uint32_t) pid;
uint32_t pid_hi = (uint32_t) (pid >> 32);
uint32_t response = wfc_server_create_context(wfc_context_to_handle(context_ptr),
context_type, screen_or_stream_num, pid_lo, pid_hi);
uint32_t height_or_err = WFC_CONTEXT_HEIGHT_OR_ERR(response);
uint32_t width = WFC_CONTEXT_WIDTH(response);
if(width != 0)
{
wfc_link_init_null(&context_ptr->link);
context_ptr->device_ptr = device_ptr;
wfc_link_init_empty(&context_ptr->sources);
wfc_link_init_empty(&context_ptr->masks);
wfc_link_init_empty(&context_ptr->elements_not_in_scene);
wfc_link_init_empty(&context_ptr->elements_in_scene);
context_ptr->active = false;
context_ptr->dynamic_attributes = ctx_dyn_attrib_default;
context_ptr->static_attributes.type = context_type;
context_ptr->static_attributes.height = height_or_err;
context_ptr->static_attributes.width = width;
if(context_type == WFC_CONTEXT_TYPE_OFF_SCREEN)
{
context_ptr->output_stream = screen_or_stream_num;
}
}
else
{
vcos_blockpool_free(context_ptr);
context_ptr = NULL;
*error = (WFCErrorCode) response;
}
} // if
else
{*error = WFC_ERROR_OUT_OF_MEMORY;}
return context_ptr;
} // wfc_context_create()
//------------------------------------------------------------------------------
static void wfc_context_destroy(WFC_CONTEXT_T *context_ptr)
{
// Detach output stream for off-screen contexts.
wfc_stream_register_off_screen(context_ptr->output_stream, false);
// Remove from parent device's list of contexts.
wfc_link_detach(&context_ptr->link);
// Destroy all components
wfc_link_iterate(&context_ptr->elements_in_scene, (WFC_LINK_CALLBACK_T) wfc_element_destroy, NULL);
wfc_link_iterate(&context_ptr->elements_not_in_scene, (WFC_LINK_CALLBACK_T) wfc_element_destroy, NULL);
wfc_link_iterate(&context_ptr->sources, (WFC_LINK_CALLBACK_T) wfc_source_or_mask_destroy_actual, NULL);
wfc_link_iterate(&context_ptr->masks, (WFC_LINK_CALLBACK_T) wfc_source_or_mask_destroy_actual, NULL);
wfc_server_destroy_context(wfc_context_to_handle(context_ptr));
vcos_blockpool_free(context_ptr);
} // wfc_context_destroy()
//==============================================================================
static WFCHandle wfc_source_or_mask_create(
bool is_source, WFCDevice dev, WFCContext ctx,
WFCNativeStreamType stream, const WFCint *attribList)
//!@brief Create a new image provider and associate it with a stream.
//!
//! wfcCreateSourceFromStream() and wfcCreateMaskFromStream() are essentially
//! wrappers for this function.
{
WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
WFC_CONTEXT_T *context_ptr = wfc_context_from_handle(ctx);
WFCHandle handle = WFC_INVALID_HANDLE;
if (!vcos_verify(device_ptr != NULL))
{
vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
return handle;
}
if(vcos_verify((context_ptr != NULL) && (context_ptr->device_ptr == device_ptr)))
{
if(!wfc_check_no_attribs(attribList))
{
wfc_set_error(device_ptr, WFC_ERROR_BAD_ATTRIBUTE);
}
else if(context_ptr->output_stream == stream)
{
// Verify that context isn't an input for this stream
wfc_set_error(device_ptr, WFC_ERROR_IN_USE);
}
else if (!wfc_stream_register_source_or_mask(stream, true))
{
vcos_log_error("%s: failed to register stream 0x%x", VCOS_FUNCTION, stream);
wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);
}
else
{
WFC_SOURCE_OR_MASK_T *source_or_mask_ptr = vcos_blockpool_calloc(&wfc_client_state.source_pool);
if(source_or_mask_ptr != NULL)
{
// Note that refcount is initialised to zero here, as a source or mask is
// only in use when it is linked to an element.
wfc_link_init_null(&source_or_mask_ptr->link);
source_or_mask_ptr->is_source = is_source;
source_or_mask_ptr->context_ptr = context_ptr;
source_or_mask_ptr->stream = stream;
if(is_source)
{
wfc_link_attach(&source_or_mask_ptr->link, &context_ptr->sources);
}
else
{
wfc_link_attach(&source_or_mask_ptr->link, &context_ptr->masks);
}
handle = wfc_source_or_mask_to_handle(source_or_mask_ptr);
}
else
{
wfc_stream_register_source_or_mask(stream, false);
vcos_log_error("%s: failed to allocate source/mask info for stream 0x%x", VCOS_FUNCTION, stream);
wfc_set_error(device_ptr, WFC_ERROR_OUT_OF_MEMORY);
}
}
}
else
{
wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);
}
return handle;
}
//------------------------------------------------------------------------------
static void wfc_source_or_mask_destroy(WFCDevice dev, WFCHandle source_or_mask)
//!@brief Destroy an image provider and dissociate its stream.
//!
//! wfcDestroySource() and wfcDestroyMask() are essentially wrappers for this function.
{
WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
WFC_SOURCE_OR_MASK_T *source_or_mask_ptr = wfc_source_or_mask_from_handle(source_or_mask);
if (!vcos_verify(device_ptr != NULL))
{
vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
return;
}
if((source_or_mask_ptr != NULL) && (source_or_mask_ptr->context_ptr != NULL)
&& (source_or_mask_ptr->context_ptr->device_ptr == device_ptr))
{
wfc_source_or_mask_destroy_actual(source_or_mask_ptr, NULL);
}
else
{
wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);
}
}
//------------------------------------------------------------------------------
static void wfc_source_or_mask_acquire(WFC_SOURCE_OR_MASK_T *source_or_mask_ptr)
//! Indicate that the image provider is now linked to an element.
{
vcos_log_trace("%s: %p refcount %d", VCOS_FUNCTION, source_or_mask_ptr,
source_or_mask_ptr ? source_or_mask_ptr->refcount : 0);
if(source_or_mask_ptr != NULL)
{source_or_mask_ptr->refcount++;}
} // wfc_source_or_mask_acquire()
//------------------------------------------------------------------------------
static void wfc_source_or_mask_release(WFC_SOURCE_OR_MASK_T *source_or_mask_ptr)
//! Indicate the the image provider is no longer linked to an element; destroy if previously requested.
{
vcos_log_trace("%s: %p refcount %d", VCOS_FUNCTION, source_or_mask_ptr,
source_or_mask_ptr ? source_or_mask_ptr->refcount : 0);
if(source_or_mask_ptr != NULL)
{
if(source_or_mask_ptr->refcount > 0)
{
source_or_mask_ptr->refcount--;
}
// If no-one is using this source or mask, and a request has previously
// been made to destroy it, do so now.
if((source_or_mask_ptr->refcount == 0) && source_or_mask_ptr->destroy_pending)
{
wfc_source_or_mask_destroy_actual(source_or_mask_ptr, NULL);
}
}
}
//------------------------------------------------------------------------------
static void wfc_source_or_mask_destroy_actual(WFC_SOURCE_OR_MASK_T *source_or_mask_ptr, void *unused)
{
source_or_mask_ptr->destroy_pending = true;
if(source_or_mask_ptr->refcount == 0)
{
vcos_log_trace("%s: %p source 0x%x stream 0x%x", VCOS_FUNCTION, source_or_mask_ptr,
wfc_source_or_mask_to_handle(source_or_mask_ptr), source_or_mask_ptr->stream);
wfc_stream_register_source_or_mask(source_or_mask_ptr->stream, false);
// Remove from parent context's list of sources or masks.
wfc_link_detach(&source_or_mask_ptr->link);
// Destroy.
vcos_blockpool_free(source_or_mask_ptr);
}
else
{
vcos_log_trace("%s: pending: %p refcount: %d", VCOS_FUNCTION, source_or_mask_ptr, source_or_mask_ptr->refcount);
}
}
//==============================================================================
static void wfc_element_destroy(WFC_ELEMENT_T *element_ptr, void *unused)
{
vcos_log_trace("%s: %p", VCOS_FUNCTION, element_ptr);
// Release source and mask (if present); destroy if previously requested.
wfc_source_or_mask_release(element_ptr->source_ptr);
wfc_source_or_mask_release(element_ptr->mask_ptr);
element_ptr->source_ptr = NULL;
element_ptr->mask_ptr = NULL;
wfc_link_detach(&element_ptr->link);
vcos_blockpool_free(element_ptr);
} // wfc_element_destroy()
//==============================================================================
static void wfc_commit_iterator(WFC_ELEMENT_T *element_ptr, WFC_SCENE_T *scene)
{
// Elements with source or destination rectangles having zero width or height
// must not displayed
if
(
(element_ptr->attributes.dest_rect[WFC_RECT_WIDTH] == 0)
|| (element_ptr->attributes.dest_rect[WFC_RECT_HEIGHT] == 0)
|| (element_ptr->attributes.src_rect[WFC_RECT_WIDTH] < 0.00001)
|| (element_ptr->attributes.src_rect[WFC_RECT_HEIGHT] < 0.00001)
)
{return;}
// Elements with a (near-)zero global alpha are transparent, so ignore them
if
(
(element_ptr->attributes.transparency_types & WFC_TRANSPARENCY_ELEMENT_GLOBAL_ALPHA)
&& (element_ptr->attributes.global_alpha < 0.001)
)
{return;}
// Copy element attributes into scene and increment count
memcpy(&scene->elements[scene->element_count++], &element_ptr->attributes, sizeof(WFC_ELEMENT_ATTRIB_T));
} // wfc_commit_iterator()
//==============================================================================
static void wfc_set_error_with_location(WFC_DEVICE_T *device, WFCErrorCode error, const char *func, int line)
//! Update device's error code (but only if previously cleared).
{
vcos_log_error("%s: device %p error 0x%x at line %d", func, device, error, line);
if((device != NULL) && (device->error == WFC_ERROR_NONE))
{device->error = error;}
} // wfc_set_error()
//==============================================================================
static bool wfc_check_no_attribs(const WFCint *attribList)
//! Returns true if the attribute list is empty.
{
return !attribList || (*attribList == WFC_NONE);
}
//------------------------------------------------------------------------------
static bool wfc_is_rotation(WFCint value)
{
return value == WFC_ROTATION_0 ||
value == WFC_ROTATION_90 ||
value == WFC_ROTATION_180 ||
value == WFC_ROTATION_270;
}
//------------------------------------------------------------------------------
static bool wfc_is_scale_filter(WFCint value)
{
return value == WFC_SCALE_FILTER_NONE ||
value == WFC_SCALE_FILTER_FASTER ||
value == WFC_SCALE_FILTER_BETTER;
}
//------------------------------------------------------------------------------
static bool wfc_are_transparency_types(WFCint value)
{
return value == WFC_TRANSPARENCY_NONE ||
value == WFC_TRANSPARENCY_ELEMENT_GLOBAL_ALPHA ||
value == WFC_TRANSPARENCY_SOURCE ||
value == WFC_TRANSPARENCY_SOURCE_VC_NON_PRE_MULT ||
value == WFC_TRANSPARENCY_MASK ||
value == (WFC_TRANSPARENCY_ELEMENT_GLOBAL_ALPHA | WFC_TRANSPARENCY_SOURCE) ||
value == (WFC_TRANSPARENCY_ELEMENT_GLOBAL_ALPHA | WFC_TRANSPARENCY_SOURCE_VC_NON_PRE_MULT) ||
value == (WFC_TRANSPARENCY_ELEMENT_GLOBAL_ALPHA | WFC_TRANSPARENCY_MASK);
}
//------------------------------------------------------------------------------
static int32_t wfc_round(float f)
{
int result = (int)f;
if (f>=0)
if ((f-result)>=0.5) return ++result; else return result;
else
if ((f-result)<=-0.5) return --result; else return result;
}
//==============================================================================
static void wfc_link_detach(WFC_LINK_T *link)
{
vcos_assert(link != NULL);
if (link->next) {
/*
never unlink a base link
*/
vcos_assert(link->next != link);
vcos_assert(link->prev != link);
link->next->prev = link->prev;
link->prev->next = link->next;
link->prev = NULL;
link->next = NULL;
}
}
//------------------------------------------------------------------------------
static void wfc_link_attach(WFC_LINK_T *link, WFC_LINK_T *prev)
{
wfc_link_detach(link);
link->prev = prev;
link->next = prev->next;
link->prev->next = link;
link->next->prev = link;
}
//------------------------------------------------------------------------------
static void wfc_link_init_null(WFC_LINK_T *link)
//!@brief Initialise a link when the link will be used to keep track of structures
//! of the kind which contain the link.
{
link->prev = NULL;
link->next = NULL;
}
//------------------------------------------------------------------------------
static void wfc_link_init_empty(WFC_LINK_T *link)
//!@brief Initialise a link which will contain structures which are children of the
//! structure containing the link.
{
link->prev = link;
link->next = link;
}
//------------------------------------------------------------------------------
static void wfc_link_iterate(WFC_LINK_T *link, WFC_LINK_CALLBACK_T func, void *arg)
{
WFC_LINK_T *curr = link;
WFC_LINK_T *next = curr->next;
while (next != link) {
curr = next;
next = curr->next;
func(curr, arg);
}
}
//------------------------------------------------------------------------------
void wfc_set_deferral_stream(WFCDevice dev, WFCContext ctx, WFCNativeStreamType stream)
{
WFC_LOCK();
WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
WFC_CONTEXT_T *context_ptr = wfc_context_from_handle(ctx);
if (!vcos_verify(device_ptr != NULL))
{
vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
WFC_UNLOCK();
return;
}
if(vcos_verify((context_ptr != NULL) && (context_ptr->device_ptr == device_ptr)))
{
wfc_server_set_deferral_stream(ctx, stream);
} //if
else
{wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);}
WFC_UNLOCK();
}
//------------------------------------------------------------------------------
/** Called when a scene for composition has been taken
*
* @param cb_data Callback data
*/
static void wfc_client_scene_taken_cb(void *cb_data)
{
VCOS_SEMAPHORE_T *wait_sem = (VCOS_SEMAPHORE_T *)cb_data;
vcos_assert(wait_sem != NULL);
vcos_semaphore_post(wait_sem);
}
//------------------------------------------------------------------------------
/** Wait for the scene taken callback to have been called. Deletes the semaphore
* and releases the VideoCore keep alive.
*
* @param wait_sem The wait semaphore.
* @param ctx The handle for the context receiving the scene, used in logging.
* @param calling_function The calling function name, used in logging.
*/
static void wfc_client_wait_for_scene_taken(VCOS_SEMAPHORE_T *wait_sem, WFCContext ctx,
const char *calling_function)
{
VCOS_STATUS_T status;
#if defined(VCOS_LOGGING_ENABLED)
uint64_t pid = vcos_process_id_current();
vcos_log_trace("%s: wait for compositor to take scene, context 0x%x pid 0x%x%08x",
calling_function, ctx, (uint32_t)(pid >> 32), (uint32_t)pid);
#else
vcos_unused(ctx);
vcos_unused(calling_function);
#endif
status = vcos_semaphore_wait(wait_sem);
vcos_assert(status == VCOS_SUCCESS);
vcos_unused(status);
vcos_semaphore_delete(wait_sem);
wfc_server_release_keep_alive();
vcos_log_trace("%s: wait completed", calling_function);
}
//==============================================================================