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
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
37typedef struct
38{
39 WFCDevice device;
40 WFCContext context;
41 WFCElement element;
42} WFC_DATA_T;
43
44#define OPENWFC_BOUNCE
45
46//==============================================================================
47
48static EGL_DISPMANX_WINDOW_T *check_default(EGLNativeWindowType win);
49
50//==============================================================================
51
52static bool have_default_dwin;
53static EGL_DISPMANX_WINDOW_T default_dwin;
54
55static WFC_DATA_T wfc_data;
56
57//==============================================================================
58
59uint32_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
67void 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
81void *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
231static 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