1 | /* |
2 | Copyright (c) 2012, Broadcom Europe Ltd |
3 | All rights reserved. |
4 | |
5 | Redistribution and use in source and binary forms, with or without |
6 | modification, 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 | |
16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY |
20 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
23 | ON 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 |
25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | */ |
27 | |
28 | //============================================================================== |
29 | |
30 | #include "interface/khronos/common/khrn_client_platform.h" |
31 | |
32 | #include "interface/khronos/include/WF/wfc.h" |
33 | #include "interface/khronos/wf/wfc_int.h" |
34 | |
35 | //============================================================================== |
36 | |
37 | typedef struct |
38 | { |
39 | WFCDevice device; |
40 | WFCContext context; |
41 | WFCElement element; |
42 | } WFC_DATA_T; |
43 | |
44 | #define OPENWFC_BOUNCE |
45 | |
46 | //============================================================================== |
47 | |
48 | static EGL_DISPMANX_WINDOW_T *check_default(EGLNativeWindowType win); |
49 | |
50 | //============================================================================== |
51 | |
52 | static bool have_default_dwin; |
53 | static EGL_DISPMANX_WINDOW_T default_dwin; |
54 | |
55 | static WFC_DATA_T wfc_data; |
56 | |
57 | //============================================================================== |
58 | |
59 | uint32_t platform_get_handle(EGLDisplay dpy, EGLNativeWindowType win) |
60 | { |
61 | EGL_DISPMANX_WINDOW_T *dwin = check_default(win); |
62 | return dwin->element; /* same handles used on host and videocore sides */ |
63 | } |
64 | |
65 | //------------------------------------------------------------------------------ |
66 | |
67 | void platform_get_dimensions(EGLDisplay dpy, EGLNativeWindowType win, |
68 | uint32_t *width, uint32_t *height, uint32_t *swapchain_count) |
69 | { |
70 | EGL_DISPMANX_WINDOW_T *dwin = check_default(win); |
71 | |
72 | *width = dwin->width; |
73 | *height = dwin->height; |
74 | *swapchain_count = 0; |
75 | } |
76 | |
77 | //------------------------------------------------------------------------------ |
78 | |
79 | #define NUM_OF_ELEMENTS 2 |
80 | |
81 | void *platform_wfc_bounce_thread(void *param) |
82 | // Thread function for making previously-created source bounce around the screen. |
83 | { |
84 | WFC_BOUNCE_DATA_T *bounce_data = (WFC_BOUNCE_DATA_T *) param; |
85 | |
86 | uint32_t i; |
87 | int32_t xstep[NUM_OF_ELEMENTS], ystep[NUM_OF_ELEMENTS]; |
88 | WFCint dest_rect[NUM_OF_ELEMENTS][WFC_RECT_SIZE]; |
89 | WFCint src_rect[WFC_RECT_SIZE]; |
90 | WFCElement element_local[NUM_OF_ELEMENTS]; |
91 | |
92 | uint32_t num_of_elements = NUM_OF_ELEMENTS; |
93 | WFCElement *element = element_local; |
94 | |
95 | // Get context (i.e. screen) dimensions. |
96 | int32_t ctx_width; |
97 | int32_t ctx_height; |
98 | int32_t dest_width, dest_height; |
99 | |
100 | int32_t x, y; |
101 | |
102 | bool use_local_elements = (bounce_data->num_of_elements == 0); |
103 | if(!use_local_elements) |
104 | { |
105 | vcos_assert(bounce_data->num_of_elements <= NUM_OF_ELEMENTS); |
106 | vcos_assert(bounce_data->element != NULL); |
107 | num_of_elements = bounce_data->num_of_elements; |
108 | element = bounce_data->element; |
109 | } // if |
110 | |
111 | // Initialise values |
112 | ctx_width = wfcGetContextAttribi(bounce_data->device, |
113 | bounce_data->context, WFC_CONTEXT_TARGET_WIDTH); |
114 | ctx_height = wfcGetContextAttribi(bounce_data->device, |
115 | bounce_data->context, WFC_CONTEXT_TARGET_HEIGHT); |
116 | |
117 | // Change background colour |
118 | wfcSetContextAttribi(bounce_data->device, |
119 | bounce_data->context, WFC_CONTEXT_BG_COLOR, 0x0000FFFF); |
120 | |
121 | float scale = 0.4; |
122 | if(num_of_elements == 1) |
123 | {scale = 0.75;} |
124 | |
125 | dest_width = bounce_data->dest_width * scale; |
126 | dest_height = bounce_data->dest_height * scale; |
127 | |
128 | // Define source rectangle |
129 | src_rect[WFC_RECT_X] = bounce_data->src_x; |
130 | src_rect[WFC_RECT_Y] = bounce_data->src_y; |
131 | src_rect[WFC_RECT_WIDTH] = bounce_data->src_width; |
132 | src_rect[WFC_RECT_HEIGHT] = bounce_data->src_height; |
133 | |
134 | for(i = 0; i < num_of_elements; i++) |
135 | { |
136 | if(use_local_elements) |
137 | { |
138 | // Create and set up element |
139 | element[i] = wfcCreateElement(bounce_data->device, |
140 | bounce_data->context, NO_ATTRIBUTES); |
141 | vcos_assert(element[i] != WFC_INVALID_HANDLE); |
142 | |
143 | wfcInsertElement(bounce_data->device, element[i], WFC_INVALID_HANDLE); |
144 | if(vcos_verify(wfcGetError(bounce_data->device) == WFC_ERROR_NONE)) {}; |
145 | } // if |
146 | else |
147 | { |
148 | // Element created in calling app, so use that |
149 | element[i] = bounce_data->element[i]; |
150 | } // else |
151 | |
152 | wfcSetElementAttribiv(bounce_data->device, element[i], |
153 | WFC_ELEMENT_SOURCE_RECTANGLE, WFC_RECT_SIZE, src_rect); |
154 | |
155 | // Attach existing source |
156 | wfcSetElementAttribi(bounce_data->device, element[i], |
157 | WFC_ELEMENT_SOURCE, bounce_data->source); |
158 | |
159 | if(num_of_elements > 1) |
160 | { |
161 | wfcSetElementAttribi(bounce_data->device, element[i], |
162 | WFC_ELEMENT_TRANSPARENCY_TYPES, WFC_TRANSPARENCY_ELEMENT_GLOBAL_ALPHA); |
163 | wfcSetElementAttribf(bounce_data->device, element[i], |
164 | WFC_ELEMENT_GLOBAL_ALPHA, 0.75); |
165 | } // if |
166 | |
167 | // Define initial destination rectangle |
168 | dest_rect[i][WFC_RECT_X] = i * 100; |
169 | dest_rect[i][WFC_RECT_Y] = i * 10; |
170 | dest_rect[i][WFC_RECT_WIDTH] = dest_width; |
171 | dest_rect[i][WFC_RECT_HEIGHT] = dest_height; |
172 | wfcSetElementAttribiv(bounce_data->device, element[i], |
173 | WFC_ELEMENT_DESTINATION_RECTANGLE, WFC_RECT_SIZE, dest_rect[i]); |
174 | |
175 | xstep[i] = (i + 1) * 2; |
176 | ystep[i] = (i + 1) * 2; |
177 | } // for |
178 | |
179 | while(!bounce_data->stop_bouncing) |
180 | { |
181 | for(i = 0; i < num_of_elements; i++) |
182 | { |
183 | // Compute new x and y values. |
184 | x = dest_rect[i][WFC_RECT_X]; |
185 | y = dest_rect[i][WFC_RECT_Y]; |
186 | |
187 | x += xstep[i]; |
188 | if(x + dest_width >= ctx_width) |
189 | {x = ctx_width - dest_width - 1; xstep[i] *= -1;} |
190 | else if(x < 0) |
191 | {x = 0; xstep[i] *= -1;} |
192 | |
193 | y += ystep[i]; |
194 | if(y + dest_height >= ctx_height) |
195 | {y = ctx_height - dest_height - 1; ystep[i] *= -1;} |
196 | else if(y < 0) |
197 | {y = 0; ystep[i] *= -1;} |
198 | |
199 | dest_rect[i][WFC_RECT_X] = x; |
200 | dest_rect[i][WFC_RECT_Y] = y; |
201 | |
202 | // Set updated destination rectangle |
203 | wfcSetElementAttribiv(bounce_data->device, element[i], |
204 | WFC_ELEMENT_DESTINATION_RECTANGLE, WFC_RECT_SIZE, dest_rect[i]); |
205 | } // for |
206 | |
207 | wfcCommit(bounce_data->device, bounce_data->context, WFC_TRUE); |
208 | vcos_sleep(30); |
209 | } // while |
210 | |
211 | // Remove elements |
212 | if(use_local_elements) |
213 | { |
214 | for(i = 0; i < num_of_elements; i++) |
215 | { |
216 | wfcDestroyElement(bounce_data->device, element[i]); |
217 | } // for |
218 | } // if |
219 | |
220 | // Change background colour |
221 | wfcSetContextAttribi(bounce_data->device, |
222 | bounce_data->context, WFC_CONTEXT_BG_COLOR, 0xFF0000FF); |
223 | |
224 | wfcCommit(bounce_data->device, bounce_data->context, WFC_TRUE); |
225 | |
226 | return NULL; |
227 | } // platform_bounce_thread |
228 | |
229 | //============================================================================== |
230 | |
231 | static EGL_DISPMANX_WINDOW_T *check_default(EGLNativeWindowType win) |
232 | { |
233 | // Window already exists, so return it. |
234 | if(win != 0) |
235 | {return (EGL_DISPMANX_WINDOW_T*) win;} |
236 | |
237 | // Window doesn't exist (= 0), but one has previously been created, so use |
238 | // that. |
239 | if(have_default_dwin) |
240 | {return &default_dwin;} |
241 | |
242 | // Window doesn't exist, and hasn't previously been created, so make it so. |
243 | wfc_data.device = wfcCreateDevice(WFC_DEFAULT_DEVICE_ID, NO_ATTRIBUTES); |
244 | vcos_assert(wfc_data.device != WFC_INVALID_HANDLE); |
245 | wfc_data.context = wfcCreateOnScreenContext(wfc_data.device, 0, NO_ATTRIBUTES); |
246 | vcos_assert(wfc_data.context != WFC_INVALID_HANDLE); |
247 | |
248 | WFCint context_width = wfcGetContextAttribi |
249 | (wfc_data.device, wfc_data.context, WFC_CONTEXT_TARGET_WIDTH); |
250 | WFCint context_height = wfcGetContextAttribi |
251 | (wfc_data.device, wfc_data.context, WFC_CONTEXT_TARGET_HEIGHT); |
252 | |
253 | #ifdef OPENWFC_BOUNCE |
254 | // Create and attach source |
255 | default_dwin.element = 1; // Use arbitrary non-zero value for stream number. |
256 | WFCNativeStreamType stream = (WFCNativeStreamType) default_dwin.element; |
257 | vcos_assert(stream != WFC_INVALID_HANDLE); |
258 | WFCSource source = wfcCreateSourceFromStream(wfc_data.device, wfc_data.context, stream, NO_ATTRIBUTES); |
259 | vcos_assert(source != WFC_INVALID_HANDLE); |
260 | |
261 | static VCOS_THREAD_T bounce_thread_data; |
262 | static WFC_BOUNCE_DATA_T bounce_data; |
263 | |
264 | bounce_data.device = wfc_data.device; |
265 | bounce_data.context = wfc_data.context; |
266 | bounce_data.source = source; |
267 | bounce_data.src_width = context_width; |
268 | bounce_data.src_height = context_height; |
269 | bounce_data.dest_width = context_width; |
270 | bounce_data.dest_height = context_height; |
271 | bounce_data.stop_bouncing = 0; |
272 | |
273 | VCOS_STATUS_T status; |
274 | status = vcos_thread_create(&bounce_thread_data, "bounce_thread" , NULL, |
275 | platform_wfc_bounce_thread, &bounce_data); |
276 | vcos_assert(status == VCOS_SUCCESS); |
277 | #else |
278 | WFCint rect_src[WFC_RECT_SIZE] = { 0, 0, 0, 0 }; |
279 | WFCint rect_dest[WFC_RECT_SIZE] = { 0, 0, 0, 0 }; |
280 | |
281 | wfc_data.element = wfcCreateElement(wfc_data.device, wfc_data.context, NO_ATTRIBUTES); |
282 | vcos_assert(wfc_data.element != WFC_INVALID_HANDLE); |
283 | default_dwin.element = wfc_data.element; |
284 | |
285 | wfcInsertElement(wfc_data.device, wfc_data.element, WFC_INVALID_HANDLE); |
286 | if(vcos_verify(wfcGetError(wfc_data.device) == WFC_ERROR_NONE)) {}; |
287 | |
288 | /* Set element attributes */ |
289 | rect_src[WFC_RECT_X] = 0; |
290 | rect_src[WFC_RECT_Y] = 0; |
291 | rect_src[WFC_RECT_WIDTH] = context_width; |
292 | rect_src[WFC_RECT_HEIGHT] = context_height; |
293 | wfcSetElementAttribiv(wfc_data.device, wfc_data.element, |
294 | WFC_ELEMENT_SOURCE_RECTANGLE, WFC_RECT_SIZE, rect_src); |
295 | |
296 | rect_dest[WFC_RECT_X] = 0; |
297 | rect_dest[WFC_RECT_Y] = 0; |
298 | rect_dest[WFC_RECT_WIDTH] = context_width; |
299 | rect_dest[WFC_RECT_HEIGHT] = context_height; |
300 | wfcSetElementAttribiv(wfc_data.device, wfc_data.element, |
301 | WFC_ELEMENT_DESTINATION_RECTANGLE, WFC_RECT_SIZE, rect_dest); |
302 | |
303 | // Create and attach source |
304 | default_dwin.element = wfc_data.element; // Stream and element handles given same value. |
305 | WFCNativeStreamType stream = (WFCNativeStreamType) default_dwin.element; |
306 | vcos_assert(stream != WFC_INVALID_HANDLE); |
307 | WFCSource source = wfcCreateSourceFromStream(wfc_data.device, wfc_data.context, stream, NO_ATTRIBUTES); |
308 | vcos_assert(source != WFC_INVALID_HANDLE); |
309 | |
310 | wfcSetElementAttribi(wfc_data.device, wfc_data.element, WFC_ELEMENT_SOURCE, source); |
311 | #endif |
312 | |
313 | // Send to display |
314 | wfcCommit(wfc_data.device, wfc_data.context, WFC_TRUE); |
315 | |
316 | // Enable this and future commits to be enacted immediately |
317 | wfcActivate(wfc_data.device, wfc_data.context); |
318 | |
319 | default_dwin.width = 800; |
320 | default_dwin.height = 480; |
321 | |
322 | have_default_dwin = true; |
323 | |
324 | return &default_dwin; |
325 | |
326 | } // check_default() |
327 | |
328 | //============================================================================== |
329 | |