|
1 /* Copyright (c) 2009 The Khronos Group Inc. |
|
2 * |
|
3 * Permission is hereby granted, free of charge, to any person obtaining a |
|
4 * copy of this software and/or associated documentation files (the |
|
5 * "Materials"), to deal in the Materials without restriction, including |
|
6 * without limitation the rights to use, copy, modify, merge, publish, |
|
7 * distribute, sublicense, and/or sell copies of the Materials, and to |
|
8 * permit persons to whom the Materials are furnished to do so, subject to |
|
9 * the following conditions: |
|
10 * |
|
11 * The above copyright notice and this permission notice shall be included |
|
12 * in all copies or substantial portions of the Materials. |
|
13 * |
|
14 * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
|
15 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
|
16 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. |
|
17 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY |
|
18 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, |
|
19 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
|
20 * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. |
|
21 */ |
|
22 |
|
23 /*! \ingroup wfc |
|
24 * \file wfcscene.c |
|
25 * |
|
26 * \brief SI Scene graph management functions. |
|
27 */ |
|
28 |
|
29 #include "WF/wfc.h" |
|
30 #include "wfcstructs.h" |
|
31 #include "wfcscene.h" |
|
32 #include "wfcelement.h" |
|
33 #include "wfcimageprovider.h" |
|
34 |
|
35 #include "owfmemory.h" |
|
36 #include "owfarray.h" |
|
37 #include "owflinkedlist.h" |
|
38 #include "owfobject.h" |
|
39 |
|
40 #include "owfdebug.h" |
|
41 |
|
42 /*! |
|
43 * \brief Destroy an element. In case the element is marked as shared, |
|
44 * this function does nothing. An element is marked as shared, when it is |
|
45 * inserted into working copy scene. The marked flag is reset when the element |
|
46 * is removed from the context (i.e. it only resides in the device's |
|
47 * list of created elements) |
|
48 * |
|
49 * \param element Element to destroy |
|
50 */ |
|
51 static void WFC_Scene_DestroyElement(WFC_ELEMENT* element) |
|
52 { |
|
53 /* elements in the working copy are "read only" because |
|
54 * they're shared between the device & the working copy |
|
55 */ |
|
56 if (!element->shared) |
|
57 { |
|
58 WFC_Element_Destroy(element); |
|
59 } |
|
60 } |
|
61 |
|
62 OWF_API_CALL void |
|
63 WFC_Scene_Destroy(WFC_SCENE* scene) |
|
64 { |
|
65 OWF_NODE* node; |
|
66 |
|
67 DPRINT(("WFC_Scene_Destroy(%p)", scene)); |
|
68 if (scene) |
|
69 { |
|
70 for (node = scene->elements; NULL != node; node = node->next) |
|
71 { |
|
72 WFC_Scene_DestroyElement((WFC_ELEMENT*)node->data); |
|
73 } |
|
74 |
|
75 scene->elements = OWF_List_Clear(scene->elements); |
|
76 |
|
77 DESTROY(scene->context); |
|
78 |
|
79 OWF_Pool_PutObject(scene); |
|
80 } |
|
81 } |
|
82 |
|
83 /*! |
|
84 * \brief Append element into scene |
|
85 * |
|
86 * \param scene Scene |
|
87 * \param element Element to add |
|
88 */ |
|
89 static void |
|
90 WFC_Scene_AppendElement(WFC_SCENE* scene, |
|
91 WFC_ELEMENT* element) |
|
92 { |
|
93 OWF_NODE* node; |
|
94 |
|
95 /* OBS! No duplicate check here! Use with caution*/ |
|
96 |
|
97 node = OWF_Node_Create(CONTEXT(scene->context)->nodePool, element); |
|
98 scene->elements = OWF_List_Append(scene->elements, node); |
|
99 return ; |
|
100 } |
|
101 |
|
102 /*----------------------------------------------------------------------------*/ |
|
103 OWF_API_CALL WFC_SCENE* |
|
104 WFC_Scene_Clone(WFC_SCENE* scene) |
|
105 { |
|
106 WFC_SCENE* cloneScene; |
|
107 OWF_NODE* node; |
|
108 |
|
109 cloneScene = WFC_Scene_Create(CONTEXT(scene->context)); |
|
110 |
|
111 for (node = scene->elements; NULL != node; node = node->next) |
|
112 { |
|
113 WFC_ELEMENT* original; |
|
114 WFC_ELEMENT* cloneElem; |
|
115 |
|
116 original = ELEMENT(node->data); |
|
117 if (WFC_Element_AffectsCompositionResults(original)) |
|
118 { |
|
119 cloneElem = WFC_Element_Clone(original); |
|
120 WFC_Scene_AppendElement(cloneScene, cloneElem); |
|
121 } |
|
122 } |
|
123 |
|
124 return cloneScene; |
|
125 } |
|
126 |
|
127 /*----------------------------------------------------------------------------*/ |
|
128 OWF_API_CALL WFC_SCENE* |
|
129 WFC_Scene_Create(WFC_CONTEXT* context) |
|
130 { |
|
131 WFC_SCENE* scene; |
|
132 |
|
133 DPRINT(("WFC_Scene_Create")); |
|
134 scene = SCENE(OWF_Pool_GetObject(context->scenePool)); |
|
135 |
|
136 OWF_ASSERT(scene); |
|
137 |
|
138 ADDREF(scene->context, context); |
|
139 |
|
140 return scene; |
|
141 } |
|
142 |
|
143 /*----------------------------------------------------------------------------*/ |
|
144 OWF_API_CALL WFCErrorCode |
|
145 WFC_Scene_InsertElement(WFC_SCENE* scene, |
|
146 WFC_ELEMENT* element, |
|
147 WFCElement elementBelow) |
|
148 { |
|
149 WFCErrorCode result = WFC_ERROR_NONE; |
|
150 OWF_NODE* iter = NULL; |
|
151 OWF_NODE* newPos = NULL; |
|
152 OWF_NODE* oldPos = NULL; |
|
153 |
|
154 if (!scene || !element) |
|
155 { |
|
156 return WFC_ERROR_ILLEGAL_ARGUMENT; |
|
157 } |
|
158 |
|
159 if (element->handle == (WFCHandle)element) |
|
160 { |
|
161 /* nothing to do */ |
|
162 return WFC_ERROR_NONE; |
|
163 } |
|
164 |
|
165 newPos = NULL; /*scene->elements;*/ |
|
166 for (iter = scene->elements; NULL != iter; iter = iter->next) |
|
167 { |
|
168 WFC_ELEMENT* temp = NULL; |
|
169 |
|
170 temp = ELEMENT(iter->data); |
|
171 |
|
172 if (temp->handle == elementBelow) |
|
173 { |
|
174 /* insertion point found */ |
|
175 newPos = iter; |
|
176 } |
|
177 if (temp->handle == element->handle) |
|
178 { |
|
179 /* already in the scene; relocate */ |
|
180 oldPos = iter; |
|
181 } |
|
182 } |
|
183 |
|
184 if (newPos && newPos == oldPos) { |
|
185 /* inserting element above self is a no-op */ |
|
186 return WFC_ERROR_NONE; |
|
187 } |
|
188 |
|
189 if (!newPos && WFC_INVALID_HANDLE != elementBelow) |
|
190 { |
|
191 /* could not find elementBelow from the scene */ |
|
192 result = WFC_ERROR_ILLEGAL_ARGUMENT; |
|
193 } |
|
194 else |
|
195 { |
|
196 OWF_NODE* newNode = NULL; |
|
197 |
|
198 /* first remove element from its old slot, if already |
|
199 * on the list |
|
200 */ |
|
201 if (NULL != oldPos) |
|
202 { |
|
203 scene->elements = OWF_List_Remove(scene->elements, oldPos); |
|
204 OWF_Node_Destroy(oldPos); |
|
205 } |
|
206 |
|
207 /* allocate new node to insert */ |
|
208 newNode = OWF_Node_Create(CONTEXT(scene->context)->nodePool, element); |
|
209 if (NULL != newPos) |
|
210 { |
|
211 /* insert into new position, above elementBelow */ |
|
212 OWF_List_InsertAfter(newPos, newNode); |
|
213 } |
|
214 else |
|
215 { |
|
216 /* insert on bottom */ |
|
217 scene->elements = OWF_List_Insert(scene->elements, newNode); |
|
218 } |
|
219 } |
|
220 |
|
221 DPRINT((" Order of the elements (bottom to top): ")); |
|
222 for (iter = scene->elements; NULL != iter; iter = iter->next) |
|
223 { |
|
224 DPRINT((" %d", ELEMENT(iter->data)->handle)); |
|
225 } |
|
226 return result; |
|
227 |
|
228 } |
|
229 |
|
230 /*----------------------------------------------------------------------------*/ |
|
231 OWF_API_CALL void |
|
232 WFC_Scene_RemoveElement(WFC_SCENE* scene, |
|
233 WFCElement element) |
|
234 { |
|
235 OWF_NODE* node = NULL; |
|
236 |
|
237 for (node = scene->elements; NULL != node; node = node->next) |
|
238 { |
|
239 WFC_ELEMENT* etemp; |
|
240 |
|
241 etemp = ELEMENT(node->data); |
|
242 if (etemp->handle == element) |
|
243 { |
|
244 scene->elements = OWF_List_Remove(scene->elements, node); |
|
245 OWF_Node_Destroy(node); |
|
246 WFC_Scene_DestroyElement(etemp); |
|
247 break; |
|
248 |
|
249 } |
|
250 } |
|
251 DPRINT((" Order of the elements (bottom to top): ")); |
|
252 for (node = scene->elements; NULL != node; node = node->next) |
|
253 { |
|
254 DPRINT((" %d", ELEMENT(node->data)->handle)); |
|
255 } |
|
256 } |
|
257 |
|
258 /*----------------------------------------------------------------------------*/ |
|
259 OWF_API_CALL WFC_ELEMENT* |
|
260 WFC_Scene_FindElement(WFC_SCENE* scene, |
|
261 WFCElement element) |
|
262 { |
|
263 OWF_NODE* node = NULL; |
|
264 WFC_ELEMENT* result = NULL; |
|
265 |
|
266 for (node = scene->elements; NULL != node; node = node->next) |
|
267 { |
|
268 WFC_ELEMENT* etemp; |
|
269 |
|
270 etemp = ELEMENT(node->data); |
|
271 if (etemp->handle == element) |
|
272 { |
|
273 result = etemp; |
|
274 break; |
|
275 } |
|
276 } |
|
277 return result; |
|
278 } |
|
279 |
|
280 /*----------------------------------------------------------------------------*/ |
|
281 OWF_API_CALL void |
|
282 WFC_Scene_LockSourcesAndMasks(WFC_SCENE* scene) |
|
283 { |
|
284 OWF_NODE* node = NULL; |
|
285 |
|
286 DPRINT(("WFC_Scene_LockSourcesAndMasks(scene = %p)", scene)); |
|
287 |
|
288 for (node = scene->elements; NULL != node; node = node->next) |
|
289 { |
|
290 WFC_ELEMENT* element; |
|
291 |
|
292 element = ELEMENT(node->data); |
|
293 |
|
294 DPRINT((" Element source handle = %d", element->sourceHandle)); |
|
295 DPRINT((" Element source = %p", element->source)); |
|
296 DPRINT((" Element dest size = %.2fx%.2f", |
|
297 element->dstRect[2], element->dstRect[3])); |
|
298 DPRINT((" Element src size = %.2fx%.2f", |
|
299 element->srcRect[2], element->srcRect[3])); |
|
300 |
|
301 if (WFC_Element_AffectsCompositionResults(element)) |
|
302 { |
|
303 DPRINT((" Locking element %p", element)); |
|
304 WFC_ImageProvider_LockForReading(element->source); |
|
305 /* set the flag so that composition knows to include the |
|
306 element into composition */ |
|
307 element->skipCompose = |
|
308 (element->source->lockedStream.image->data == NULL) ? |
|
309 WFC_TRUE : WFC_FALSE; |
|
310 } |
|
311 else |
|
312 { |
|
313 element->skipCompose = WFC_TRUE; |
|
314 } |
|
315 |
|
316 if (!element->skipCompose && |
|
317 WFC_INVALID_HANDLE != element->maskHandle && |
|
318 NULL != element->mask) |
|
319 { |
|
320 WFC_ImageProvider_LockForReading(element->mask); |
|
321 element->maskComposed = WFC_TRUE; |
|
322 |
|
323 OWF_ASSERT(element->mask); |
|
324 OWF_ASSERT(element->mask->streamHandle); |
|
325 OWF_ASSERT(element->mask->lockedStream.image); |
|
326 |
|
327 if(element->mask->lockedStream.image->data == NULL) |
|
328 { |
|
329 WFC_ImageProvider_Unlock(element->source); |
|
330 element->skipCompose = WFC_TRUE; |
|
331 } |
|
332 } |
|
333 else |
|
334 { |
|
335 element->maskComposed = WFC_FALSE; |
|
336 } |
|
337 } |
|
338 } |
|
339 |
|
340 /*----------------------------------------------------------------------------*/ |
|
341 OWF_API_CALL void |
|
342 WFC_Scene_UnlockSourcesAndMasks(WFC_SCENE* scene) |
|
343 { |
|
344 OWF_NODE* node = NULL; |
|
345 |
|
346 DPRINT(("WFC_Scene_UnlockSourcesAndMasks(scene = %p)", scene)); |
|
347 |
|
348 for (node = scene->elements; NULL != node; node = node->next) |
|
349 { |
|
350 WFC_ELEMENT* element; |
|
351 |
|
352 element = ELEMENT(node->data); |
|
353 |
|
354 DPRINT((" Unlocking element %p", element)); |
|
355 if (element->source && !element->skipCompose) |
|
356 { |
|
357 WFC_ImageProvider_Unlock(element->source); |
|
358 } |
|
359 |
|
360 if (element->mask && !element->skipCompose) |
|
361 { |
|
362 WFC_ImageProvider_Unlock(element->mask); |
|
363 } |
|
364 } |
|
365 } |
|
366 |
|
367 /*----------------------------------------------------------------------------*/ |
|
368 OWF_API_CALL WFCElement |
|
369 WFC_Scene_GetNeighbourElement(WFC_SCENE* scene, WFCElement element, WFCint n) |
|
370 { |
|
371 WFCElement result = WFC_INVALID_HANDLE; |
|
372 OWF_NODE* node = NULL; |
|
373 OWF_NODE* prev = NULL; |
|
374 |
|
375 for (node = scene->elements; NULL != node; node = node->next) |
|
376 { |
|
377 WFC_ELEMENT* etemp; |
|
378 |
|
379 etemp = ELEMENT(node->data); |
|
380 if (etemp->handle == element) |
|
381 { |
|
382 if (n < 0) |
|
383 { |
|
384 result = prev ? ELEMENT(prev->data)->handle |
|
385 : WFC_INVALID_HANDLE; |
|
386 } |
|
387 else |
|
388 { |
|
389 result = node->next ? ELEMENT(node->next->data)->handle |
|
390 : WFC_INVALID_HANDLE; |
|
391 |
|
392 } |
|
393 break; |
|
394 } |
|
395 prev = node; |
|
396 } |
|
397 return result; |
|
398 } |
|
399 |
|
400 /*----------------------------------------------------------------------------*/ |
|
401 OWF_API_CALL WFCboolean |
|
402 WFC_Scene_HasConflicts(WFC_SCENE* scene) |
|
403 { |
|
404 WFCboolean result = WFC_FALSE; |
|
405 OWF_NODE* node = NULL; |
|
406 |
|
407 for (node = scene->elements; NULL != node; node = node->next) |
|
408 { |
|
409 WFC_ELEMENT* element; |
|
410 |
|
411 element = ELEMENT(node->data); |
|
412 |
|
413 result = result || WFC_Element_HasConflicts(element) ? WFC_TRUE : WFC_FALSE; |
|
414 if (result) |
|
415 { |
|
416 /* conflict found */ |
|
417 break; |
|
418 } |
|
419 } |
|
420 return result; |
|
421 } |
|
422 |
|
423 /*----------------------------------------------------------------------------*/ |
|
424 OWF_API_CALL void |
|
425 WFC_Scene_Commit(WFC_SCENE* scene) |
|
426 { |
|
427 OWF_NODE* node; |
|
428 |
|
429 for (node = scene->elements; NULL != node; node = node->next) |
|
430 { |
|
431 WFC_ELEMENT* element; |
|
432 |
|
433 element = ELEMENT(node->data); |
|
434 WFC_Element_Commit(element); |
|
435 } |
|
436 } |
|
437 |
|
438 /*----------------------------------------------------------------------------*/ |
|
439 OWF_API_CALL WFCElement |
|
440 WFC_Scene_LowestElement(WFC_SCENE* scene) |
|
441 { |
|
442 WFCElement element = WFC_INVALID_HANDLE; |
|
443 |
|
444 if (scene && scene->elements) |
|
445 { |
|
446 element = ELEMENT(scene->elements->data)->handle; |
|
447 } |
|
448 return element; |
|
449 } |