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