1/*
2Copyright (c) 2012, Broadcom Europe Ltd
3All rights reserved.
4
5Redistribution and use in source and binary forms, with or without
6modification, are permitted provided that the following conditions are met:
7 * Redistributions of source code must retain the above copyright
8 notice, this list of conditions and the following disclaimer.
9 * Redistributions in binary form must reproduce the above copyright
10 notice, this list of conditions and the following disclaimer in the
11 documentation and/or other materials provided with the distribution.
12 * Neither the name of the copyright holder nor the
13 names of its contributors may be used to endorse or promote products
14 derived from this software without specific prior written permission.
15
16THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
20DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*/
27#define VCOS_VERIFY_BKPTS 1
28
29#define VCOS_LOG_CATEGORY (&log_cat)
30
31#include <stdlib.h>
32#include <stddef.h>
33
34#include "interface/khronos/include/WF/wfc.h"
35
36#include "interface/khronos/wf/wfc_client_stream.h"
37#include "interface/khronos/wf/wfc_server_api.h"
38
39//#define WFC_FULL_LOGGING
40#ifdef WFC_FULL_LOGGING
41#define WFC_LOG_LEVEL VCOS_LOG_TRACE
42#else
43#define WFC_LOG_LEVEL VCOS_LOG_WARN
44#endif
45
46//==============================================================================
47
48//!@name
49//! Values used in wfcEnumerateDevices().
50//!@{
51#define WFC_NUM_OF_DEVICES 1
52#define WFC_OUR_DEVICE_ID 1
53//!@}
54
55//!@name
56//! Global mutex
57//!@{
58#define WFC_LOCK() do {vcos_mutex_lock(&wfc_client_state.mutex);} while (0)
59#define WFC_UNLOCK() do {vcos_mutex_unlock(&wfc_client_state.mutex);} while (0)
60//!@}
61
62//!@name
63//! Values for wfc_source_or_mask_create()
64//!@{
65#define WFC_IS_SOURCE 1
66#define WFC_IS_MASK 0
67//!@}
68
69//==============================================================================
70
71//! Simple doubly-linked list.
72typedef struct _WFC_LINK
73{
74 struct _WFC_LINK *prev;
75 struct _WFC_LINK *next;
76} WFC_LINK_T;
77
78//! Function pointer type, used when iterating through the linked list in wfc_link_iterate().
79typedef void (*WFC_LINK_CALLBACK_T)(WFC_LINK_T *link, void *arg);
80
81//------------------------------------------------------------------------------
82
83//! WF-C device
84typedef struct
85{
86 WFCErrorCode error; //!< Error code returned by wfcGetError().
87
88 WFC_LINK_T contexts; //!< Contexts belonging to this device.
89} WFC_DEVICE_T;
90
91#define DEVICE_POOL_COUNT 4
92#define DEVICE_POOL_MAX_SUBPOOLS 4
93
94//! WFCDevice handle modifier
95#define WFC_DEVICE_MOD 0xD0000000
96
97//! WF-C context
98typedef struct
99{
100 WFC_LINK_T link; //!< Handle of this context within the contexts list.
101
102 WFC_DEVICE_T *device_ptr; //!< Parent device
103 WFC_LINK_T sources; //!< List of sources belonging to this context
104 WFC_LINK_T masks; //!< List of masks belonging to this context
105 WFCNativeStreamType output_stream; //!< For off-screen contexts only, stream to compose into.
106
107 WFC_LINK_T elements_not_in_scene; //!< List of elements belonging to this context, but not on screen.
108 WFC_LINK_T elements_in_scene; //!< List of elements belonging to this context and on screen.
109 bool active; //!< True if this context has had autonomous composition enabled with wfcActivate().
110
111 WFC_CONTEXT_STATIC_ATTRIB_T static_attributes; //!< Attributes associated with the context which are fixed on creation.
112 WFC_CONTEXT_DYNAMIC_ATTRIB_T dynamic_attributes;//!< Attributes associated with the context which may change.
113
114 uint32_t commit_count; //!< Count of commits made
115 WFC_SCENE_T committed_scene; //!< Last committed scene
116} WFC_CONTEXT_T;
117
118#define CONTEXT_POOL_COUNT 4
119#define CONTEXT_POOL_MAX_SUBPOOLS 4
120
121//! WFCContext handle modifier
122#define WFC_CONTEXT_MOD 0xC0000000
123
124//! WF-C image provider (source or mask)
125typedef struct
126{
127 WFC_LINK_T link; //!< Handle of this source/mask within the source/mask list.
128 bool is_source; //!< Indicates if this is a source or a mask.
129
130 WFC_CONTEXT_T *context_ptr; //!< Parent context
131
132 //!@brief Number of elements using this source/mask.
133 //! Required to ensure that it won't be destroyed while it's still in use.
134 uint32_t refcount;
135
136 WFCNativeStreamType stream; //!< Stream associated with this source/mask.
137
138 //!@brief Destruction requested.
139 //! Indicates that the source/mask will be destroyed at the earliest opportunity.
140 bool destroy_pending;
141} WFC_SOURCE_OR_MASK_T;
142
143#define SOURCE_POOL_COUNT 16
144#define SOURCE_POOL_MAX_SUBPOOLS 8
145
146//! WFCSource handle modifier
147#define WFC_SOURCE_MOD 0x50000000
148
149//! WF-C element
150typedef struct
151{
152 WFC_LINK_T link; //!< Handle of this element within the element list.
153 WFC_CONTEXT_T *context_ptr; //!< Parent context.
154
155 WFC_SOURCE_OR_MASK_T *source_ptr; //!< Source associated with this element.
156 WFC_SOURCE_OR_MASK_T *mask_ptr; //!< Mask associated with this element.
157
158 bool is_in_scene; //!< Indicates if this element is within the scene.
159
160 WFC_ELEMENT_ATTRIB_T attributes; //!< Element attributes.
161} WFC_ELEMENT_T;
162
163#define ELEMENT_POOL_COUNT 16
164#define ELEMENT_POOL_MAX_SUBPOOLS 8
165
166//! WFCElement handle modifier
167#define WFC_ELEMENT_MOD 0xE0000000
168
169//! Global state
170typedef struct
171{
172 bool is_initialised; //!< Set the first time wfcCreateDevice() is called.
173 VCOS_MUTEX_T mutex; //!< Global mutex.
174 VCOS_UNSIGNED handle_mod; //!< Process specific handle modifier
175 VCOS_BLOCKPOOL_T device_pool; //!< Devices allocated by this process
176 VCOS_BLOCKPOOL_T context_pool; //!< Contexts allocated by this process
177 VCOS_BLOCKPOOL_T element_pool; //!< Elements allocated by this process
178 VCOS_BLOCKPOOL_T source_pool; //!< Sources allocated by this process
179} WFC_CLIENT_STATE_T;
180
181//! Blockpool information for initialisation
182typedef struct WFC_BLOCKPOOL_INFO_tag
183{
184 VCOS_BLOCKPOOL_T *pool;
185 VCOS_UNSIGNED size;
186 VCOS_UNSIGNED count;
187 VCOS_UNSIGNED max_subpools;
188 const char *name;
189} WFC_BLOCKPOOL_INFO_T;
190
191//==============================================================================
192
193static VCOS_ONCE_T wfc_client_once; //!< For initialisation
194static WFC_CLIENT_STATE_T wfc_client_state; //!< Global state
195
196//! Initialisation data for the client blockpools
197static const WFC_BLOCKPOOL_INFO_T wfc_client_blockpool_info[] = {
198 { &wfc_client_state.device_pool, sizeof(WFC_DEVICE_T), DEVICE_POOL_COUNT, DEVICE_POOL_MAX_SUBPOOLS, "WFC device pool" },
199 { &wfc_client_state.context_pool, sizeof(WFC_CONTEXT_T), CONTEXT_POOL_COUNT, CONTEXT_POOL_MAX_SUBPOOLS, "WFC context pool" },
200 { &wfc_client_state.element_pool, sizeof(WFC_ELEMENT_T), ELEMENT_POOL_COUNT, ELEMENT_POOL_MAX_SUBPOOLS, "WFC element pool" },
201 { &wfc_client_state.source_pool, sizeof(WFC_SOURCE_OR_MASK_T), SOURCE_POOL_COUNT, SOURCE_POOL_MAX_SUBPOOLS, "WFC source pool" },
202};
203
204static VCOS_LOG_CAT_T log_cat = VCOS_LOG_INIT("wfc_client_func", WFC_LOG_LEVEL);
205
206//==============================================================================
207//!@name Static functions
208//!@{
209
210static void wfc_initialise_client_state(void);
211static WFC_DEVICE_T *wfc_device_from_handle(WFCDevice dev);
212static WFCDevice wfc_device_to_handle(WFC_DEVICE_T *device_ptr);
213static WFC_CONTEXT_T *wfc_context_from_handle(WFCContext ctx);
214static WFCContext wfc_context_to_handle(WFC_CONTEXT_T *context_ptr);
215static WFC_ELEMENT_T *wfc_element_from_handle(WFCElement element);
216static WFCElement wfc_element_to_handle(WFC_ELEMENT_T *element_ptr);
217static WFCElement wfc_element_link_to_handle(WFC_LINK_T *element_link_ptr);
218static WFC_SOURCE_OR_MASK_T *wfc_source_or_mask_from_handle(WFCHandle source_or_mask);
219static WFCHandle wfc_source_or_mask_to_handle(WFC_SOURCE_OR_MASK_T *source_or_mask_ptr);
220
221static WFC_CONTEXT_T *wfc_context_create
222 (WFC_DEVICE_T *device_ptr, WFCContextType context_type,
223 uint32_t screen_or_stream_num, WFCErrorCode *error);
224static void wfc_context_destroy(WFC_CONTEXT_T *context_ptr);
225
226static WFCHandle wfc_source_or_mask_create(bool is_source, WFCDevice dev, WFCContext ctx,
227 WFCNativeStreamType stream, const WFCint *attribList);
228static void wfc_source_or_mask_destroy(WFCDevice dev, WFCHandle source_or_mask);
229static void wfc_source_or_mask_acquire(WFC_SOURCE_OR_MASK_T *source_or_mask_ptr);
230static void wfc_source_or_mask_release(WFC_SOURCE_OR_MASK_T *source_or_mask_ptr);
231
232static void wfc_element_destroy(WFC_ELEMENT_T *element_ptr, void *unused);
233
234static void wfc_commit_iterator(WFC_ELEMENT_T *element_ptr, WFC_SCENE_T *scene);
235
236static void wfc_set_error_with_location(WFC_DEVICE_T *device, WFCErrorCode error, const char *func, int line);
237
238static bool wfc_check_no_attribs(const WFCint *attribList);
239static bool wfc_is_rotation(WFCint value);
240static bool wfc_is_scale_filter(WFCint value);
241static bool wfc_are_transparency_types(WFCint value);
242
243static int32_t wfc_round(float f);
244
245static void wfc_link_detach(WFC_LINK_T *link);
246static void wfc_link_attach(WFC_LINK_T *link, WFC_LINK_T *prev);
247static void wfc_link_init_null(WFC_LINK_T *link);
248static void wfc_link_init_empty(WFC_LINK_T *link);
249static void wfc_link_iterate(WFC_LINK_T *link, WFC_LINK_CALLBACK_T func, void *arg);
250
251static void wfc_source_or_mask_destroy_actual
252 (WFC_SOURCE_OR_MASK_T *source_or_mask_ptr, void *unused);
253
254static void wfc_client_scene_taken_cb(void *cb_data);
255static void wfc_client_wait_for_scene_taken(VCOS_SEMAPHORE_T *wait_sem, WFCContext ctx,
256 const char *calling_function);
257
258#define wfc_set_error(D, E) wfc_set_error_with_location(D, E, __FILE__, __LINE__)
259
260//!@} // (Static functions)
261
262//!@name OpenWF-C API functions
263//! Refer to the <a href="http://www.khronos.org/registry/wf/">OpenWF-C specification</a> for details.
264//!@{
265//==============================================================================
266// Device functions
267
268WFC_API_CALL WFCint WFC_APIENTRY
269 wfcEnumerateDevices(WFCint *deviceIds, WFCint deviceIdsCount,
270 const WFCint *filterList) WFC_APIEXIT
271{
272 bool filters_valid = true;
273
274 // Check for valid filter list. Somewhat redundant, as there is only one device,
275 // and it supports all screens.
276 if(filterList != NULL)
277 {
278 filters_valid &= (*filterList == WFC_DEVICE_FILTER_SCREEN_NUMBER);
279 filterList++;
280 filters_valid &= ((*filterList >= 0) && (*filterList <= WFC_ID_MAX_SCREENS));
281 filterList++;
282 filters_valid &= (*filterList == WFC_NONE);
283 } // if
284
285 if(vcos_verify(filters_valid))
286 {
287 if(deviceIds != NULL)
288 {
289 if(deviceIdsCount > 0)
290 {
291 *deviceIds = WFC_OUR_DEVICE_ID;
292 return WFC_NUM_OF_DEVICES;
293 } // if
294 else
295 {return 0;}
296 } // if
297 else
298 {return WFC_NUM_OF_DEVICES;}
299 } // if
300
301 return 0;
302} // wfcEnumerateDevices()
303
304//------------------------------------------------------------------------------
305
306WFC_API_CALL WFCDevice WFC_APIENTRY
307 wfcCreateDevice(WFCint deviceId, const WFCint *attribList) WFC_APIEXIT
308{
309 WFCDevice result = WFC_INVALID_HANDLE;
310
311 // This function will be called before anything else can be created, so is
312 // a good place to initialise the state.
313 vcos_once(&wfc_client_once, wfc_initialise_client_state);
314
315 if (!wfc_client_state.is_initialised)
316 return WFC_INVALID_HANDLE;
317
318 WFC_LOCK();
319
320 if ((deviceId == WFC_DEFAULT_DEVICE_ID || deviceId == WFC_OUR_DEVICE_ID)
321 && wfc_check_no_attribs(attribList))
322 {
323 WFC_DEVICE_T *device = vcos_blockpool_calloc(&wfc_client_state.device_pool);
324
325 if(vcos_verify(device != NULL))
326 {
327 if (wfc_server_connect() != VCOS_SUCCESS)
328 {
329 vcos_blockpool_free(device);
330 vcos_log_error("%s: failed to connect to server", VCOS_FUNCTION);
331 }
332 else
333 {
334 device->error = WFC_ERROR_NONE;
335 wfc_link_init_empty(&device->contexts);
336 result = wfc_device_to_handle(device);
337 }
338 } // if
339 } // if
340
341 WFC_UNLOCK();
342
343 return result;
344} // wfcCreateDevice()
345
346//------------------------------------------------------------------------------
347
348WFC_API_CALL WFCErrorCode WFC_APIENTRY
349 wfcGetError(WFCDevice dev) WFC_APIEXIT
350{
351 WFCErrorCode result;
352
353 WFC_LOCK();
354
355 WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
356
357 if(vcos_verify(device_ptr != NULL))
358 {
359 result = device_ptr->error;
360 device_ptr->error = WFC_ERROR_NONE;
361 } // if
362 else
363 {result = WFC_ERROR_BAD_DEVICE;}
364
365 WFC_UNLOCK();
366
367 return result;
368} // wfcGetError()
369
370//------------------------------------------------------------------------------
371
372WFC_API_CALL WFCint WFC_APIENTRY
373 wfcGetDeviceAttribi(WFCDevice dev, WFCDeviceAttrib attrib) WFC_APIEXIT
374{
375 WFC_LOCK();
376
377 WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
378
379 if (!vcos_verify(device_ptr != NULL))
380 {
381 // Behaviour is unspecified if dev is null, so do something sensible.
382 vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
383 WFC_UNLOCK();
384 return 0;
385 }
386
387 WFCint result = 0;
388
389 switch (attrib)
390 {
391 case WFC_DEVICE_CLASS:
392 result = WFC_DEVICE_CLASS_FULLY_CAPABLE;
393 break;
394 case WFC_DEVICE_ID:
395 result = WFC_OUR_DEVICE_ID;
396 break;
397 default:
398 wfc_set_error(device_ptr, WFC_ERROR_BAD_ATTRIBUTE);
399 } // switch
400
401 WFC_UNLOCK();
402
403 return result;
404} // wfcGetDeviceAttribi()
405
406//------------------------------------------------------------------------------
407
408WFC_API_CALL WFCErrorCode WFC_APIENTRY
409 wfcDestroyDevice(WFCDevice dev) WFC_APIEXIT
410{
411 WFCErrorCode result;
412
413 WFC_LOCK();
414
415 WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
416
417 if(vcos_verify(device_ptr != NULL))
418 {
419 // Destroy all of the contexts associated with the device. This will in turn
420 // destroy all of the sources, masks and elements associated with each context.
421 wfc_link_iterate(&device_ptr->contexts, (WFC_LINK_CALLBACK_T) wfc_context_destroy, NULL);
422
423 vcos_blockpool_free(device_ptr);
424
425 wfc_server_disconnect();
426
427 result = WFC_ERROR_NONE;
428 } // if
429 else
430 {result = WFC_ERROR_BAD_DEVICE;}
431
432 WFC_UNLOCK();
433
434 return result;
435} // wfcDestroyDevice()
436
437//==============================================================================
438// Context functions
439
440WFC_API_CALL WFCContext WFC_APIENTRY
441 wfcCreateOnScreenContext(WFCDevice dev,
442 WFCint screenNumber,
443 const WFCint *attribList) WFC_APIEXIT
444{
445 WFC_LOCK();
446
447 WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
448
449 if (!vcos_verify(device_ptr != NULL))
450 {
451 vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
452 WFC_UNLOCK();
453 return WFC_INVALID_HANDLE;
454 }
455
456 WFCContext context = WFC_INVALID_HANDLE;
457
458 if (screenNumber < 0 || screenNumber >= WFC_ID_MAX_SCREENS)
459 {wfc_set_error(device_ptr, WFC_ERROR_UNSUPPORTED);}
460 else if (!wfc_check_no_attribs(attribList))
461 {wfc_set_error(device_ptr, WFC_ERROR_BAD_ATTRIBUTE);}
462 else
463 {
464 WFC_CONTEXT_T *context_ptr;
465
466 WFCErrorCode error;
467
468 // Create on-screen context_ptr
469 context_ptr = wfc_context_create
470 (device_ptr, WFC_CONTEXT_TYPE_ON_SCREEN, screenNumber, &error);
471
472 // Insert new context_ptr into list of contexts
473 if(context_ptr)
474 {
475 wfc_link_attach(&context_ptr->link, &device_ptr->contexts);
476
477 context = wfc_context_to_handle(context_ptr);
478 } // if
479 else
480 {wfc_set_error(device_ptr, error);}
481 } // else
482
483 WFC_UNLOCK();
484
485 return context;
486} // wfcCreateOnScreenContext()
487
488//------------------------------------------------------------------------------
489
490WFC_API_CALL WFCContext WFC_APIENTRY
491 wfcCreateOffScreenContext(WFCDevice dev,
492 WFCNativeStreamType stream,
493 const WFCint *attribList) WFC_APIEXIT
494{
495 WFC_LOCK();
496
497 WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
498
499 if (!vcos_verify(device_ptr != NULL))
500 {
501 vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
502 WFC_UNLOCK();
503 return WFC_INVALID_HANDLE;
504 }
505
506 WFCContext context = WFC_INVALID_HANDLE;
507
508 if(stream == WFC_INVALID_HANDLE)
509 {wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);}
510 else if(wfc_stream_used_for_off_screen(stream))
511 {wfc_set_error(device_ptr, WFC_ERROR_IN_USE);}
512 else if (!wfc_check_no_attribs(attribList))
513 {wfc_set_error(device_ptr, WFC_ERROR_BAD_ATTRIBUTE);}
514 else
515 {
516 WFC_CONTEXT_T *context_ptr;
517
518 WFCErrorCode error;
519
520 // Create on-screen context_ptr
521 context_ptr = wfc_context_create
522 (device_ptr, WFC_CONTEXT_TYPE_OFF_SCREEN, stream, &error);
523
524 // Insert new context_ptr into list of contexts
525 if(context_ptr)
526 {
527 wfc_link_attach(&context_ptr->link, &device_ptr->contexts);
528
529 context = wfc_context_to_handle(context_ptr);
530
531 wfc_stream_register_off_screen(stream, true);
532 } // if
533 else
534 {wfc_set_error(device_ptr, error);}
535 } // else
536
537 WFC_UNLOCK();
538
539 return context;
540} // wfcCreateOffScreenContext()
541
542//------------------------------------------------------------------------------
543
544WFC_API_CALL void WFC_APIENTRY
545 wfcCommit(WFCDevice dev, WFCContext ctx, WFCboolean wait) WFC_APIEXIT
546{
547 WFC_LOCK();
548
549 WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
550 WFC_CONTEXT_T *context_ptr = wfc_context_from_handle(ctx);
551 VCOS_STATUS_T status = VCOS_ENOSYS;
552 VCOS_SEMAPHORE_T wait_sem;
553 WFCboolean wait_for_sem = WFC_FALSE;
554
555 if (!vcos_verify(device_ptr != NULL))
556 {
557 vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
558 WFC_UNLOCK();
559 return;
560 }
561
562 // Send data for all elements
563 if(vcos_verify((context_ptr != NULL) && (context_ptr->device_ptr == device_ptr)))
564 {
565 WFC_SCENE_T *scene = &context_ptr->committed_scene;
566
567 memset(scene, 0, sizeof(*scene));
568 // Store scene in committed_scene structure
569 memcpy(&scene->context, &context_ptr->dynamic_attributes, sizeof(WFC_CONTEXT_DYNAMIC_ATTRIB_T));
570 scene->element_count = 0;
571 scene->commit_count = context_ptr->commit_count++;
572 wfc_link_iterate(&context_ptr->elements_in_scene,
573 (WFC_LINK_CALLBACK_T) wfc_commit_iterator, scene);
574
575 vcos_log_info("%s: dev 0x%X, ctx 0x%X commit %u", VCOS_FUNCTION, dev, ctx, context_ptr->committed_scene.commit_count);
576
577 if (context_ptr->active)
578 {
579 uint32_t commit_flags = WFC_SERVER_COMMIT_COMPOSE;
580
581 if (wait)
582 {
583 commit_flags |= WFC_SERVER_COMMIT_WAIT;
584
585 // Long running operation, so keep VC alive until it completes.
586 wfc_server_use_keep_alive();
587
588 status = vcos_semaphore_create(&wait_sem, "WFC commit", 0);
589 vcos_assert(status == VCOS_SUCCESS); // On platforms we care about.
590 wait_for_sem = WFC_TRUE;
591
592 do
593 {
594 status = wfc_server_commit_scene(ctx, &context_ptr->committed_scene,
595 commit_flags, wfc_client_scene_taken_cb, &wait_sem);
596
597 if (status == VCOS_EAGAIN)
598 {
599 // Another thread is competing for access to the context, so
600 // wait a little and try again.
601 vcos_sleep(1);
602 }
603 }
604 while (status == VCOS_EAGAIN);
605
606 if (status != VCOS_SUCCESS)
607 {
608 wait_for_sem = WFC_FALSE;
609 wfc_server_release_keep_alive();
610 vcos_semaphore_delete(&wait_sem);
611 }
612 }
613 else
614 {
615 status = wfc_server_commit_scene(ctx, &context_ptr->committed_scene,
616 commit_flags, NULL, NULL);
617 }
618
619 if (status != VCOS_SUCCESS)
620 {
621 vcos_log_info("%s: failed to compose scene: %d", VCOS_FUNCTION, status);
622 wfc_set_error(device_ptr, WFC_ERROR_BUSY);
623 }
624 }
625 } // if
626 else
627 {wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);}
628
629 WFC_UNLOCK();
630
631 // Wait for the scene to be taken outside the lock
632 if (wait_for_sem)
633 {
634 wfc_client_wait_for_scene_taken(&wait_sem, ctx, VCOS_FUNCTION);
635 }
636
637 vcos_log_trace("%s: complete", VCOS_FUNCTION);
638} // wfcCommit()
639
640//------------------------------------------------------------------------------
641
642WFC_API_CALL WFCint WFC_APIENTRY
643 wfcGetContextAttribi(WFCDevice dev, WFCContext ctx,
644 WFCContextAttrib attrib) WFC_APIEXIT
645{
646 WFC_LOCK();
647
648 WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
649 WFC_CONTEXT_T *context_ptr = wfc_context_from_handle(ctx);
650 WFCint result = 0;
651
652 if (!vcos_verify(device_ptr != NULL))
653 {
654 vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
655 WFC_UNLOCK();
656 return result;
657 }
658
659 if(vcos_verify((context_ptr != NULL) && (context_ptr->device_ptr == device_ptr)))
660 {
661 switch (attrib)
662 {
663 case WFC_CONTEXT_TYPE:
664 result = context_ptr->static_attributes.type;
665 break;
666 case WFC_CONTEXT_TARGET_WIDTH:
667 result = context_ptr->static_attributes.width;
668 break;
669 case WFC_CONTEXT_TARGET_HEIGHT:
670 result = context_ptr->static_attributes.height;
671 break;
672 case WFC_CONTEXT_LOWEST_ELEMENT:
673 {
674 WFC_LINK_T *first = &context_ptr->elements_in_scene;
675 WFC_LINK_T *current = first;
676
677 if(first->next == first)
678 {
679 // List is empty.
680 result = WFC_INVALID_HANDLE;
681 } // if
682 else
683 {
684 // First element in list is the lowest.
685 result = (WFCint) wfc_element_link_to_handle(current->next);
686 } // else
687 break;
688 }
689 case WFC_CONTEXT_ROTATION:
690 result = context_ptr->dynamic_attributes.rotation;
691 break;
692 case WFC_CONTEXT_BG_COLOR:
693 result = (WFCint) (context_ptr->dynamic_attributes.background_clr[WFC_BG_CLR_RED] * 255.0f) << 24 |
694 (WFCint) (context_ptr->dynamic_attributes.background_clr[WFC_BG_CLR_GREEN] * 255.0f) << 16 |
695 (WFCint) (context_ptr->dynamic_attributes.background_clr[WFC_BG_CLR_BLUE] * 255.0f) << 8 |
696 (WFCint) (context_ptr->dynamic_attributes.background_clr[WFC_BG_CLR_ALPHA] * 255.0f);
697 break;
698 default:
699 wfc_set_error(device_ptr, WFC_ERROR_BAD_ATTRIBUTE);
700 break;
701 } // switch
702 } // if
703 else
704 {wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);}
705
706 WFC_UNLOCK();
707
708 return result;
709} // wfcGetContextAttribi()
710
711//------------------------------------------------------------------------------
712
713WFC_API_CALL void WFC_APIENTRY
714 wfcGetContextAttribfv(WFCDevice dev, WFCContext ctx,
715 WFCContextAttrib attrib, WFCint count, WFCfloat *values) WFC_APIEXIT
716{
717 WFC_LOCK();
718
719 WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
720 WFC_CONTEXT_T *context_ptr = wfc_context_from_handle(ctx);
721
722 if (!vcos_verify(device_ptr != NULL))
723 {
724 vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
725 WFC_UNLOCK();
726 return;
727 }
728
729 if(vcos_verify((context_ptr != NULL) && (context_ptr->device_ptr == device_ptr)))
730 {
731 uint32_t i;
732
733 switch (attrib)
734 {
735 case WFC_CONTEXT_BG_COLOR:
736 if(vcos_verify(values != NULL) &&
737 vcos_verify(((uint32_t) values & 0x3) == 0) &&
738 vcos_verify(count == WFC_BG_CLR_SIZE))
739 {
740 for (i = 0; i < WFC_BG_CLR_SIZE; i++)
741 {values[i] = context_ptr->dynamic_attributes.background_clr[i];}
742 } // if
743 else
744 {wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);}
745 break;
746 default:
747 wfc_set_error(device_ptr, WFC_ERROR_BAD_ATTRIBUTE);
748 break;
749 } // switch
750 }
751 else
752 {wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);}
753
754 WFC_UNLOCK();
755} // wfcGetContextAttribfv()
756
757//------------------------------------------------------------------------------
758
759WFC_API_CALL void WFC_APIENTRY
760 wfcSetContextAttribi(WFCDevice dev, WFCContext ctx,
761 WFCContextAttrib attrib, WFCint value) WFC_APIEXIT
762{
763 WFC_LOCK();
764
765 WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
766 WFC_CONTEXT_T *context_ptr = wfc_context_from_handle(ctx);
767
768 if (!vcos_verify(device_ptr != NULL))
769 {
770 vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
771 WFC_UNLOCK();
772 return;
773 }
774
775 if(vcos_verify((context_ptr != NULL) && (context_ptr->device_ptr == device_ptr)))
776 {
777 switch(attrib)
778 {
779 case WFC_CONTEXT_ROTATION:
780 if(wfc_is_rotation(value))
781 {context_ptr->dynamic_attributes.rotation = value;}
782 else
783 {wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);}
784 break;
785 case WFC_CONTEXT_BG_COLOR:
786 {
787 int32_t i;
788 for(i = WFC_BG_CLR_SIZE - 1; i >= 0; i--)
789 {
790 context_ptr->dynamic_attributes.background_clr[i]
791 = ((float) (value & 0xff)) / 255.0f;
792 value >>= 8;
793 } // for
794 break;
795 }
796 default:
797 wfc_set_error(device_ptr, WFC_ERROR_BAD_ATTRIBUTE);
798 break;
799 } // switch
800 } // if
801 else
802 {wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);}
803
804 WFC_UNLOCK();
805} // wfcSetContextAttribi()
806
807//------------------------------------------------------------------------------
808
809WFC_API_CALL void WFC_APIENTRY
810 wfcSetContextAttribfv(WFCDevice dev, WFCContext ctx,
811 WFCContextAttrib attrib,
812 WFCint count, const WFCfloat *values) WFC_APIEXIT
813{
814 WFC_LOCK();
815
816 WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
817 WFC_CONTEXT_T *context_ptr = wfc_context_from_handle(ctx);
818
819 if (!vcos_verify(device_ptr != NULL))
820 {
821 vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
822 WFC_UNLOCK();
823 return;
824 }
825
826 if(vcos_verify((context_ptr != NULL) && (context_ptr->device_ptr == device_ptr)))
827 {
828 int i;
829
830 switch (attrib)
831 {
832 case WFC_CONTEXT_BG_COLOR:
833 if(vcos_verify((values != NULL) && (((uint32_t) values & 0x3) == 0)
834 && (count == WFC_BG_CLR_SIZE)))
835 {
836 for (i = 0; i < WFC_BG_CLR_SIZE; i++)
837 {context_ptr->dynamic_attributes.background_clr[i] = values[i];}
838 } // if
839 else
840 {wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);}
841 break;
842 default:
843 wfc_set_error(device_ptr, WFC_ERROR_BAD_ATTRIBUTE);
844 break;
845 } // switch
846 } // if
847 else
848 {wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);}
849
850 WFC_UNLOCK();
851} // wfcSetContextAttribfv()
852
853//------------------------------------------------------------------------------
854
855WFC_API_CALL void WFC_APIENTRY
856 wfcDestroyContext(WFCDevice dev, WFCContext ctx) WFC_APIEXIT
857{
858 WFC_LOCK();
859
860 WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
861 WFC_CONTEXT_T *context_ptr = wfc_context_from_handle(ctx);
862
863 vcos_log_trace("%s: context = 0x%X", VCOS_FUNCTION, ctx);
864
865 if (!vcos_verify(device_ptr != NULL))
866 {
867 vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
868 WFC_UNLOCK();
869 return;
870 }
871
872 if(vcos_verify((context_ptr != NULL) && (context_ptr->device_ptr == device_ptr)))
873 {
874 wfc_context_destroy(context_ptr);
875 }
876 else
877 {wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);}
878
879 WFC_UNLOCK();
880} // wfcDestroyContext()
881
882//==============================================================================
883// Source functions
884
885WFC_API_CALL WFCSource WFC_APIENTRY wfcCreateSourceFromStream(WFCDevice dev, WFCContext ctx,
886 WFCNativeStreamType stream,
887 const WFCint *attribList) WFC_APIEXIT
888{
889 WFCSource source;
890
891 WFC_LOCK();
892
893 source = (WFCSource) wfc_source_or_mask_create(WFC_IS_SOURCE, dev, ctx, stream, attribList);
894
895 WFC_UNLOCK();
896
897 return source;
898} // wfcCreateSourceFromStream()
899
900//------------------------------------------------------------------------------
901
902WFC_API_CALL void WFC_APIENTRY
903 wfcDestroySource(WFCDevice dev, WFCSource src) WFC_APIEXIT
904{
905 vcos_log_trace("%s: source = 0x%X", VCOS_FUNCTION, src);
906
907 WFC_LOCK();
908 wfc_source_or_mask_destroy(dev, (WFCHandle) src);
909 WFC_UNLOCK();
910} // wfcDestroySource()
911
912//==============================================================================
913// Mask functions
914
915WFC_API_CALL WFCMask WFC_APIENTRY
916 wfcCreateMaskFromStream(WFCDevice dev, WFCContext ctx,
917 WFCNativeStreamType stream,
918 const WFCint *attribList) WFC_APIEXIT
919{
920 WFCMask mask;
921
922 WFC_LOCK();
923
924 mask = (WFCMask) wfc_source_or_mask_create(WFC_IS_MASK, dev, ctx, stream, attribList);
925
926 WFC_UNLOCK();
927
928 return mask;
929} // wfcCreateMaskFromStream()
930
931//------------------------------------------------------------------------------
932
933WFC_API_CALL void WFC_APIENTRY
934 wfcDestroyMask(WFCDevice dev, WFCMask msk) WFC_APIEXIT
935{
936 WFC_LOCK();
937 wfc_source_or_mask_destroy(dev, (WFCHandle) msk);
938 WFC_UNLOCK();
939} // wfcDestroyMask()
940
941//==============================================================================
942// Element functions
943
944WFC_API_CALL WFCElement WFC_APIENTRY
945 wfcCreateElement(WFCDevice dev, WFCContext ctx,
946 const WFCint *attribList) WFC_APIEXIT
947{
948 WFC_LOCK();
949
950 WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
951 WFC_CONTEXT_T *context_ptr = wfc_context_from_handle(ctx);
952
953 WFCElement element = WFC_INVALID_HANDLE;
954
955 if (!vcos_verify(device_ptr != NULL))
956 {
957 vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
958 WFC_UNLOCK();
959 return WFC_INVALID_HANDLE;
960 }
961
962 if(vcos_verify((context_ptr != NULL) && (context_ptr->device_ptr == device_ptr)))
963 {
964 if(wfc_check_no_attribs(attribList))
965 {
966 WFC_ELEMENT_T *element_ptr = vcos_blockpool_calloc(&wfc_client_state.element_pool);
967 const WFC_ELEMENT_ATTRIB_T element_attrib_default = WFC_ELEMENT_ATTRIB_DEFAULT;
968
969 if(element_ptr != NULL)
970 {
971 wfc_link_init_null(&element_ptr->link);
972 element_ptr->context_ptr = context_ptr;
973 element_ptr->attributes = element_attrib_default;
974
975 wfc_link_attach(&element_ptr->link, &context_ptr->elements_not_in_scene);
976
977 element = wfc_element_to_handle(element_ptr);
978 } // if
979 else
980 {wfc_set_error(device_ptr, WFC_ERROR_OUT_OF_MEMORY);}
981 } // if
982 else
983 {wfc_set_error(device_ptr, WFC_ERROR_BAD_ATTRIBUTE);}
984 } // if
985 else
986 {wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);}
987
988 WFC_UNLOCK();
989
990 return element;
991} // wfcCreateElement()
992
993//------------------------------------------------------------------------------
994
995WFC_API_CALL WFCint WFC_APIENTRY
996 wfcGetElementAttribi(WFCDevice dev, WFCElement elm,
997 WFCElementAttrib attrib) WFC_APIEXIT
998{
999 WFC_LOCK();
1000
1001 WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
1002 WFC_ELEMENT_T *element_ptr = wfc_element_from_handle(elm);
1003
1004 WFCint result = 0;
1005
1006 if (!vcos_verify(device_ptr != NULL))
1007 {
1008 vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
1009 WFC_UNLOCK();
1010 return result;
1011 }
1012
1013 if(vcos_verify((element_ptr != NULL) && (element_ptr->context_ptr != NULL)
1014 && (element_ptr->context_ptr->device_ptr == device_ptr)))
1015 {
1016 switch (attrib)
1017 {
1018 case WFC_ELEMENT_SOURCE:
1019 result = (WFCint)wfc_source_or_mask_to_handle(element_ptr->source_ptr);
1020 break;
1021 case WFC_ELEMENT_SOURCE_FLIP:
1022 result = element_ptr->attributes.flip;
1023 break;
1024 case WFC_ELEMENT_SOURCE_ROTATION:
1025 result = element_ptr->attributes.rotation;
1026 break;
1027 case WFC_ELEMENT_SOURCE_SCALE_FILTER:
1028 result = element_ptr->attributes.scale_filter;
1029 break;
1030 case WFC_ELEMENT_TRANSPARENCY_TYPES:
1031 result = element_ptr->attributes.transparency_types;
1032 break;
1033 case WFC_ELEMENT_GLOBAL_ALPHA:
1034 result = wfc_round(element_ptr->attributes.global_alpha * 255.0f);
1035 break;
1036 case WFC_ELEMENT_MASK:
1037 result = (WFCint)wfc_source_or_mask_to_handle(element_ptr->mask_ptr);
1038 break;
1039 default:
1040 wfc_set_error(device_ptr, WFC_ERROR_BAD_ATTRIBUTE);
1041 break;
1042 } // switch
1043 } // if
1044 else
1045 {wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);}
1046
1047 WFC_UNLOCK();
1048
1049 return result;
1050} // wfcGetElementAttribi()
1051
1052//------------------------------------------------------------------------------
1053
1054WFC_API_CALL WFCfloat WFC_APIENTRY
1055 wfcGetElementAttribf(WFCDevice dev, WFCElement elm,
1056 WFCElementAttrib attrib) WFC_APIEXIT
1057{
1058 WFC_LOCK();
1059
1060 WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
1061 WFC_ELEMENT_T *element_ptr = wfc_element_from_handle(elm);
1062
1063 WFCfloat result = 0;
1064
1065 if (!vcos_verify(device_ptr != NULL))
1066 {
1067 vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
1068 WFC_UNLOCK();
1069 return result;
1070 }
1071
1072 if(vcos_verify((element_ptr != NULL) && (element_ptr->context_ptr != NULL)
1073 && (element_ptr->context_ptr->device_ptr == device_ptr)))
1074 {
1075 switch (attrib) {
1076 case WFC_ELEMENT_GLOBAL_ALPHA:
1077 result = element_ptr->attributes.global_alpha;
1078 break;
1079 default:
1080 wfc_set_error(device_ptr, WFC_ERROR_BAD_ATTRIBUTE);
1081 break;
1082 }
1083 }
1084 else
1085 {wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);}
1086
1087 WFC_UNLOCK();
1088
1089 return result;
1090} // wfcGetElementAttribf()
1091
1092//------------------------------------------------------------------------------
1093
1094WFC_API_CALL void WFC_APIENTRY
1095 wfcGetElementAttribiv(WFCDevice dev, WFCElement elm,
1096 WFCElementAttrib attrib, WFCint count, WFCint *values) WFC_APIEXIT
1097{
1098 WFC_LOCK();
1099
1100 WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
1101 WFC_ELEMENT_T *element_ptr = wfc_element_from_handle(elm);
1102
1103 if (!vcos_verify(device_ptr != NULL))
1104 {
1105 vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
1106 WFC_UNLOCK();
1107 return;
1108 }
1109
1110 if(vcos_verify((element_ptr != NULL) && (element_ptr->context_ptr != NULL)
1111 && (element_ptr->context_ptr->device_ptr == device_ptr)))
1112 {
1113 int i;
1114
1115 switch (attrib) {
1116 case WFC_ELEMENT_DESTINATION_RECTANGLE:
1117 if (values && count == WFC_RECT_SIZE)
1118 for (i = 0; i < WFC_RECT_SIZE; i++)
1119 values[i] = element_ptr->attributes.dest_rect[i];
1120 else
1121 wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);
1122 break;
1123 case WFC_ELEMENT_SOURCE_RECTANGLE:
1124 if (values && !((size_t)values & 3) && count == WFC_RECT_SIZE)
1125 {
1126 for (i = 0; i < WFC_RECT_SIZE; i++)
1127 values[i] = (WFCint) element_ptr->attributes.src_rect[i];
1128 } // if
1129 else
1130 wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);
1131 break;
1132 default:
1133 wfc_set_error(device_ptr, WFC_ERROR_BAD_ATTRIBUTE);
1134 break;
1135 }
1136 }
1137 else
1138 {wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);}
1139
1140 WFC_UNLOCK();
1141} // wfcGetElementAttribiv()
1142
1143//------------------------------------------------------------------------------
1144
1145WFC_API_CALL void WFC_APIENTRY
1146 wfcGetElementAttribfv(WFCDevice dev, WFCElement elm,
1147 WFCElementAttrib attrib, WFCint count, WFCfloat *values) WFC_APIEXIT
1148{
1149 WFC_LOCK();
1150
1151 WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
1152 WFC_ELEMENT_T *element_ptr = wfc_element_from_handle(elm);
1153
1154 if (!vcos_verify(device_ptr != NULL))
1155 {
1156 vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
1157 WFC_UNLOCK();
1158 return;
1159 }
1160
1161 if(vcos_verify((element_ptr != NULL) && (element_ptr->context_ptr != NULL)
1162 && (element_ptr->context_ptr->device_ptr == device_ptr)))
1163 {
1164 uint32_t i;
1165
1166 switch(attrib)
1167 {
1168 case WFC_ELEMENT_DESTINATION_RECTANGLE:
1169 if(values && !((size_t)values & 3) && (count == WFC_RECT_SIZE))
1170 {
1171 for (i = 0; i < WFC_RECT_SIZE; i++)
1172 {values[i] = (WFCfloat) element_ptr->attributes.dest_rect[i];}
1173 } // if
1174 else
1175 {wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);}
1176 break;
1177 case WFC_ELEMENT_SOURCE_RECTANGLE:
1178 if(values && !((size_t)values & 3) && (count == WFC_RECT_SIZE))
1179 {
1180 for (i = 0; i < WFC_RECT_SIZE; i++)
1181 {values[i] = element_ptr->attributes.src_rect[i];}
1182 } // if
1183 else
1184 {wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);}
1185 break;
1186 default:
1187 wfc_set_error(device_ptr, WFC_ERROR_BAD_ATTRIBUTE);
1188 break;
1189 } // switch
1190 } // if
1191 else
1192 {wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);}
1193
1194 WFC_UNLOCK();
1195} // wfcGetElementAttribfv()
1196
1197//------------------------------------------------------------------------------
1198
1199WFC_API_CALL void WFC_APIENTRY
1200 wfcSetElementAttribi(WFCDevice dev, WFCElement elm,
1201 WFCElementAttrib attrib, WFCint value) WFC_APIEXIT
1202{
1203 WFC_LOCK();
1204
1205 WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
1206 WFC_ELEMENT_T *element_ptr = wfc_element_from_handle(elm);
1207
1208 if (!vcos_verify(device_ptr != NULL))
1209 {
1210 vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
1211 WFC_UNLOCK();
1212 return;
1213 }
1214
1215 if(vcos_verify((element_ptr != NULL) && (element_ptr->context_ptr != NULL)
1216 && (element_ptr->context_ptr->device_ptr == device_ptr)))
1217 {
1218 switch (attrib)
1219 {
1220 case WFC_ELEMENT_SOURCE:
1221 {
1222 WFC_SOURCE_OR_MASK_T *new_source_ptr = wfc_source_or_mask_from_handle(value);
1223
1224 if
1225 (
1226 ((new_source_ptr != NULL) && (element_ptr->context_ptr == new_source_ptr->context_ptr))
1227 || (new_source_ptr == NULL)
1228 )
1229 {
1230 wfc_source_or_mask_acquire(new_source_ptr);
1231 wfc_source_or_mask_release(element_ptr->source_ptr);
1232 element_ptr->source_ptr = new_source_ptr;
1233
1234 element_ptr->attributes.source_stream =
1235 element_ptr->source_ptr ? element_ptr->source_ptr->stream : WFC_INVALID_HANDLE;
1236 } // if
1237 else
1238 {wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);}
1239 break;
1240 }
1241 case WFC_ELEMENT_SOURCE_FLIP:
1242 {
1243 if (value == WFC_FALSE || value == WFC_TRUE)
1244 element_ptr->attributes.flip = value;
1245 else
1246 wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);
1247
1248 break;
1249 }
1250 case WFC_ELEMENT_SOURCE_ROTATION:
1251 {
1252 if (wfc_is_rotation(value))
1253 element_ptr->attributes.rotation = value;
1254 else
1255 wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);
1256
1257 break;
1258 }
1259 case WFC_ELEMENT_SOURCE_SCALE_FILTER:
1260 {
1261 if (wfc_is_scale_filter(value))
1262 element_ptr->attributes.scale_filter = value;
1263 else
1264 wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);
1265
1266 break;
1267 }
1268 case WFC_ELEMENT_TRANSPARENCY_TYPES:
1269 {
1270 if (wfc_are_transparency_types(value))
1271 element_ptr->attributes.transparency_types = value;
1272 else
1273 wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);
1274
1275 break;
1276 }
1277 case WFC_ELEMENT_GLOBAL_ALPHA:
1278 {
1279 if (value >= 0 && value <= 255)
1280 element_ptr->attributes.global_alpha = (float)value / 255.0f;
1281 else
1282 wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);
1283
1284 break;
1285 }
1286 case WFC_ELEMENT_MASK:
1287 {
1288 WFC_SOURCE_OR_MASK_T *new_mask_ptr = wfc_source_or_mask_from_handle(value);
1289
1290 if
1291 (
1292 ((new_mask_ptr != NULL) && (element_ptr->context_ptr == new_mask_ptr->context_ptr))
1293 || (new_mask_ptr == NULL)
1294 )
1295 {
1296 wfc_source_or_mask_release(element_ptr->mask_ptr);
1297 element_ptr->mask_ptr = new_mask_ptr;
1298 wfc_source_or_mask_acquire(element_ptr->mask_ptr);
1299
1300 element_ptr->attributes.mask_stream =
1301 element_ptr->mask_ptr ? element_ptr->mask_ptr->stream : WFC_INVALID_HANDLE;
1302 } // if
1303 else
1304 {wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);}
1305 break;
1306 }
1307 default:
1308 wfc_set_error(device_ptr, WFC_ERROR_BAD_ATTRIBUTE);
1309 break;
1310 } // switch
1311 } // if
1312 else
1313 {wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);}
1314
1315 WFC_UNLOCK();
1316} // wfcSetElementAttribi()
1317
1318//------------------------------------------------------------------------------
1319
1320WFC_API_CALL void WFC_APIENTRY
1321 wfcSetElementAttribf(WFCDevice dev, WFCElement elm,
1322 WFCElementAttrib attrib, WFCfloat value) WFC_APIEXIT
1323{
1324 WFC_LOCK();
1325
1326 WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
1327 WFC_ELEMENT_T *element_ptr = wfc_element_from_handle(elm);
1328
1329 if (!vcos_verify(device_ptr != NULL))
1330 {
1331 vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
1332 WFC_UNLOCK();
1333 return;
1334 }
1335
1336 if(vcos_verify((element_ptr != NULL) && (element_ptr->context_ptr != NULL)
1337 && (element_ptr->context_ptr->device_ptr == device_ptr)))
1338 {
1339 switch(attrib)
1340 {
1341 case WFC_ELEMENT_GLOBAL_ALPHA:
1342 if (value >= 0.0f && value <= 1.0f)
1343 element_ptr->attributes.global_alpha = value;
1344 else
1345 wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);
1346 break;
1347 default:
1348 wfc_set_error(device_ptr, WFC_ERROR_BAD_ATTRIBUTE);
1349 break;
1350 } // switch
1351 } // if
1352 else
1353 wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);
1354
1355 WFC_UNLOCK();
1356} // wfcSetElementAttribf()
1357
1358//------------------------------------------------------------------------------
1359
1360WFC_API_CALL void WFC_APIENTRY
1361 wfcSetElementAttribiv(WFCDevice dev, WFCElement elm,
1362 WFCElementAttrib attrib,
1363 WFCint count, const WFCint *values) WFC_APIEXIT
1364{
1365 WFC_LOCK();
1366
1367 WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
1368 WFC_ELEMENT_T *element_ptr = wfc_element_from_handle(elm);
1369
1370 if (!vcos_verify(device_ptr != NULL))
1371 {
1372 vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
1373 WFC_UNLOCK();
1374 return;
1375 }
1376
1377 if(vcos_verify((element_ptr != NULL) && (element_ptr->context_ptr != NULL)
1378 && (element_ptr->context_ptr->device_ptr == device_ptr)))
1379 {
1380 uint32_t i;
1381
1382 switch (attrib) {
1383 case WFC_ELEMENT_DESTINATION_RECTANGLE:
1384 if (values && !((size_t)values & 3) && count == WFC_RECT_SIZE)
1385 {
1386 for (i = 0; i < WFC_RECT_SIZE; i++)
1387 {element_ptr->attributes.dest_rect[i] = values[i];}
1388 } // if
1389 else
1390 {wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);}
1391 break;
1392 case WFC_ELEMENT_SOURCE_RECTANGLE:
1393 if (values && !((size_t)values & 3) && count == WFC_RECT_SIZE)
1394 {
1395 // TODO verify that source rectangle is within the source image.
1396 for (i = 0; i < WFC_RECT_SIZE; i++)
1397 {element_ptr->attributes.src_rect[i] = (float)values[i];}
1398 } // if
1399 else
1400 {wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);}
1401 break;
1402 default:
1403 wfc_set_error(device_ptr, WFC_ERROR_BAD_ATTRIBUTE);
1404 break;
1405 } // switch
1406 } // if
1407 else
1408 {wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);}
1409
1410 WFC_UNLOCK();
1411} // wfcSetElementAttribiv()
1412
1413//------------------------------------------------------------------------------
1414
1415WFC_API_CALL void WFC_APIENTRY
1416 wfcSetElementAttribfv(WFCDevice dev, WFCElement elm,
1417 WFCElementAttrib attrib,
1418 WFCint count, const WFCfloat *values) WFC_APIEXIT
1419{
1420 WFC_LOCK();
1421
1422 WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
1423 WFC_ELEMENT_T *element_ptr = wfc_element_from_handle(elm);
1424
1425 if (!vcos_verify(device_ptr != NULL))
1426 {
1427 vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
1428 WFC_UNLOCK();
1429 return;
1430 }
1431
1432 if(vcos_verify((element_ptr != NULL) && (element_ptr->context_ptr != NULL)
1433 && (element_ptr->context_ptr->device_ptr == device_ptr)))
1434 {
1435 uint32_t i;
1436
1437 switch (attrib)
1438 {
1439 case WFC_ELEMENT_DESTINATION_RECTANGLE:
1440 if (values && !((size_t)values & 3) && count == WFC_RECT_SIZE)
1441 {
1442 for (i = 0; i < WFC_RECT_SIZE; i++)
1443 {element_ptr->attributes.dest_rect[i] = (int)values[i];}
1444 } // if
1445 else
1446 {wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);}
1447 break;
1448 case WFC_ELEMENT_SOURCE_RECTANGLE:
1449 if (values && !((size_t)values & 3) && count == WFC_RECT_SIZE)
1450 {
1451 // TODO verify that source rectangle is within the source image.
1452 // Note that these are floats, so check if difference is < 0.00001,
1453 // as per spec, p37 (PDF p42)
1454 for (i = 0; i < WFC_RECT_SIZE; i++)
1455 {element_ptr->attributes.src_rect[i] = values[i];}
1456 } // if
1457 else
1458 {wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);}
1459 break;
1460 default:
1461 wfc_set_error(device_ptr, WFC_ERROR_BAD_ATTRIBUTE);
1462 break;
1463 } // switch
1464 } // if
1465 else
1466 {wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);}
1467
1468 WFC_UNLOCK();
1469} // wfcSetElementAttribfv()
1470
1471//------------------------------------------------------------------------------
1472
1473WFC_API_CALL void WFC_APIENTRY
1474 wfcInsertElement(WFCDevice dev, WFCElement elm, WFCElement subordinate) WFC_APIEXIT
1475{
1476 WFC_LOCK();
1477
1478 WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
1479 WFC_ELEMENT_T *element_ptr = wfc_element_from_handle(elm);
1480 WFC_ELEMENT_T *subordinate_ptr = wfc_element_from_handle(subordinate);
1481
1482 if (!vcos_verify(device_ptr != NULL))
1483 {
1484 vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
1485 WFC_UNLOCK();
1486 return;
1487 }
1488
1489 if(vcos_verify
1490 (
1491 (element_ptr != NULL) && (element_ptr->context_ptr != NULL)
1492 && (element_ptr->context_ptr->device_ptr == device_ptr)
1493 &&
1494 (
1495 (subordinate_ptr == NULL)
1496 || ((subordinate_ptr->context_ptr != NULL)
1497 && (subordinate_ptr->context_ptr->device_ptr == device_ptr))
1498 )
1499 ))
1500 {
1501 if(subordinate_ptr != NULL)
1502 {
1503 // Insert element after subordinate.
1504 if((element_ptr->context_ptr == subordinate_ptr->context_ptr) && subordinate_ptr->is_in_scene)
1505 {
1506 // Insert element in front of itself has no effect.
1507 if (elm != subordinate)
1508 {
1509 wfc_link_attach(&element_ptr->link, &subordinate_ptr->link);
1510 element_ptr->is_in_scene = true;
1511 }
1512 }
1513 else
1514 {wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);}
1515 } // if
1516 else
1517 {
1518 // Insert at the "bottom of the scene" - which is the end of the list.
1519 wfc_link_attach(&element_ptr->link, &element_ptr->context_ptr->elements_in_scene);
1520 element_ptr->is_in_scene = true;
1521 } // else
1522 }
1523 else
1524 {wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);}
1525
1526 WFC_UNLOCK();
1527} // wfcInsertElement()
1528
1529//------------------------------------------------------------------------------
1530
1531WFC_API_CALL void WFC_APIENTRY
1532 wfcRemoveElement(WFCDevice dev, WFCElement elm) WFC_APIEXIT
1533{
1534 WFC_LOCK();
1535
1536 WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
1537 WFC_ELEMENT_T *element_ptr = wfc_element_from_handle(elm);
1538
1539 if (!vcos_verify(device_ptr != NULL))
1540 {
1541 vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
1542 WFC_UNLOCK();
1543 return;
1544 }
1545
1546 if(vcos_verify((element_ptr != NULL) && (element_ptr->context_ptr != NULL)
1547 && (element_ptr->context_ptr->device_ptr == device_ptr)))
1548 {
1549 wfc_link_attach(&element_ptr->link, &element_ptr->context_ptr->elements_not_in_scene);
1550 element_ptr->is_in_scene = false;
1551 }
1552 else
1553 {wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);}
1554
1555 WFC_UNLOCK();
1556} // wfcRemoveElement()
1557
1558//------------------------------------------------------------------------------
1559
1560WFC_API_CALL WFCElement WFC_APIENTRY
1561 wfcGetElementAbove(WFCDevice dev, WFCElement elm) WFC_APIEXIT
1562{
1563 WFC_LOCK();
1564
1565 WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
1566 WFC_ELEMENT_T *element_ptr = wfc_element_from_handle(elm);
1567
1568 WFCElement result = WFC_INVALID_HANDLE;
1569
1570 if (!vcos_verify(device_ptr != NULL))
1571 {
1572 vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
1573 WFC_UNLOCK();
1574 return result;
1575 }
1576
1577 if(vcos_verify((element_ptr != NULL) && (element_ptr->context_ptr != NULL)
1578 && (element_ptr->context_ptr->device_ptr == device_ptr)))
1579 {
1580 if (element_ptr->is_in_scene)
1581 {
1582 if (element_ptr->link.next != &element_ptr->context_ptr->elements_in_scene)
1583 {result = wfc_element_link_to_handle(element_ptr->link.next);}
1584 }
1585 else
1586 {wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);}
1587 }
1588 else
1589 {wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);}
1590
1591 WFC_UNLOCK();
1592
1593 return result;
1594} // wfcGetElementAbove()
1595
1596//------------------------------------------------------------------------------
1597
1598WFC_API_CALL WFCElement WFC_APIENTRY
1599 wfcGetElementBelow(WFCDevice dev, WFCElement elm) WFC_APIEXIT
1600{
1601 WFC_LOCK();
1602
1603 WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
1604 WFC_ELEMENT_T *element_ptr = wfc_element_from_handle(elm);
1605
1606 WFCElement result = WFC_INVALID_HANDLE;
1607
1608 if (!vcos_verify(device_ptr != NULL))
1609 {
1610 vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
1611 WFC_UNLOCK();
1612 return result;
1613 }
1614
1615 if(vcos_verify((element_ptr != NULL) && (element_ptr->context_ptr != NULL)
1616 && (element_ptr->context_ptr->device_ptr == device_ptr)))
1617 {
1618 if (element_ptr->is_in_scene)
1619 {
1620 if (element_ptr->link.prev != &element_ptr->context_ptr->elements_in_scene)
1621 {result = wfc_element_link_to_handle(element_ptr->link.prev);}
1622 }
1623 else
1624 {wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);}
1625 }
1626 else
1627 {wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);}
1628
1629 WFC_UNLOCK();
1630
1631 return result;
1632} // wfcGetElementBelow()
1633
1634//------------------------------------------------------------------------------
1635
1636WFC_API_CALL void WFC_APIENTRY
1637 wfcDestroyElement(WFCDevice dev, WFCElement elm) WFC_APIEXIT
1638{
1639 vcos_log_trace("%s: element = 0x%X", VCOS_FUNCTION, elm);
1640
1641 WFC_LOCK();
1642
1643 WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
1644 WFC_ELEMENT_T *element_ptr = wfc_element_from_handle(elm);
1645
1646 if (!vcos_verify(device_ptr != NULL))
1647 {
1648 vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
1649 WFC_UNLOCK();
1650 return;
1651 }
1652
1653 if(vcos_verify((element_ptr != NULL) && (element_ptr->context_ptr != NULL)
1654 && (element_ptr->context_ptr->device_ptr == device_ptr)))
1655 {wfc_element_destroy(element_ptr, NULL);}
1656 else
1657 {wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);}
1658
1659 WFC_UNLOCK();
1660} // wfcDestroyElement()
1661
1662//==============================================================================
1663// Rendering
1664
1665WFC_API_CALL void WFC_APIENTRY
1666 wfcActivate(WFCDevice dev, WFCContext ctx) WFC_APIEXIT
1667{
1668 WFC_LOCK();
1669
1670 WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
1671 WFC_CONTEXT_T *context_ptr = wfc_context_from_handle(ctx);
1672 VCOS_STATUS_T status = VCOS_ENOSYS;
1673
1674 if (!vcos_verify(device_ptr != NULL))
1675 {
1676 vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
1677 WFC_UNLOCK();
1678 return;
1679 }
1680
1681 if(vcos_verify((context_ptr != NULL) && (context_ptr->device_ptr == device_ptr)))
1682 {
1683 wfc_server_activate(ctx);
1684
1685 context_ptr->active = true;
1686
1687 do
1688 {
1689 vcos_log_info("%s: dev 0x%X, ctx 0x%X commit %u", VCOS_FUNCTION, dev, ctx, context_ptr->committed_scene.commit_count);
1690
1691 status = wfc_server_commit_scene(ctx, &context_ptr->committed_scene,
1692 0, NULL, NULL);
1693
1694 if (status == VCOS_EAGAIN)
1695 {
1696 // Another thread is competing for access to the context, so
1697 // wait a little and try again.
1698 vcos_sleep(1);
1699 }
1700 }
1701 while (status == VCOS_EAGAIN);
1702
1703 if (status != VCOS_SUCCESS)
1704 {
1705 wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);
1706 }
1707 } //if
1708 else
1709 {wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);}
1710
1711 WFC_UNLOCK();
1712} // wfcActivate()
1713
1714//------------------------------------------------------------------------------
1715
1716WFC_API_CALL void WFC_APIENTRY
1717 wfcDeactivate(WFCDevice dev, WFCContext ctx) WFC_APIEXIT
1718{
1719 WFC_LOCK();
1720
1721 WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
1722 WFC_CONTEXT_T *context_ptr = wfc_context_from_handle(ctx);
1723
1724 if (!vcos_verify(device_ptr != NULL))
1725 {
1726 vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
1727 WFC_UNLOCK();
1728 return;
1729 }
1730
1731 if(vcos_verify((context_ptr != NULL) && (context_ptr->device_ptr == device_ptr)))
1732 {
1733 wfc_server_deactivate(ctx);
1734
1735 context_ptr->active = false;
1736 } else
1737 wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);
1738
1739 WFC_UNLOCK();
1740} // wfcDeactivate()
1741
1742//------------------------------------------------------------------------------
1743
1744WFC_API_CALL void WFC_APIENTRY
1745 wfcCompose(WFCDevice dev, WFCContext ctx, WFCboolean wait) WFC_APIEXIT
1746{
1747 WFC_LOCK();
1748
1749 WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
1750 WFC_CONTEXT_T *context_ptr = wfc_context_from_handle(ctx);
1751 VCOS_STATUS_T status = VCOS_ENOSYS;
1752 VCOS_SEMAPHORE_T wait_sem;
1753
1754 if (!vcos_verify(device_ptr != NULL))
1755 {
1756 vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
1757 WFC_UNLOCK();
1758 return;
1759 }
1760
1761 if(vcos_verify((context_ptr != NULL) && (context_ptr->device_ptr == device_ptr)))
1762 {
1763 // Only tell the server to compose if the context is not active, since it will
1764 // be automatically composed on commit when active
1765 if(!context_ptr->active)
1766 {
1767 uint32_t commit_flags = WFC_SERVER_COMMIT_COMPOSE;
1768
1769 vcos_log_info("%s: dev 0x%X, ctx 0x%X commit %u", VCOS_FUNCTION, dev, ctx, context_ptr->committed_scene.commit_count);
1770
1771 if (wait)
1772 {
1773 commit_flags |= WFC_SERVER_COMMIT_WAIT;
1774
1775 // Long running operation, so keep VC alive until it completes.
1776 wfc_server_use_keep_alive();
1777
1778 status = vcos_semaphore_create(&wait_sem, "WFC compose", 0);
1779 vcos_assert(status == VCOS_SUCCESS); // On platforms we care about.
1780
1781 do
1782 {
1783 status = wfc_server_commit_scene(ctx, &context_ptr->committed_scene,
1784 commit_flags, wfc_client_scene_taken_cb, &wait_sem);
1785
1786 if (status == VCOS_EAGAIN)
1787 {
1788 // Another thread is competing for access to the context, so
1789 // wait a little and try again.
1790 vcos_sleep(1);
1791 }
1792 }
1793 while (status == VCOS_EAGAIN);
1794
1795 if (status != VCOS_SUCCESS)
1796 {
1797 vcos_semaphore_delete(&wait_sem);
1798 wfc_server_release_keep_alive();
1799 }
1800 }
1801 else
1802 {
1803 status = wfc_server_commit_scene(ctx, &context_ptr->committed_scene,
1804 commit_flags, NULL, NULL);
1805 }
1806
1807 if (status != VCOS_SUCCESS)
1808 {
1809 vcos_log_info("%s: failed to compose scene: %d", VCOS_FUNCTION, status);
1810 wfc_set_error(device_ptr, WFC_ERROR_BUSY);
1811 }
1812 } // if
1813 else
1814 {wfc_set_error(device_ptr, WFC_ERROR_UNSUPPORTED);}
1815 }
1816 else
1817 {wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);}
1818
1819 WFC_UNLOCK();
1820
1821 // Wait for the scene to be taken outside the lock
1822 if (wait && status == VCOS_SUCCESS)
1823 {
1824 wfc_client_wait_for_scene_taken(&wait_sem, ctx, VCOS_FUNCTION);
1825 }
1826} // wfcCompose()
1827
1828//------------------------------------------------------------------------------
1829
1830WFC_API_CALL void WFC_APIENTRY
1831 wfcFence(WFCDevice dev, WFCContext ctx, WFCEGLDisplay dpy,
1832 WFCEGLSync sync) WFC_APIEXIT
1833{
1834 vcos_unused(dpy);
1835 vcos_unused(sync);
1836
1837 WFC_LOCK();
1838
1839 WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
1840 WFC_CONTEXT_T *context_ptr = wfc_context_from_handle(ctx);
1841
1842 if (!vcos_verify(device_ptr != NULL))
1843 {
1844 vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
1845 WFC_UNLOCK();
1846 return;
1847 }
1848
1849 // TODO wfcFence()
1850 vcos_assert(0);
1851
1852 if(vcos_verify((context_ptr != NULL) && (context_ptr->device_ptr == device_ptr)))
1853 {
1854 /* Set error as WFC_ERROR_ILLEGAL_ARGUMENT
1855 - if dpy is not a valid EGLDisplay
1856 - if sync is not a valid sync object
1857 - if sync’s EGL_SYNC_TYPE_KHR is not EGL_SYNC_REUSABLE_KHR
1858 */
1859 } // if
1860 else
1861 {wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);}
1862
1863 WFC_UNLOCK();
1864} // wfcFence()
1865
1866//==============================================================================
1867// Renderer and extension information
1868
1869WFC_API_CALL WFCint WFC_APIENTRY
1870 wfcGetStrings(WFCDevice dev,
1871 WFCStringID name,
1872 const char **strings,
1873 WFCint stringsCount) WFC_APIEXIT
1874{
1875 WFC_LOCK();
1876
1877 WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
1878 const char *name_string = NULL;
1879
1880 if (!vcos_verify(device_ptr != NULL))
1881 {
1882 vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
1883 WFC_UNLOCK();
1884 return 0;
1885 }
1886
1887 switch(name)
1888 {
1889 case WFC_VENDOR:
1890 name_string = "Broadcom";
1891 break;
1892 case WFC_RENDERER:
1893 name_string = "VideoCore IV HW";
1894 break;
1895 case WFC_VERSION:
1896 name_string = "1.0";
1897 break;
1898 case WFC_EXTENSIONS:
1899 name_string = "";
1900 break;
1901 default:
1902 wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);
1903 WFC_UNLOCK();
1904 return 0;
1905 } // switch
1906
1907 WFCint num_of_strings = 0;
1908
1909 if(stringsCount >= 0)
1910 {
1911 num_of_strings = 1;
1912 if((strings != NULL) && (stringsCount > 0))
1913 {
1914 *strings = name_string;
1915 } // if
1916 } // if
1917 else
1918 {
1919 wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);
1920 } // else
1921
1922 WFC_UNLOCK();
1923
1924 return num_of_strings;
1925} // wfcGetStrings()
1926
1927//------------------------------------------------------------------------------
1928
1929WFC_API_CALL WFCboolean WFC_APIENTRY
1930 wfcIsExtensionSupported(WFCDevice dev, const char *string) WFC_APIEXIT
1931{
1932 vcos_unused(string);
1933
1934 // TODO wfcIsExtensionSupported()
1935 vcos_assert(0);
1936
1937 if(!vcos_verify(dev != WFC_INVALID_HANDLE))
1938 {return WFC_FALSE;}
1939
1940 return WFC_FALSE;
1941}
1942
1943//!@} // (OpenWF-C API functions)
1944//==============================================================================
1945
1946static void wfc_initialise_client_state(void)
1947{
1948 size_t pool_index;
1949 const WFC_BLOCKPOOL_INFO_T *pool_info = wfc_client_blockpool_info;
1950 uint64_t pid = vcos_process_id_current();
1951
1952 // Logging
1953 vcos_log_set_level(&log_cat, WFC_LOG_LEVEL);
1954 vcos_log_register("wfc_client_func", &log_cat);
1955
1956 vcos_log_error("%s: entered", VCOS_FUNCTION);
1957
1958 // Allocate all the pools
1959 for (pool_index = 0; pool_index < countof(wfc_client_blockpool_info); pool_index++, pool_info++)
1960 {
1961 if (vcos_blockpool_create_on_heap(pool_info->pool, pool_info->count, pool_info->size,
1962 VCOS_BLOCKPOOL_ALIGN_DEFAULT, 0, pool_info->name) != VCOS_SUCCESS)
1963 goto fail;
1964
1965 vcos_blockpool_extend(pool_info->pool, pool_info->max_subpools - 1, pool_info->count);
1966 }
1967
1968 vcos_mutex_create(&wfc_client_state.mutex, NULL);
1969
1970 // Set up a handle modifier that is generally process specific. The shifting
1971 // around should put the ID on Linux in an otherwise fairly unused bit of the
1972 // handle, which makes debugging easier.
1973 wfc_client_state.handle_mod = (VCOS_UNSIGNED)((pid << 16) ^ (pid >> 16) ^ (pid >> 48));
1974
1975 wfc_client_state.is_initialised = true;
1976
1977 vcos_log_error("%s: success", VCOS_FUNCTION);
1978 // Success
1979 return;
1980
1981fail:
1982 vcos_log_error("%s: failed to allocate memory pools", VCOS_FUNCTION);
1983
1984 // pool_index and pool_info refer to the one that failed to allocate. Free
1985 // any pools already allocated.
1986 while (pool_index-- > 0)
1987 {
1988 pool_info--;
1989 vcos_blockpool_delete(pool_info->pool);
1990 }
1991}
1992
1993//------------------------------------------------------------------------------
1994
1995static WFC_DEVICE_T *wfc_device_from_handle(WFCDevice dev)
1996{
1997 VCOS_UNSIGNED handle_mod = WFC_DEVICE_MOD ^ wfc_client_state.handle_mod;
1998
1999 if (dev == WFC_INVALID_HANDLE)
2000 return NULL;
2001 return vcos_blockpool_elem_from_handle(&wfc_client_state.device_pool, dev ^ handle_mod);
2002}
2003
2004//------------------------------------------------------------------------------
2005
2006static WFCDevice wfc_device_to_handle(WFC_DEVICE_T *device_ptr)
2007{
2008 VCOS_UNSIGNED handle_mod = WFC_DEVICE_MOD ^ wfc_client_state.handle_mod;
2009 VCOS_UNSIGNED handle = vcos_blockpool_elem_to_handle(device_ptr);
2010
2011 if (handle == VCOS_BLOCKPOOL_INVALID_HANDLE)
2012 return WFC_INVALID_HANDLE;
2013
2014 return (WFCDevice)(handle ^ handle_mod);
2015}
2016
2017//------------------------------------------------------------------------------
2018
2019static WFC_CONTEXT_T *wfc_context_from_handle(WFCContext ctx)
2020{
2021 VCOS_UNSIGNED handle_mod = WFC_CONTEXT_MOD ^ wfc_client_state.handle_mod;
2022
2023 if (ctx == WFC_INVALID_HANDLE)
2024 return NULL;
2025
2026 return vcos_blockpool_elem_from_handle(&wfc_client_state.context_pool, ctx ^ handle_mod);
2027}
2028
2029//------------------------------------------------------------------------------
2030
2031static WFCContext wfc_context_to_handle(WFC_CONTEXT_T *context_ptr)
2032{
2033 VCOS_UNSIGNED handle_mod = WFC_CONTEXT_MOD ^ wfc_client_state.handle_mod;
2034 VCOS_UNSIGNED handle = vcos_blockpool_elem_to_handle(context_ptr);
2035
2036 if (handle == VCOS_BLOCKPOOL_INVALID_HANDLE)
2037 return WFC_INVALID_HANDLE;
2038
2039 return (WFCContext)(handle ^ handle_mod);
2040}
2041
2042//------------------------------------------------------------------------------
2043
2044static WFC_ELEMENT_T *wfc_element_from_handle(WFCElement element)
2045{
2046 VCOS_UNSIGNED handle_mod = WFC_ELEMENT_MOD ^ wfc_client_state.handle_mod;
2047
2048 if (element == WFC_INVALID_HANDLE)
2049 return NULL;
2050
2051 return vcos_blockpool_elem_from_handle(&wfc_client_state.element_pool, element ^ handle_mod);
2052}
2053
2054//------------------------------------------------------------------------------
2055
2056static WFCElement wfc_element_to_handle(WFC_ELEMENT_T *element_ptr)
2057{
2058 VCOS_UNSIGNED handle_mod = WFC_ELEMENT_MOD ^ wfc_client_state.handle_mod;
2059 VCOS_UNSIGNED handle = vcos_blockpool_elem_to_handle(element_ptr);
2060
2061 if (handle == VCOS_BLOCKPOOL_INVALID_HANDLE)
2062 return WFC_INVALID_HANDLE;
2063
2064 return (WFCElement)(handle ^ handle_mod);
2065}
2066
2067//------------------------------------------------------------------------------
2068
2069static WFCElement wfc_element_link_to_handle(WFC_LINK_T *element_link_ptr)
2070{
2071 return wfc_element_to_handle((WFC_ELEMENT_T *)((char *)element_link_ptr - offsetof(WFC_ELEMENT_T, link)));
2072}
2073
2074//------------------------------------------------------------------------------
2075
2076static WFC_SOURCE_OR_MASK_T *wfc_source_or_mask_from_handle(WFCHandle source_or_mask)
2077{
2078 VCOS_UNSIGNED handle_mod = WFC_SOURCE_MOD ^ wfc_client_state.handle_mod;
2079
2080 if (source_or_mask == WFC_INVALID_HANDLE)
2081 return NULL;
2082
2083 return vcos_blockpool_elem_from_handle(&wfc_client_state.source_pool, source_or_mask ^ handle_mod);
2084}
2085
2086//------------------------------------------------------------------------------
2087
2088static WFCHandle wfc_source_or_mask_to_handle(WFC_SOURCE_OR_MASK_T *source_or_mask_ptr)
2089{
2090 VCOS_UNSIGNED handle_mod = WFC_SOURCE_MOD ^ wfc_client_state.handle_mod;
2091 VCOS_UNSIGNED handle = vcos_blockpool_elem_to_handle(source_or_mask_ptr);
2092
2093 if (handle == VCOS_BLOCKPOOL_INVALID_HANDLE)
2094 return WFC_INVALID_HANDLE;
2095
2096 return (WFCHandle)(handle ^ handle_mod);
2097}
2098
2099//------------------------------------------------------------------------------
2100
2101//!@name
2102//! Macros used in wfc_context_create() to extract data returned from wfc_server_create_context().
2103//!@{
2104#define WFC_CONTEXT_WIDTH(data) ((data) >> 16)
2105#define WFC_CONTEXT_HEIGHT_OR_ERR(data) ((data) & 0xFFFF)
2106//!@}
2107
2108static WFC_CONTEXT_T *wfc_context_create
2109 (WFC_DEVICE_T *device_ptr, WFCContextType context_type,
2110 uint32_t screen_or_stream_num, WFCErrorCode *error)
2111{
2112 WFC_CONTEXT_T *context_ptr = vcos_blockpool_calloc(&wfc_client_state.context_pool);
2113 const WFC_CONTEXT_DYNAMIC_ATTRIB_T ctx_dyn_attrib_default = WFC_CONTEXT_DYNAMIC_ATTRIB_DEFAULT;
2114
2115 if(context_ptr != NULL)
2116 {
2117 uint64_t pid = vcos_process_id_current();
2118 uint32_t pid_lo = (uint32_t) pid;
2119 uint32_t pid_hi = (uint32_t) (pid >> 32);
2120
2121 uint32_t response = wfc_server_create_context(wfc_context_to_handle(context_ptr),
2122 context_type, screen_or_stream_num, pid_lo, pid_hi);
2123
2124 uint32_t height_or_err = WFC_CONTEXT_HEIGHT_OR_ERR(response);
2125 uint32_t width = WFC_CONTEXT_WIDTH(response);
2126
2127 if(width != 0)
2128 {
2129 wfc_link_init_null(&context_ptr->link);
2130
2131 context_ptr->device_ptr = device_ptr;
2132 wfc_link_init_empty(&context_ptr->sources);
2133 wfc_link_init_empty(&context_ptr->masks);
2134
2135 wfc_link_init_empty(&context_ptr->elements_not_in_scene);
2136 wfc_link_init_empty(&context_ptr->elements_in_scene);
2137 context_ptr->active = false;
2138
2139 context_ptr->dynamic_attributes = ctx_dyn_attrib_default;
2140 context_ptr->static_attributes.type = context_type;
2141 context_ptr->static_attributes.height = height_or_err;
2142 context_ptr->static_attributes.width = width;
2143
2144 if(context_type == WFC_CONTEXT_TYPE_OFF_SCREEN)
2145 {
2146 context_ptr->output_stream = screen_or_stream_num;
2147 }
2148 }
2149 else
2150 {
2151 vcos_blockpool_free(context_ptr);
2152 context_ptr = NULL;
2153 *error = (WFCErrorCode) response;
2154 }
2155 } // if
2156 else
2157 {*error = WFC_ERROR_OUT_OF_MEMORY;}
2158
2159 return context_ptr;
2160} // wfc_context_create()
2161
2162//------------------------------------------------------------------------------
2163
2164static void wfc_context_destroy(WFC_CONTEXT_T *context_ptr)
2165{
2166 // Detach output stream for off-screen contexts.
2167 wfc_stream_register_off_screen(context_ptr->output_stream, false);
2168
2169 // Remove from parent device's list of contexts.
2170 wfc_link_detach(&context_ptr->link);
2171
2172 // Destroy all components
2173 wfc_link_iterate(&context_ptr->elements_in_scene, (WFC_LINK_CALLBACK_T) wfc_element_destroy, NULL);
2174 wfc_link_iterate(&context_ptr->elements_not_in_scene, (WFC_LINK_CALLBACK_T) wfc_element_destroy, NULL);
2175 wfc_link_iterate(&context_ptr->sources, (WFC_LINK_CALLBACK_T) wfc_source_or_mask_destroy_actual, NULL);
2176 wfc_link_iterate(&context_ptr->masks, (WFC_LINK_CALLBACK_T) wfc_source_or_mask_destroy_actual, NULL);
2177
2178 wfc_server_destroy_context(wfc_context_to_handle(context_ptr));
2179
2180 vcos_blockpool_free(context_ptr);
2181} // wfc_context_destroy()
2182
2183//==============================================================================
2184
2185static WFCHandle wfc_source_or_mask_create(
2186 bool is_source, WFCDevice dev, WFCContext ctx,
2187 WFCNativeStreamType stream, const WFCint *attribList)
2188//!@brief Create a new image provider and associate it with a stream.
2189//!
2190//! wfcCreateSourceFromStream() and wfcCreateMaskFromStream() are essentially
2191//! wrappers for this function.
2192{
2193 WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
2194 WFC_CONTEXT_T *context_ptr = wfc_context_from_handle(ctx);
2195
2196 WFCHandle handle = WFC_INVALID_HANDLE;
2197
2198 if (!vcos_verify(device_ptr != NULL))
2199 {
2200 vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
2201 return handle;
2202 }
2203
2204 if(vcos_verify((context_ptr != NULL) && (context_ptr->device_ptr == device_ptr)))
2205 {
2206 if(!wfc_check_no_attribs(attribList))
2207 {
2208 wfc_set_error(device_ptr, WFC_ERROR_BAD_ATTRIBUTE);
2209 }
2210 else if(context_ptr->output_stream == stream)
2211 {
2212 // Verify that context isn't an input for this stream
2213 wfc_set_error(device_ptr, WFC_ERROR_IN_USE);
2214 }
2215 else if (!wfc_stream_register_source_or_mask(stream, true))
2216 {
2217 vcos_log_error("%s: failed to register stream 0x%x", VCOS_FUNCTION, stream);
2218 wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);
2219 }
2220 else
2221 {
2222 WFC_SOURCE_OR_MASK_T *source_or_mask_ptr = vcos_blockpool_calloc(&wfc_client_state.source_pool);
2223
2224 if(source_or_mask_ptr != NULL)
2225 {
2226 // Note that refcount is initialised to zero here, as a source or mask is
2227 // only in use when it is linked to an element.
2228
2229 wfc_link_init_null(&source_or_mask_ptr->link);
2230
2231 source_or_mask_ptr->is_source = is_source;
2232 source_or_mask_ptr->context_ptr = context_ptr;
2233 source_or_mask_ptr->stream = stream;
2234
2235 if(is_source)
2236 {
2237 wfc_link_attach(&source_or_mask_ptr->link, &context_ptr->sources);
2238 }
2239 else
2240 {
2241 wfc_link_attach(&source_or_mask_ptr->link, &context_ptr->masks);
2242 }
2243 handle = wfc_source_or_mask_to_handle(source_or_mask_ptr);
2244 }
2245 else
2246 {
2247 wfc_stream_register_source_or_mask(stream, false);
2248 vcos_log_error("%s: failed to allocate source/mask info for stream 0x%x", VCOS_FUNCTION, stream);
2249 wfc_set_error(device_ptr, WFC_ERROR_OUT_OF_MEMORY);
2250 }
2251 }
2252 }
2253 else
2254 {
2255 wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);
2256 }
2257
2258 return handle;
2259}
2260
2261//------------------------------------------------------------------------------
2262
2263static void wfc_source_or_mask_destroy(WFCDevice dev, WFCHandle source_or_mask)
2264//!@brief Destroy an image provider and dissociate its stream.
2265//!
2266//! wfcDestroySource() and wfcDestroyMask() are essentially wrappers for this function.
2267{
2268 WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
2269 WFC_SOURCE_OR_MASK_T *source_or_mask_ptr = wfc_source_or_mask_from_handle(source_or_mask);
2270
2271 if (!vcos_verify(device_ptr != NULL))
2272 {
2273 vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
2274 return;
2275 }
2276
2277 if((source_or_mask_ptr != NULL) && (source_or_mask_ptr->context_ptr != NULL)
2278 && (source_or_mask_ptr->context_ptr->device_ptr == device_ptr))
2279 {
2280 wfc_source_or_mask_destroy_actual(source_or_mask_ptr, NULL);
2281 }
2282 else
2283 {
2284 wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);
2285 }
2286}
2287
2288//------------------------------------------------------------------------------
2289
2290static void wfc_source_or_mask_acquire(WFC_SOURCE_OR_MASK_T *source_or_mask_ptr)
2291//! Indicate that the image provider is now linked to an element.
2292{
2293 vcos_log_trace("%s: %p refcount %d", VCOS_FUNCTION, source_or_mask_ptr,
2294 source_or_mask_ptr ? source_or_mask_ptr->refcount : 0);
2295 if(source_or_mask_ptr != NULL)
2296 {source_or_mask_ptr->refcount++;}
2297} // wfc_source_or_mask_acquire()
2298
2299//------------------------------------------------------------------------------
2300
2301static void wfc_source_or_mask_release(WFC_SOURCE_OR_MASK_T *source_or_mask_ptr)
2302//! Indicate the the image provider is no longer linked to an element; destroy if previously requested.
2303{
2304 vcos_log_trace("%s: %p refcount %d", VCOS_FUNCTION, source_or_mask_ptr,
2305 source_or_mask_ptr ? source_or_mask_ptr->refcount : 0);
2306 if(source_or_mask_ptr != NULL)
2307 {
2308 if(source_or_mask_ptr->refcount > 0)
2309 {
2310 source_or_mask_ptr->refcount--;
2311 }
2312
2313 // If no-one is using this source or mask, and a request has previously
2314 // been made to destroy it, do so now.
2315 if((source_or_mask_ptr->refcount == 0) && source_or_mask_ptr->destroy_pending)
2316 {
2317 wfc_source_or_mask_destroy_actual(source_or_mask_ptr, NULL);
2318 }
2319 }
2320}
2321
2322//------------------------------------------------------------------------------
2323
2324static void wfc_source_or_mask_destroy_actual(WFC_SOURCE_OR_MASK_T *source_or_mask_ptr, void *unused)
2325{
2326 source_or_mask_ptr->destroy_pending = true;
2327
2328 if(source_or_mask_ptr->refcount == 0)
2329 {
2330 vcos_log_trace("%s: %p source 0x%x stream 0x%x", VCOS_FUNCTION, source_or_mask_ptr,
2331 wfc_source_or_mask_to_handle(source_or_mask_ptr), source_or_mask_ptr->stream);
2332
2333 wfc_stream_register_source_or_mask(source_or_mask_ptr->stream, false);
2334
2335 // Remove from parent context's list of sources or masks.
2336 wfc_link_detach(&source_or_mask_ptr->link);
2337
2338 // Destroy.
2339 vcos_blockpool_free(source_or_mask_ptr);
2340 }
2341 else
2342 {
2343 vcos_log_trace("%s: pending: %p refcount: %d", VCOS_FUNCTION, source_or_mask_ptr, source_or_mask_ptr->refcount);
2344 }
2345}
2346
2347//==============================================================================
2348
2349static void wfc_element_destroy(WFC_ELEMENT_T *element_ptr, void *unused)
2350{
2351 vcos_log_trace("%s: %p", VCOS_FUNCTION, element_ptr);
2352
2353 // Release source and mask (if present); destroy if previously requested.
2354 wfc_source_or_mask_release(element_ptr->source_ptr);
2355 wfc_source_or_mask_release(element_ptr->mask_ptr);
2356
2357 element_ptr->source_ptr = NULL;
2358 element_ptr->mask_ptr = NULL;
2359
2360 wfc_link_detach(&element_ptr->link);
2361
2362 vcos_blockpool_free(element_ptr);
2363} // wfc_element_destroy()
2364
2365//==============================================================================
2366
2367static void wfc_commit_iterator(WFC_ELEMENT_T *element_ptr, WFC_SCENE_T *scene)
2368{
2369 // Elements with source or destination rectangles having zero width or height
2370 // must not displayed
2371 if
2372 (
2373 (element_ptr->attributes.dest_rect[WFC_RECT_WIDTH] == 0)
2374 || (element_ptr->attributes.dest_rect[WFC_RECT_HEIGHT] == 0)
2375 || (element_ptr->attributes.src_rect[WFC_RECT_WIDTH] < 0.00001)
2376 || (element_ptr->attributes.src_rect[WFC_RECT_HEIGHT] < 0.00001)
2377 )
2378 {return;}
2379
2380 // Elements with a (near-)zero global alpha are transparent, so ignore them
2381 if
2382 (
2383 (element_ptr->attributes.transparency_types & WFC_TRANSPARENCY_ELEMENT_GLOBAL_ALPHA)
2384 && (element_ptr->attributes.global_alpha < 0.001)
2385 )
2386 {return;}
2387
2388 // Copy element attributes into scene and increment count
2389 memcpy(&scene->elements[scene->element_count++], &element_ptr->attributes, sizeof(WFC_ELEMENT_ATTRIB_T));
2390} // wfc_commit_iterator()
2391
2392//==============================================================================
2393
2394static void wfc_set_error_with_location(WFC_DEVICE_T *device, WFCErrorCode error, const char *func, int line)
2395//! Update device's error code (but only if previously cleared).
2396{
2397 vcos_log_error("%s: device %p error 0x%x at line %d", func, device, error, line);
2398 if((device != NULL) && (device->error == WFC_ERROR_NONE))
2399 {device->error = error;}
2400} // wfc_set_error()
2401
2402//==============================================================================
2403
2404static bool wfc_check_no_attribs(const WFCint *attribList)
2405//! Returns true if the attribute list is empty.
2406{
2407 return !attribList || (*attribList == WFC_NONE);
2408}
2409
2410//------------------------------------------------------------------------------
2411
2412static bool wfc_is_rotation(WFCint value)
2413{
2414 return value == WFC_ROTATION_0 ||
2415 value == WFC_ROTATION_90 ||
2416 value == WFC_ROTATION_180 ||
2417 value == WFC_ROTATION_270;
2418}
2419
2420//------------------------------------------------------------------------------
2421
2422static bool wfc_is_scale_filter(WFCint value)
2423{
2424 return value == WFC_SCALE_FILTER_NONE ||
2425 value == WFC_SCALE_FILTER_FASTER ||
2426 value == WFC_SCALE_FILTER_BETTER;
2427}
2428
2429//------------------------------------------------------------------------------
2430
2431static bool wfc_are_transparency_types(WFCint value)
2432{
2433 return value == WFC_TRANSPARENCY_NONE ||
2434 value == WFC_TRANSPARENCY_ELEMENT_GLOBAL_ALPHA ||
2435 value == WFC_TRANSPARENCY_SOURCE ||
2436 value == WFC_TRANSPARENCY_SOURCE_VC_NON_PRE_MULT ||
2437 value == WFC_TRANSPARENCY_MASK ||
2438 value == (WFC_TRANSPARENCY_ELEMENT_GLOBAL_ALPHA | WFC_TRANSPARENCY_SOURCE) ||
2439 value == (WFC_TRANSPARENCY_ELEMENT_GLOBAL_ALPHA | WFC_TRANSPARENCY_SOURCE_VC_NON_PRE_MULT) ||
2440 value == (WFC_TRANSPARENCY_ELEMENT_GLOBAL_ALPHA | WFC_TRANSPARENCY_MASK);
2441}
2442
2443//------------------------------------------------------------------------------
2444
2445static int32_t wfc_round(float f)
2446{
2447 int result = (int)f;
2448 if (f>=0)
2449 if ((f-result)>=0.5) return ++result; else return result;
2450 else
2451 if ((f-result)<=-0.5) return --result; else return result;
2452}
2453
2454//==============================================================================
2455
2456static void wfc_link_detach(WFC_LINK_T *link)
2457{
2458 vcos_assert(link != NULL);
2459 if (link->next) {
2460 /*
2461 never unlink a base link
2462 */
2463
2464 vcos_assert(link->next != link);
2465 vcos_assert(link->prev != link);
2466
2467 link->next->prev = link->prev;
2468 link->prev->next = link->next;
2469
2470 link->prev = NULL;
2471 link->next = NULL;
2472 }
2473}
2474
2475//------------------------------------------------------------------------------
2476
2477static void wfc_link_attach(WFC_LINK_T *link, WFC_LINK_T *prev)
2478{
2479 wfc_link_detach(link);
2480
2481 link->prev = prev;
2482 link->next = prev->next;
2483
2484 link->prev->next = link;
2485 link->next->prev = link;
2486}
2487
2488//------------------------------------------------------------------------------
2489
2490static void wfc_link_init_null(WFC_LINK_T *link)
2491//!@brief Initialise a link when the link will be used to keep track of structures
2492//! of the kind which contain the link.
2493{
2494 link->prev = NULL;
2495 link->next = NULL;
2496}
2497
2498//------------------------------------------------------------------------------
2499
2500static void wfc_link_init_empty(WFC_LINK_T *link)
2501//!@brief Initialise a link which will contain structures which are children of the
2502//! structure containing the link.
2503{
2504 link->prev = link;
2505 link->next = link;
2506}
2507
2508//------------------------------------------------------------------------------
2509
2510static void wfc_link_iterate(WFC_LINK_T *link, WFC_LINK_CALLBACK_T func, void *arg)
2511{
2512 WFC_LINK_T *curr = link;
2513 WFC_LINK_T *next = curr->next;
2514
2515 while (next != link) {
2516 curr = next;
2517 next = curr->next;
2518
2519 func(curr, arg);
2520 }
2521}
2522
2523//------------------------------------------------------------------------------
2524
2525void wfc_set_deferral_stream(WFCDevice dev, WFCContext ctx, WFCNativeStreamType stream)
2526{
2527 WFC_LOCK();
2528
2529 WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
2530 WFC_CONTEXT_T *context_ptr = wfc_context_from_handle(ctx);
2531
2532 if (!vcos_verify(device_ptr != NULL))
2533 {
2534 vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
2535 WFC_UNLOCK();
2536 return;
2537 }
2538
2539 if(vcos_verify((context_ptr != NULL) && (context_ptr->device_ptr == device_ptr)))
2540 {
2541 wfc_server_set_deferral_stream(ctx, stream);
2542 } //if
2543 else
2544 {wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);}
2545
2546 WFC_UNLOCK();
2547}
2548
2549//------------------------------------------------------------------------------
2550
2551/** Called when a scene for composition has been taken
2552 *
2553 * @param cb_data Callback data
2554 */
2555static void wfc_client_scene_taken_cb(void *cb_data)
2556{
2557 VCOS_SEMAPHORE_T *wait_sem = (VCOS_SEMAPHORE_T *)cb_data;
2558
2559 vcos_assert(wait_sem != NULL);
2560 vcos_semaphore_post(wait_sem);
2561}
2562
2563//------------------------------------------------------------------------------
2564
2565/** Wait for the scene taken callback to have been called. Deletes the semaphore
2566 * and releases the VideoCore keep alive.
2567 *
2568 * @param wait_sem The wait semaphore.
2569 * @param ctx The handle for the context receiving the scene, used in logging.
2570 * @param calling_function The calling function name, used in logging.
2571 */
2572static void wfc_client_wait_for_scene_taken(VCOS_SEMAPHORE_T *wait_sem, WFCContext ctx,
2573 const char *calling_function)
2574{
2575 VCOS_STATUS_T status;
2576
2577#if defined(VCOS_LOGGING_ENABLED)
2578 uint64_t pid = vcos_process_id_current();
2579
2580 vcos_log_trace("%s: wait for compositor to take scene, context 0x%x pid 0x%x%08x",
2581 calling_function, ctx, (uint32_t)(pid >> 32), (uint32_t)pid);
2582#else
2583 vcos_unused(ctx);
2584 vcos_unused(calling_function);
2585#endif
2586
2587 status = vcos_semaphore_wait(wait_sem);
2588 vcos_assert(status == VCOS_SUCCESS);
2589 vcos_unused(status);
2590
2591 vcos_semaphore_delete(wait_sem);
2592 wfc_server_release_keep_alive();
2593
2594 vcos_log_trace("%s: wait completed", calling_function);
2595}
2596
2597//==============================================================================
2598