| 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 | #define VCOS_LOG_CATEGORY (&khrn_client_log) |
| 28 | |
| 29 | #include "interface/khronos/common/khrn_client_platform.h" |
| 30 | #include "interface/khronos/common/khrn_client.h" |
| 31 | #include "interface/khronos/common/khrn_client_rpc.h" |
| 32 | #include "interface/khronos/common/khrn_int_ids.h" |
| 33 | #include <stdio.h> |
| 34 | #include <string.h> |
| 35 | #include <assert.h> |
| 36 | #ifdef WANT_X |
| 37 | #include "X11/Xlib.h" |
| 38 | #endif |
| 39 | |
| 40 | extern VCOS_LOG_CAT_T khrn_client_log; |
| 41 | |
| 42 | extern void vc_vchi_khronos_init(); |
| 43 | |
| 44 | static void send_bound_pixmaps(void); |
| 45 | #ifdef WANT_X |
| 46 | static void dump_hierarchy(Window w, Window thisw, Window look, int level); |
| 47 | static void dump_ancestors(Window w); |
| 48 | #endif |
| 49 | |
| 50 | //see helpers\scalerlib\scalerlib_misc.c |
| 51 | //int32_t scalerlib_convert_vcimage_to_display_element() |
| 52 | //dark blue, 1<<3 in 888 |
| 53 | #define CHROMA_KEY_565 0x0001 |
| 54 | // |
| 55 | |
| 56 | #ifdef WANT_X |
| 57 | static Display *hacky_display = 0; |
| 58 | |
| 59 | static XErrorHandler old_handler = (XErrorHandler) 0 ; |
| 60 | static int application_error_handler(Display *display, XErrorEvent *theEvent) |
| 61 | { |
| 62 | vcos_log_trace( |
| 63 | "Ignoring Xlib error: error code %d request code %d\n" , |
| 64 | theEvent->error_code, |
| 65 | theEvent->request_code) ; |
| 66 | return 0 ; |
| 67 | } |
| 68 | #endif |
| 69 | |
| 70 | |
| 71 | VCOS_STATUS_T khronos_platform_semaphore_create(PLATFORM_SEMAPHORE_T *sem, int name[3], int count) |
| 72 | { |
| 73 | char buf[64]; |
| 74 | vcos_snprintf(buf,sizeof(buf),"KhanSemaphore%08x%08x%08x" , name[0], name[1], name[2]); |
| 75 | return vcos_named_semaphore_create(sem, buf, count); |
| 76 | } |
| 77 | |
| 78 | uint64_t khronos_platform_get_process_id() |
| 79 | { |
| 80 | CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE(); |
| 81 | |
| 82 | return rpc_get_client_id(thread); |
| 83 | } |
| 84 | |
| 85 | static bool process_attached = false; |
| 86 | |
| 87 | void *platform_tls_get(PLATFORM_TLS_T tls) |
| 88 | { |
| 89 | void *ret; |
| 90 | |
| 91 | if (!process_attached) |
| 92 | /* TODO: this isn't thread safe */ |
| 93 | { |
| 94 | vcos_log_trace("Attaching process" ); |
| 95 | client_process_attach(); |
| 96 | process_attached = true; |
| 97 | tls = client_tls; |
| 98 | |
| 99 | vc_vchi_khronos_init(); |
| 100 | } |
| 101 | |
| 102 | ret = vcos_tls_get(tls); |
| 103 | if (!ret) |
| 104 | { |
| 105 | /* The problem here is that on VCFW, the first notification we get that a thread |
| 106 | * exists at all is when it calls an arbitrary EGL function. We need to detect this |
| 107 | * case and initiliase the per-thread state. |
| 108 | * |
| 109 | * On Windows this gets done in DllMain. |
| 110 | */ |
| 111 | client_thread_attach(); |
| 112 | vcos_thread_at_exit(client_thread_detach, NULL); |
| 113 | ret = vcos_tls_get(tls); |
| 114 | } |
| 115 | return ret; |
| 116 | } |
| 117 | |
| 118 | void *platform_tls_get_check(PLATFORM_TLS_T tls) |
| 119 | { |
| 120 | return platform_tls_get(tls); |
| 121 | } |
| 122 | |
| 123 | /* ---------------------------------------------------------------------- |
| 124 | * workaround for broken platforms which don't detect threads exiting |
| 125 | * -------------------------------------------------------------------- */ |
| 126 | void platform_hint_thread_finished() |
| 127 | { |
| 128 | /* |
| 129 | todo: should we do this: |
| 130 | |
| 131 | vcos_thread_deregister_at_exit(client_thread_detach); |
| 132 | client_thread_detach(); |
| 133 | |
| 134 | here? |
| 135 | */ |
| 136 | } |
| 137 | |
| 138 | #ifndef KHRN_PLATFORM_VCOS_NO_MALLOC |
| 139 | |
| 140 | /** |
| 141 | Allocate memory |
| 142 | |
| 143 | @param size Size in bytes of memory block to allocate |
| 144 | @return pointer to memory block |
| 145 | **/ |
| 146 | void *khrn_platform_malloc(size_t size, const char * name) |
| 147 | { |
| 148 | return vcos_malloc(size, name); |
| 149 | } |
| 150 | |
| 151 | /** |
| 152 | Free memory |
| 153 | |
| 154 | @param v Pointer to memory area to free |
| 155 | **/ |
| 156 | void khrn_platform_free(void *v) |
| 157 | { |
| 158 | if (v) |
| 159 | { |
| 160 | vcos_free(v); |
| 161 | } |
| 162 | } |
| 163 | |
| 164 | #endif |
| 165 | |
| 166 | |
| 167 | #ifdef WANT_X |
| 168 | static XImage *current_ximage = NULL; |
| 169 | |
| 170 | static KHRN_IMAGE_FORMAT_T ximage_to_image_format(int bits_per_pixel, unsigned long red_mask, unsigned long green_mask, unsigned long blue_mask) |
| 171 | { |
| 172 | if (bits_per_pixel == 16 /*&& red_mask == 0xf800 && green_mask == 0x07e0 && blue_mask == 0x001f*/) |
| 173 | return RGB_565_RSO; |
| 174 | //else if (bits_per_pixel == 24 && red_mask == 0xff0000 && green_mask == 0x00ff00 && blue_mask == 0x0000ff) |
| 175 | // return RGB_888_RSO; |
| 176 | else if (bits_per_pixel == 24 && red_mask == 0x0000ff && green_mask == 0x00ff00 && blue_mask == 0xff0000) |
| 177 | return BGR_888_RSO; |
| 178 | else if (bits_per_pixel == 32 /*&& red_mask == 0x0000ff && green_mask == 0x00ff00 && blue_mask == 0xff0000*/) |
| 179 | return ABGR_8888_RSO; //meego uses alpha channel |
| 180 | else if (bits_per_pixel == 32 && red_mask == 0xff0000 && green_mask == 0x00ff00 && blue_mask == 0x0000ff) |
| 181 | return ARGB_8888_RSO; |
| 182 | else |
| 183 | { |
| 184 | vcos_log_warn("platform_get_pixmap_info unknown image format\n" ); |
| 185 | return IMAGE_FORMAT_INVALID; |
| 186 | } |
| 187 | } |
| 188 | |
| 189 | bool platform_get_pixmap_info(EGLNativePixmapType pixmap, KHRN_IMAGE_WRAP_T *image) |
| 190 | { |
| 191 | Window r; |
| 192 | int x, y; |
| 193 | unsigned int w, h, b, d; |
| 194 | KHRN_IMAGE_FORMAT_T format; |
| 195 | XImage *xi; |
| 196 | XWindowAttributes attr; |
| 197 | Status rc; |
| 198 | |
| 199 | vcos_log_trace("platform_get_pixmap_info !!!" ); |
| 200 | |
| 201 | if (!XGetGeometry(hacky_display, (Drawable)pixmap, &r, &x, &y, &w, &h, &b, &d)) |
| 202 | return false; |
| 203 | |
| 204 | vcos_log_trace("platform_get_pixmap_info %d geometry = %d %d %d %d" ,(int)pixmap, |
| 205 | x, y, w, h); |
| 206 | |
| 207 | xi = XGetImage(hacky_display, (Drawable)pixmap, 0, 0, w, h, 0xffffffff, ZPixmap); |
| 208 | if (xi == NULL) |
| 209 | return false; |
| 210 | |
| 211 | vcos_log_trace("platform_get_pixmap_info ximage = %d %d %d 0x%08x %d %x %x %x" , |
| 212 | xi->width, xi->height, xi->bytes_per_line, (uint32_t)xi->data, |
| 213 | xi->bits_per_pixel, (uint32_t)xi->red_mask, |
| 214 | (uint32_t)xi->green_mask, (uint32_t)xi->blue_mask); |
| 215 | |
| 216 | format = ximage_to_image_format(xi->bits_per_pixel, xi->red_mask, xi->green_mask, xi->blue_mask); |
| 217 | if (format == IMAGE_FORMAT_INVALID) |
| 218 | { |
| 219 | XDestroyImage(xi); |
| 220 | return false; |
| 221 | } |
| 222 | |
| 223 | image->format = format; |
| 224 | image->width = xi->width; |
| 225 | image->height = xi->height; |
| 226 | image->stride = xi->bytes_per_line; |
| 227 | image->aux = NULL; |
| 228 | image->storage = xi->data; |
| 229 | |
| 230 | //hacking to see if this pixmap is actually the offscreen pixmap for the window that is our current surface |
| 231 | { |
| 232 | int xw, yw; |
| 233 | unsigned int ww, hw, bw, dw; |
| 234 | unsigned long pixel; |
| 235 | Window rw,win = (Window)CLIENT_GET_THREAD_STATE()->opengl.draw->win; |
| 236 | vcos_log_trace("current EGL surface win %d " , (int)win); |
| 237 | if(win!=0) |
| 238 | { |
| 239 | /* Install our error handler to override Xlib's termination behavior */ |
| 240 | old_handler = XSetErrorHandler(application_error_handler) ; |
| 241 | |
| 242 | XGetGeometry(hacky_display, (Drawable)win, &rw, &xw, &yw, &ww, &hw, &bw, &dw); |
| 243 | vcos_log_trace("%dx%d" , ww, hw); |
| 244 | if(ww==w && hw==h) |
| 245 | { |
| 246 | //this pixmap is the same size as our current window |
| 247 | pixel = XGetPixel(xi,w/2,h/2); |
| 248 | vcos_log_trace("Pixmap centre pixel 0x%lx%s" ,pixel,pixel==CHROMA_KEY_565 ? "- chroma key!!" : "" ); |
| 249 | if(pixel == CHROMA_KEY_565)//the pixmap is also full of our magic chroma key colour, we want to copy the server side EGL surface. |
| 250 | image->aux = (void *)CLIENT_GET_THREAD_STATE()->opengl.draw->serverbuffer ; |
| 251 | } |
| 252 | |
| 253 | (void) XSetErrorHandler(old_handler) ; |
| 254 | } |
| 255 | } |
| 256 | // |
| 257 | |
| 258 | current_ximage = xi; |
| 259 | return true; |
| 260 | } |
| 261 | |
| 262 | void khrn_platform_release_pixmap_info(EGLNativePixmapType pixmap, KHRN_IMAGE_WRAP_T *image) |
| 263 | { |
| 264 | XDestroyImage(current_ximage); |
| 265 | current_ximage = NULL; |
| 266 | } |
| 267 | #else |
| 268 | static KHRN_IMAGE_FORMAT_T convert_format(uint32_t format) |
| 269 | { |
| 270 | switch (format & ~EGL_PIXEL_FORMAT_USAGE_MASK_BRCM) { |
| 271 | case EGL_PIXEL_FORMAT_ARGB_8888_PRE_BRCM: return (KHRN_IMAGE_FORMAT_T)(ABGR_8888 | IMAGE_FORMAT_PRE); |
| 272 | case EGL_PIXEL_FORMAT_ARGB_8888_BRCM: return ABGR_8888; |
| 273 | case EGL_PIXEL_FORMAT_XRGB_8888_BRCM: return XBGR_8888; |
| 274 | case EGL_PIXEL_FORMAT_RGB_565_BRCM: return RGB_565; |
| 275 | case EGL_PIXEL_FORMAT_A_8_BRCM: return A_8; |
| 276 | default: |
| 277 | vcos_assert(0); |
| 278 | return (KHRN_IMAGE_FORMAT_T)0; |
| 279 | } |
| 280 | } |
| 281 | |
| 282 | bool platform_get_pixmap_info(EGLNativePixmapType pixmap, KHRN_IMAGE_WRAP_T *image) |
| 283 | { |
| 284 | image->format = convert_format(((uint32_t *)pixmap)[4]); |
| 285 | image->width = ((uint32_t *)pixmap)[2]; |
| 286 | image->height = ((uint32_t *)pixmap)[3]; |
| 287 | |
| 288 | /* can't actually access data */ |
| 289 | image->stride = 0; |
| 290 | image->aux = 0; |
| 291 | image->storage = 0; |
| 292 | |
| 293 | return image->format != 0; |
| 294 | } |
| 295 | void khrn_platform_release_pixmap_info(EGLNativePixmapType pixmap, KHRN_IMAGE_WRAP_T *image) |
| 296 | { |
| 297 | /* Nothing to do */ |
| 298 | } |
| 299 | #endif |
| 300 | |
| 301 | void platform_get_pixmap_server_handle(EGLNativePixmapType pixmap, uint32_t *handle) |
| 302 | { |
| 303 | handle[0] = ((uint32_t *)pixmap)[0]; |
| 304 | handle[1] = ((uint32_t *)pixmap)[1]; |
| 305 | } |
| 306 | |
| 307 | bool platform_match_pixmap_api_support(EGLNativePixmapType pixmap, uint32_t api_support) |
| 308 | { |
| 309 | return |
| 310 | (!(api_support & EGL_OPENGL_BIT) || (((uint32_t *)pixmap)[4] & EGL_PIXEL_FORMAT_RENDER_GL_BRCM)) && |
| 311 | (!(api_support & EGL_OPENGL_ES_BIT) || (((uint32_t *)pixmap)[4] & EGL_PIXEL_FORMAT_RENDER_GLES_BRCM)) && |
| 312 | (!(api_support & EGL_OPENGL_ES2_BIT) || (((uint32_t *)pixmap)[4] & EGL_PIXEL_FORMAT_RENDER_GLES2_BRCM)) && |
| 313 | (!(api_support & EGL_OPENVG_BIT) || (((uint32_t *)pixmap)[4] & EGL_PIXEL_FORMAT_RENDER_VG_BRCM)); |
| 314 | } |
| 315 | |
| 316 | #if EGL_BRCM_global_image && EGL_KHR_image |
| 317 | |
| 318 | bool platform_use_global_image_as_egl_image(uint32_t id_0, uint32_t id_1, EGLNativePixmapType pixmap, EGLint *error) |
| 319 | { |
| 320 | return true; |
| 321 | } |
| 322 | |
| 323 | void platform_acquire_global_image(uint32_t id_0, uint32_t id_1) |
| 324 | { |
| 325 | } |
| 326 | |
| 327 | void platform_release_global_image(uint32_t id_0, uint32_t id_1) |
| 328 | { |
| 329 | } |
| 330 | |
| 331 | void platform_get_global_image_info(uint32_t id_0, uint32_t id_1, |
| 332 | uint32_t *pixel_format, uint32_t *width, uint32_t *height) |
| 333 | { |
| 334 | EGLint id[2] = {id_0, id_1}; |
| 335 | EGLint width_height_pixel_format[3]; |
| 336 | verify(eglQueryGlobalImageBRCM(id, width_height_pixel_format)); |
| 337 | width_height_pixel_format[2] |= |
| 338 | /* this isn't right (the flags should be those passed in to |
| 339 | * eglCreateGlobalImageBRCM), but this stuff is just for basic testing, so |
| 340 | * it doesn't really matter */ |
| 341 | EGL_PIXEL_FORMAT_RENDER_GLES_BRCM | EGL_PIXEL_FORMAT_RENDER_GLES2_BRCM | |
| 342 | EGL_PIXEL_FORMAT_RENDER_VG_BRCM | EGL_PIXEL_FORMAT_VG_IMAGE_BRCM | |
| 343 | EGL_PIXEL_FORMAT_GLES_TEXTURE_BRCM | EGL_PIXEL_FORMAT_GLES2_TEXTURE_BRCM; |
| 344 | if (pixel_format) { *pixel_format = width_height_pixel_format[2]; } |
| 345 | if (width) { *width = width_height_pixel_format[0]; } |
| 346 | if (height) { *height = width_height_pixel_format[1]; } |
| 347 | } |
| 348 | |
| 349 | #endif |
| 350 | |
| 351 | void platform_client_lock(void) |
| 352 | { |
| 353 | platform_mutex_acquire(&client_mutex); |
| 354 | } |
| 355 | |
| 356 | void platform_client_release(void) |
| 357 | { |
| 358 | platform_mutex_release(&client_mutex); |
| 359 | } |
| 360 | |
| 361 | void platform_init_rpc(struct CLIENT_THREAD_STATE *state) |
| 362 | { |
| 363 | assert(1); |
| 364 | } |
| 365 | |
| 366 | void platform_term_rpc(struct CLIENT_THREAD_STATE *state) |
| 367 | { |
| 368 | assert(1); |
| 369 | } |
| 370 | |
| 371 | void platform_maybe_free_process(void) |
| 372 | { |
| 373 | assert(1); |
| 374 | } |
| 375 | |
| 376 | void platform_destroy_winhandle(void *a, uint32_t b) |
| 377 | { |
| 378 | assert(1); |
| 379 | } |
| 380 | |
| 381 | void platform_surface_update(uint32_t handle) |
| 382 | { |
| 383 | /* |
| 384 | XXX This seems as good a place as any to do the client side pixmap hack. |
| 385 | (called from eglSwapBuffers) |
| 386 | */ |
| 387 | send_bound_pixmaps(); |
| 388 | } |
| 389 | |
| 390 | void egl_gce_win_change_image(void) |
| 391 | { |
| 392 | assert(0); |
| 393 | } |
| 394 | |
| 395 | void platform_retrieve_pixmap_completed(EGLNativePixmapType pixmap) |
| 396 | { |
| 397 | assert(0); |
| 398 | } |
| 399 | |
| 400 | void platform_send_pixmap_completed(EGLNativePixmapType pixmap) |
| 401 | { |
| 402 | assert(0); |
| 403 | } |
| 404 | |
| 405 | uint32_t platform_memcmp(const void * aLeft, const void * aRight, size_t aLen) |
| 406 | { |
| 407 | return memcmp(aLeft, aRight, aLen); |
| 408 | } |
| 409 | |
| 410 | void platform_memcpy(void * aTrg, const void * aSrc, size_t aLength) |
| 411 | { |
| 412 | memcpy(aTrg, aSrc, aLength); |
| 413 | } |
| 414 | |
| 415 | |
| 416 | #ifdef WANT_X |
| 417 | uint32_t platform_get_handle(EGLNativeWindowType win) |
| 418 | { |
| 419 | return (uint32_t)win; |
| 420 | } |
| 421 | |
| 422 | void platform_get_dimensions(EGLDisplay dpy, EGLNativeWindowType win, |
| 423 | uint32_t *width, uint32_t *height, uint32_t *swapchain_count) |
| 424 | { |
| 425 | Window w = (Window) win; |
| 426 | XWindowAttributes attr; |
| 427 | GC gc; |
| 428 | Status rc = XGetWindowAttributes(hacky_display, w, &attr); |
| 429 | |
| 430 | // check rc is OK and if it is (vcos_assert(rc == 0);?????) |
| 431 | *width = attr.width; |
| 432 | *height = attr.height; |
| 433 | *swapchain_count = 0; |
| 434 | |
| 435 | /* Hackily assume if this function is called then they want to fill with GL stuff. So fill window with chromakey. */ |
| 436 | vcos_log_trace("Calling XCreateGC %d" ,(int)w); |
| 437 | |
| 438 | gc = XCreateGC(hacky_display, w, 0, NULL); |
| 439 | XSetForeground(hacky_display, gc, CHROMA_KEY_565); |
| 440 | |
| 441 | vcos_log_trace("Calling XFillRectangle %d %dx%d" ,(int)w,attr.width, attr.height); |
| 442 | |
| 443 | XFillRectangle(hacky_display, w, gc, 0, 0, attr.width, attr.height); |
| 444 | |
| 445 | vcos_log_trace("Calling XFreeGC" ); |
| 446 | |
| 447 | XFreeGC(hacky_display, gc); |
| 448 | |
| 449 | vcos_log_trace("Done platform_get_dimensions" ); |
| 450 | //debugging |
| 451 | dump_hierarchy(attr.root, w, 0, 0); |
| 452 | } |
| 453 | #endif |
| 454 | |
| 455 | #ifdef WANT_X |
| 456 | EGLDisplay khrn_platform_set_display_id(EGLNativeDisplayType display_id) |
| 457 | { |
| 458 | if(hacky_display==0) |
| 459 | { |
| 460 | hacky_display = (Display *)display_id; |
| 461 | return (EGLDisplay)1; |
| 462 | } |
| 463 | else |
| 464 | return EGL_NO_DISPLAY; |
| 465 | } |
| 466 | #else |
| 467 | EGLDisplay khrn_platform_set_display_id(EGLNativeDisplayType display_id) |
| 468 | { |
| 469 | if (display_id == EGL_DEFAULT_DISPLAY) |
| 470 | return (EGLDisplay)1; |
| 471 | else |
| 472 | return EGL_NO_DISPLAY; |
| 473 | } |
| 474 | #endif |
| 475 | |
| 476 | #ifdef WANT_X |
| 477 | static void dump_hierarchy(Window w, Window thisw, Window look, int level) |
| 478 | { |
| 479 | Window root_dummy, parent_dummy, *children; |
| 480 | unsigned int i, nchildren; |
| 481 | XWindowAttributes attr; |
| 482 | |
| 483 | XGetWindowAttributes(hacky_display, w, &attr); |
| 484 | XQueryTree(hacky_display, w, &root_dummy, &parent_dummy, &children, &nchildren); |
| 485 | |
| 486 | for (i = 0; i < level; i++) |
| 487 | { |
| 488 | vcos_log_trace(" " ); |
| 489 | } |
| 490 | vcos_log_trace( "%d %d%s%s" , |
| 491 | attr.map_state, (int)w, |
| 492 | (w==look)?" <-- LOOK FOR ME!" :((w==thisw)?" <-- THIS WINDOW" :"" ), |
| 493 | children?"" :" no children" ); |
| 494 | |
| 495 | if (children) |
| 496 | { |
| 497 | for (i = 0; i < nchildren; i++) |
| 498 | { |
| 499 | dump_hierarchy(children[i], thisw, look, level + 1); |
| 500 | } |
| 501 | XFree(children); |
| 502 | } |
| 503 | } |
| 504 | |
| 505 | static void dump_ancestors(Window w) |
| 506 | { |
| 507 | Window root_dummy, *children; |
| 508 | unsigned int i, nchildren; |
| 509 | |
| 510 | Window grandparent,parent = w, child = 0; |
| 511 | unsigned int rlayer = ~0; |
| 512 | bool bidirectional; |
| 513 | vcos_log_trace("walking back up hierarchy" ); |
| 514 | while(parent) |
| 515 | { |
| 516 | bidirectional = false; |
| 517 | if(!XQueryTree(hacky_display, parent, &root_dummy, &grandparent, &children, &nchildren)) |
| 518 | break; |
| 519 | if (children) |
| 520 | { |
| 521 | for (i = 0; i < nchildren; i++) |
| 522 | { |
| 523 | if (children[i] == child) |
| 524 | { |
| 525 | bidirectional = true; |
| 526 | rlayer = i; |
| 527 | } |
| 528 | } |
| 529 | XFree(children); |
| 530 | } |
| 531 | vcos_log_trace("%s%s%d" , bidirectional ? "<" : "" , (child>0) ? "->" : "" , (int)parent); |
| 532 | |
| 533 | child = parent; |
| 534 | parent = grandparent; |
| 535 | |
| 536 | } |
| 537 | vcos_log_trace("->end" ); |
| 538 | } |
| 539 | |
| 540 | |
| 541 | uint32_t khrn_platform_get_window_position(EGLNativeWindowType win) |
| 542 | { |
| 543 | Window w = (Window) win; |
| 544 | Window dummy; |
| 545 | XWindowAttributes attr; |
| 546 | Window look_for_me, root_dummy, root_dummy2, parent_dummy, *children; |
| 547 | int x, y; |
| 548 | unsigned int layer, i, nchildren; |
| 549 | |
| 550 | //the assumption is that windows are at the 2nd level i.e. in the below |
| 551 | //root_dummy/attr.root -> look_for_me -> w |
| 552 | vcos_log_trace("Start khrn_platform_get_window_position" ); |
| 553 | |
| 554 | XGetWindowAttributes(hacky_display, w, &attr); |
| 555 | |
| 556 | vcos_log_trace("XGetWindowAttributes" ); |
| 557 | |
| 558 | if (attr.map_state == IsViewable) |
| 559 | { |
| 560 | XTranslateCoordinates(hacky_display, w, attr.root, 0, 0, &x, &y, &dummy); |
| 561 | |
| 562 | vcos_log_trace("XTranslateCoordinates" ); |
| 563 | |
| 564 | XQueryTree(hacky_display, w, &root_dummy, &look_for_me, &children, &nchildren); |
| 565 | if (children) XFree(children); |
| 566 | XQueryTree(hacky_display, attr.root, &root_dummy2, &parent_dummy, &children, &nchildren); |
| 567 | |
| 568 | vcos_log_trace("XQueryTree" ); |
| 569 | |
| 570 | layer = ~0; |
| 571 | |
| 572 | vcos_log_trace("Dumping hierarchy %d %d (%d)" , (int)w, (int)look_for_me, (int)root_dummy); |
| 573 | dump_hierarchy(attr.root, w, look_for_me, 0); |
| 574 | |
| 575 | if (children) |
| 576 | { |
| 577 | for (i = 0; i < nchildren; i++) |
| 578 | { |
| 579 | if (children[i] == look_for_me) |
| 580 | layer = i; |
| 581 | } |
| 582 | XFree(children); |
| 583 | } |
| 584 | |
| 585 | vcos_log_trace("XFree" ); |
| 586 | |
| 587 | if (layer == ~0) |
| 588 | { |
| 589 | vcos_log_error("EGL window isn't child of root" , i); |
| 590 | |
| 591 | //to try and find out where this window has gone, let us walk back up the hierarchy |
| 592 | dump_ancestors(w); |
| 593 | return ~0; |
| 594 | } |
| 595 | else |
| 596 | { |
| 597 | vcos_log_trace("End khrn_platform_get_window_position - visible" ); |
| 598 | return x | y << 12 | layer << 24; |
| 599 | } |
| 600 | } |
| 601 | else |
| 602 | { |
| 603 | vcos_log_trace("End khrn_platform_get_window_position - invisible" ); |
| 604 | |
| 605 | return ~0; /* Window is invisible */ |
| 606 | } |
| 607 | } |
| 608 | #else |
| 609 | static int xxx_position = 0; |
| 610 | uint32_t khrn_platform_get_window_position(EGLNativeWindowType win) |
| 611 | { |
| 612 | return xxx_position; |
| 613 | } |
| 614 | #endif |
| 615 | |
| 616 | #define NUM_PIXMAP_BINDINGS 16 |
| 617 | static struct |
| 618 | { |
| 619 | bool used; |
| 620 | bool send; |
| 621 | EGLNativePixmapType pixmap; |
| 622 | EGLImageKHR egl_image; |
| 623 | } pixmap_binding[NUM_PIXMAP_BINDINGS]; |
| 624 | |
| 625 | static void set_egl_image_color_data(EGLImageKHR egl_image, KHRN_IMAGE_WRAP_T *image) |
| 626 | { |
| 627 | int line_size = (image->stride < 0) ? -image->stride : image->stride; |
| 628 | int lines = KHDISPATCH_WORKSPACE_SIZE / line_size; |
| 629 | int offset = 0; |
| 630 | int height = image->height; |
| 631 | |
| 632 | if (khrn_image_is_brcm1(image->format)) |
| 633 | lines &= ~63; |
| 634 | |
| 635 | assert(lines > 0); |
| 636 | |
| 637 | while (height > 0) { |
| 638 | int batch = _min(lines, height); |
| 639 | uint32_t len = batch * line_size; |
| 640 | |
| 641 | CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE(); |
| 642 | int adjusted_offset = (image->stride < 0) ? (offset + (batch - 1)) : offset; |
| 643 | |
| 644 | RPC_CALL8_IN_BULK(eglIntImageSetColorData_impl, |
| 645 | thread, |
| 646 | EGLINTIMAGESETCOLORDATA_ID, |
| 647 | RPC_EGLID(egl_image), |
| 648 | RPC_UINT(image->format), |
| 649 | RPC_UINT(0), |
| 650 | RPC_INT(offset), |
| 651 | RPC_UINT(image->width), |
| 652 | RPC_INT(batch), |
| 653 | RPC_UINT(image->stride), |
| 654 | (const char *)image->storage + adjusted_offset * image->stride, |
| 655 | len); |
| 656 | |
| 657 | offset += batch; |
| 658 | height -= batch; |
| 659 | } |
| 660 | } |
| 661 | |
| 662 | static void send_bound_pixmap(int i) |
| 663 | { |
| 664 | KHRN_IMAGE_WRAP_T image; |
| 665 | |
| 666 | vcos_log_trace("send_bound_pixmap %d %d" , i, (int)pixmap_binding[i].egl_image); |
| 667 | |
| 668 | vcos_assert(i >= 0 && i < NUM_PIXMAP_BINDINGS); |
| 669 | vcos_assert(pixmap_binding[i].used); |
| 670 | |
| 671 | platform_get_pixmap_info(pixmap_binding[i].pixmap, &image); |
| 672 | set_egl_image_color_data(pixmap_binding[i].egl_image, &image); |
| 673 | khrn_platform_release_pixmap_info(pixmap_binding[i].pixmap, &image); |
| 674 | } |
| 675 | |
| 676 | static void send_bound_pixmaps(void) |
| 677 | { |
| 678 | int i; |
| 679 | for (i = 0; i < NUM_PIXMAP_BINDINGS; i++) |
| 680 | { |
| 681 | if (pixmap_binding[i].used && pixmap_binding[i].send) |
| 682 | { |
| 683 | send_bound_pixmap(i); |
| 684 | } |
| 685 | } |
| 686 | } |
| 687 | |
| 688 | void khrn_platform_bind_pixmap_to_egl_image(EGLNativePixmapType pixmap, EGLImageKHR egl_image, bool send) |
| 689 | { |
| 690 | int i; |
| 691 | for (i = 0; i < NUM_PIXMAP_BINDINGS; i++) |
| 692 | { |
| 693 | if (!pixmap_binding[i].used) |
| 694 | { |
| 695 | |
| 696 | vcos_log_trace("khrn_platform_bind_pixmap_to_egl_image %d" , i); |
| 697 | |
| 698 | pixmap_binding[i].used = true; |
| 699 | pixmap_binding[i].pixmap = pixmap; |
| 700 | pixmap_binding[i].egl_image = egl_image; |
| 701 | pixmap_binding[i].send = send; |
| 702 | if(send) |
| 703 | send_bound_pixmap(i); |
| 704 | return; |
| 705 | } |
| 706 | } |
| 707 | vcos_assert(0); /* Not enough NUM_PIXMAP_BINDINGS? */ |
| 708 | } |
| 709 | |
| 710 | void khrn_platform_unbind_pixmap_from_egl_image(EGLImageKHR egl_image) |
| 711 | { |
| 712 | int i; |
| 713 | for (i = 0; i < NUM_PIXMAP_BINDINGS; i++) |
| 714 | { |
| 715 | if (pixmap_binding[i].used && pixmap_binding[i].egl_image == egl_image) |
| 716 | { |
| 717 | pixmap_binding[i].used = false; |
| 718 | } |
| 719 | } |
| 720 | } |
| 721 | |
| 722 | |
| 723 | #ifdef EGL_SERVER_DISPMANX |
| 724 | #define NUM_WIN 6 |
| 725 | |
| 726 | static bool have_default_dwin[NUM_WIN]; |
| 727 | static EGL_DISPMANX_WINDOW_T default_dwin[NUM_WIN]; |
| 728 | |
| 729 | static EGL_DISPMANX_WINDOW_T *check_default(EGLNativeWindowType win) |
| 730 | { |
| 731 | int wid = (int)win; |
| 732 | if(wid>-NUM_WIN && wid <=0) { |
| 733 | /* |
| 734 | * Special identifiers indicating the default windows. Either use the |
| 735 | * one we've got or create a new one |
| 736 | * simple hack for VMCSX_VC4_1.0 release to demonstrate concurrent running of apps under linux |
| 737 | |
| 738 | * win == 0 => full screen window on display 0 |
| 739 | * win == -1 => 1/4 screen top left window on display 0 |
| 740 | * win == -2 => 1/4 screen top right window on display 0 |
| 741 | * win == -3 => 1/4 screen bottom left window on display 0 |
| 742 | * win == -4 => 1/4 screen bottom right window on display 0 |
| 743 | * win == -5 => full screen window on display 2 |
| 744 | |
| 745 | * it is expected that Open WFC will provide a proper mechanism in the near future |
| 746 | */ |
| 747 | wid = -wid; |
| 748 | |
| 749 | if (!have_default_dwin[wid]) { |
| 750 | DISPMANX_DISPLAY_HANDLE_T display = vc_dispmanx_display_open( (wid == 5) ? 2 : 0 ); |
| 751 | DISPMANX_MODEINFO_T info; |
| 752 | vc_dispmanx_display_get_info(display, &info); |
| 753 | int32_t dw = info.width, dh = info.height; |
| 754 | |
| 755 | DISPMANX_UPDATE_HANDLE_T update = vc_dispmanx_update_start( 0 ); |
| 756 | VC_DISPMANX_ALPHA_T alpha = {DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS, 255, 0}; |
| 757 | VC_RECT_T dst_rect; |
| 758 | VC_RECT_T src_rect; |
| 759 | |
| 760 | int x = 0, y = 0, width = 0, height = 0, layer = 0; |
| 761 | |
| 762 | switch(wid) |
| 763 | { |
| 764 | case 0: |
| 765 | x = 0; y = 0; width = dw; height = dh; layer = 0; break; |
| 766 | case 1: |
| 767 | x = 0; y = 0; width = dw/2; height = dh/2; layer = 0; break; |
| 768 | case 2: |
| 769 | x = dw/2; y = 0; width = dw/2; height = dh/2; layer = 0; break; |
| 770 | case 3: |
| 771 | x = 0; y = dh/2; width = dw/2; height = dh/2; layer = 0; break; |
| 772 | case 4: |
| 773 | x = dw/2; y = dh/2; width = dw/2; height = dh/2; layer = 0; break; |
| 774 | case 5: |
| 775 | x = 0; y = 0; width = dw; height = dh; layer = 0; break; |
| 776 | } |
| 777 | |
| 778 | src_rect.x = 0; |
| 779 | src_rect.y = 0; |
| 780 | src_rect.width = width << 16; |
| 781 | src_rect.height = height << 16; |
| 782 | |
| 783 | dst_rect.x = x; |
| 784 | dst_rect.y = y; |
| 785 | dst_rect.width = width; |
| 786 | dst_rect.height = height; |
| 787 | |
| 788 | default_dwin[wid].element = vc_dispmanx_element_add ( update, display, |
| 789 | layer, &dst_rect, 0/*src*/, |
| 790 | &src_rect, DISPMANX_PROTECTION_NONE, &alpha, 0/*clamp*/, 0/*transform*/); |
| 791 | |
| 792 | default_dwin[wid].width = width; |
| 793 | default_dwin[wid].height = height; |
| 794 | |
| 795 | vc_dispmanx_update_submit_sync( update ); |
| 796 | |
| 797 | have_default_dwin[wid] = true; |
| 798 | } |
| 799 | return &default_dwin[wid]; |
| 800 | } else |
| 801 | return (EGL_DISPMANX_WINDOW_T*)win; |
| 802 | } |
| 803 | |
| 804 | |
| 805 | void platform_get_dimensions(EGLDisplay dpy, EGLNativeWindowType win, |
| 806 | uint32_t *width, uint32_t *height, uint32_t *swapchain_count) |
| 807 | { |
| 808 | EGL_DISPMANX_WINDOW_T *dwin = check_default(win); |
| 809 | vcos_assert(dwin); |
| 810 | vcos_assert(dwin->width < 1<<16); // sanity check |
| 811 | vcos_assert(dwin->height < 1<<16); // sanity check |
| 812 | *width = dwin->width; |
| 813 | *height = dwin->height; |
| 814 | *swapchain_count = 0; |
| 815 | } |
| 816 | |
| 817 | uint32_t platform_get_handle(EGLDisplay dpy, EGLNativeWindowType win) |
| 818 | { |
| 819 | EGL_DISPMANX_WINDOW_T *dwin = check_default(win); |
| 820 | vcos_assert(dwin); |
| 821 | vcos_assert(dwin->width < 1<<16); // sanity check |
| 822 | vcos_assert(dwin->height < 1<<16); // sanity check |
| 823 | return dwin->element; |
| 824 | } |
| 825 | |
| 826 | #endif |
| 827 | |
| 828 | uint32_t platform_get_color_format ( uint32_t format ) { return format; } |
| 829 | void platform_dequeue(EGLDisplay dpy, EGLNativeWindowType window) {} |
| 830 | |