| 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 | |