RDK Documentation (Open Sourced RDK Components)
All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
graphics-lifecycle.cpp
1 /*
2  * If not stated otherwise in this file or this component's Licenses.txt file the
3  * following copyright and licenses apply:
4  *
5  * Copyright 2018 RDK Management
6  * Copyright 2005-2018 John Robinson
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  */
20 /*
21  * Copyright © 2010 Intel Corporation
22  * Copyright © 2011 Benjamin Franzke
23  * Copyright © 2012-2013 Collabora, Ltd.
24  *
25  * Permission is hereby granted, free of charge, to any person obtaining a
26  * copy of this software and associated documentation files (the "Software"),
27  * to deal in the Software without restriction, including without limitation
28  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
29  * and/or sell copies of the Software, and to permit persons to whom the
30  * Software is furnished to do so, subject to the following conditions:
31  *
32  * The above copyright notice and this permission notice (including the next
33  * paragraph) shall be included in all copies or substantial portions of the
34  * Software.
35  *
36  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
37  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
38  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
39  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
40  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
41  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
42  * DEALINGS IN THE SOFTWARE.
43  */
44 #include <stdlib.h>
45 #include <stdio.h>
46 #include <memory.h>
47 #include <assert.h>
48 #include <errno.h>
49 #include <unistd.h>
50 #include <signal.h>
51 #include <termios.h>
52 #include <sys/mman.h>
53 #include <sys/time.h>
54 
55 #include <EGL/egl.h>
56 #include <EGL/eglext.h>
57 
58 #include <GLES2/gl2.h>
59 #include <GLES2/gl2ext.h>
60 
61 #include <xkbcommon/xkbcommon.h>
62 
63 #include "wayland-client.h"
64 #include "wayland-egl.h"
65 #include "simpleshell-client-protocol.h"
66 
67 #include "LifeCycle.h"
68 #include "RtUtils.h"
69 
70 #define UNUSED(x) ((void)x)
71 
72 #if !defined (XKB_KEYMAP_COMPILE_NO_FLAGS)
73 #define XKB_KEYMAP_COMPILE_NO_FLAGS XKB_MAP_COMPILE_NO_FLAGS
74 #endif
75 
76 static void registryHandleGlobal(void *data,
77  struct wl_registry *registry, uint32_t id,
78  const char *interface, uint32_t version);
79 static void registryHandleGlobalRemove(void *data,
80  struct wl_registry *registry,
81  uint32_t name);
82 
83 static const struct wl_registry_listener registryListener =
84 {
85  registryHandleGlobal,
86  registryHandleGlobalRemove
87 };
88 
89 static void shellSurfaceId(void *data,
90  struct wl_simple_shell *wl_simple_shell,
91  struct wl_surface *surface,
92  uint32_t surfaceId);
93 static void shellSurfaceCreated(void *data,
94  struct wl_simple_shell *wl_simple_shell,
95  uint32_t surfaceId,
96  const char *name);
97 static void shellSurfaceDestroyed(void *data,
98  struct wl_simple_shell *wl_simple_shell,
99  uint32_t surfaceId,
100  const char *name);
101 static void shellSurfaceStatus(void *data,
102  struct wl_simple_shell *wl_simple_shell,
103  uint32_t surfaceId,
104  const char *name,
105  uint32_t visible,
106  int32_t x,
107  int32_t y,
108  int32_t width,
109  int32_t height,
110  wl_fixed_t opacity,
111  wl_fixed_t zorder);
112 static void shellGetSurfacesDone(void *data,
113  struct wl_simple_shell *wl_simple_shell);
114 
115 static const struct wl_simple_shell_listener shellListener =
116 {
117  shellSurfaceId,
118  shellSurfaceCreated,
119  shellSurfaceDestroyed,
120  shellSurfaceStatus,
121  shellGetSurfacesDone
122 };
123 
124 typedef enum _InputState
125 {
126  InputState_main,
127  InputState_attribute,
128 } InputState;
129 
130 typedef enum _Attribute
131 {
132  Attribute_position,
133  Attribute_size,
134  Attribute_visibility,
135  Attribute_opacity,
136  Attribute_zorder
137 } Attribute;
138 
139 typedef enum _AppMode
140 {
141  AppMode_Running,
142  AppMode_Suspended,
143 } AppMode;
144 
145 typedef struct _AppCtx
146 {
147  struct wl_display *display;
148  struct wl_registry *registry;
149  struct wl_shm *shm;
150  struct wl_compositor *compositor;
151  struct wl_simple_shell *shell;
152  struct wl_seat *seat;
153  struct wl_keyboard *keyboard;
154  struct wl_pointer *pointer;
155  struct wl_touch *touch;
156  struct wl_surface *surface;
157  struct wl_output *output;
158  struct wl_egl_window *native;
159  struct wl_callback *frameCallback;
160 
161  struct xkb_context *xkbCtx;
162  struct xkb_keymap *xkbKeymap;
163  struct xkb_state *xkbState;
164  xkb_mod_index_t modAlt;
165  xkb_mod_index_t modCtrl;
166 
167  EGLDisplay eglDisplay;
168  EGLConfig eglConfig;
169  EGLSurface eglSurfaceWindow;
170  EGLContext eglContext;
171  EGLImageKHR eglImage;
172  EGLNativePixmapType eglPixmap;
173 
174  bool getShell;
175  InputState inputState;
176  Attribute attribute;
177 
178  int planeX;
179  int planeY;
180  int planeWidth;
181  int planeHeight;
182 
183  uint32_t surfaceIdOther;
184  uint32_t surfaceIdCurrent;
185  float surfaceOpacity;
186  float surfaceZOrder;
187  bool surfaceVisible;
188  int surfaceX;
189  int surfaceY;
190  int surfaceWidth;
191  int surfaceHeight;
192 
193  int surfaceDX;
194  int surfaceDY;
195  int surfaceDWidth;
196  int surfaceDHeight;
197 
198  struct
199  {
200  GLuint rotation_uniform;
201  GLuint pos;
202  GLuint col;
203  } gl;
204  long long startTime;
205  long long currTime;
206  bool noAnimation;
207  bool needRedraw;
208  bool verboseLog;
209  int pointerX, pointerY;
210  AppMode appMode;
211 } AppCtx;
212 
213 static void processInput( AppCtx *ctx, uint32_t sym );
214 static void drawFrame( AppCtx *ctx );
215 static bool setupEGL( AppCtx *ctx );
216 static void termEGL( AppCtx *ctx );
217 static bool createSurface( AppCtx *ctx );
218 static void resizeSurface( AppCtx *ctx, int dx, int dy, int width, int height );
219 static void destroySurface( AppCtx *ctx );
220 static bool setupGL( AppCtx *ctx );
221 static bool renderGL( AppCtx *ctx );
222 
223 int g_running= 0;
224 int g_log= 0;
225 
226 static GraphicsLifeCycle *sLifeCycle = NULL;
227 static RtUtils *sRtUtils = NULL;
228 pthread_cond_t g_cond;
229 pthread_mutex_t g_mutex;
230 AppMode g_requestMode = AppMode_Running;
231 
232 static void signalHandler(int signum)
233 {
234  printf("signalHandler: signum %d\n", signum);
235  g_running = 0;
236 
237  pthread_mutex_lock(&g_mutex);
238  pthread_cond_signal(&g_cond);
239  pthread_mutex_unlock(&g_mutex);
240 }
241 
242 static long long currentTimeMillis()
243 {
244  long long timeMillis;
245  struct timeval tv;
246 
247  gettimeofday(&tv, NULL);
248  timeMillis = tv.tv_sec * 1000 + tv.tv_usec / 1000;
249 
250  return timeMillis;
251 }
252 
253 static void shmFormat(void *data, struct wl_shm *wl_shm, uint32_t format)
254 {
255  AppCtx *ctx = (AppCtx*)data;
256 
257  printf("shm format: %X\n", format);
258 }
259 
260 struct wl_shm_listener shmListener = {
261  shmFormat
262 };
263 
264 static void keyboardKeymap( void *data, struct wl_keyboard *keyboard, uint32_t format, int32_t fd, uint32_t size )
265 {
266  AppCtx *ctx= (AppCtx*)data;
267 
268  if ( format == WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1 )
269  {
270  void *map= mmap( 0, size, PROT_READ, MAP_SHARED, fd, 0 );
271  if ( map != MAP_FAILED )
272  {
273  if ( !ctx->xkbCtx )
274  {
275  ctx->xkbCtx= xkb_context_new( XKB_CONTEXT_NO_FLAGS );
276  }
277  else
278  {
279  printf("error: xkb_context_new failed\n");
280  }
281  if ( ctx->xkbCtx )
282  {
283  if ( ctx->xkbKeymap )
284  {
285  xkb_keymap_unref( ctx->xkbKeymap );
286  ctx->xkbKeymap= 0;
287  }
288  ctx->xkbKeymap= xkb_keymap_new_from_string( ctx->xkbCtx, (char*)map, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS);
289  if ( !ctx->xkbKeymap )
290  {
291  printf("error: xkb_keymap_new_from_string failed\n");
292  }
293  if ( ctx->xkbState )
294  {
295  xkb_state_unref( ctx->xkbState );
296  ctx->xkbState= 0;
297  }
298  ctx->xkbState= xkb_state_new( ctx->xkbKeymap );
299  if ( !ctx->xkbState )
300  {
301  printf("error: xkb_state_new failed\n");
302  }
303  if ( ctx->xkbKeymap )
304  {
305  ctx->modAlt= xkb_keymap_mod_get_index( ctx->xkbKeymap, XKB_MOD_NAME_ALT );
306  ctx->modCtrl= xkb_keymap_mod_get_index( ctx->xkbKeymap, XKB_MOD_NAME_CTRL );
307  }
308  munmap( map, size );
309  }
310  }
311  }
312 
313  close( fd );
314 }
315 
316 static void keyboardEnter( void *data, struct wl_keyboard *keyboard, uint32_t serial,
317  struct wl_surface *surface, struct wl_array *keys )
318 {
319  UNUSED(data);
320  UNUSED(keyboard);
321  UNUSED(serial);
322  UNUSED(keys);
323 
324  printf("keyboard enter surface %p\n", surface );
325 }
326 
327 static void keyboardLeave( void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface )
328 {
329  UNUSED(data);
330  UNUSED(keyboard);
331  UNUSED(serial);
332 
333  printf("keyboard leave surface %p\n", surface );
334 }
335 
336 static void keyboardKey( void *data, struct wl_keyboard *keyboard, uint32_t serial,
337  uint32_t time, uint32_t key, uint32_t state )
338 {
339  AppCtx *ctx= (AppCtx*)data;
340  UNUSED(keyboard);
341  UNUSED(serial);
342  xkb_keycode_t keyCode;
343  uint32_t sym;
344 
345  if ( ctx->xkbState )
346  {
347  // As per wayland protocol for XKB_V1 map, we must add 8 to the key code
348  keyCode= key+8;
349 
350  sym= xkb_state_key_get_one_sym( ctx->xkbState, keyCode );
351 
352  if ( ctx->verboseLog )
353  {
354  int ctrl= 0;
355  int alt= 0;
356 
357  if ( xkb_state_mod_index_is_active( ctx->xkbState, ctx->modCtrl, XKB_STATE_MODS_DEPRESSED) == 1 )
358  {
359  ctrl= 1;
360  }
361 
362  if ( xkb_state_mod_index_is_active( ctx->xkbState, ctx->modAlt, XKB_STATE_MODS_DEPRESSED) == 1 )
363  {
364  alt= 1;
365  }
366 
367  printf("keyboardKey: sym %X state %s ctrl %d alt %d time %u\n",
368  sym, (state == WL_KEYBOARD_KEY_STATE_PRESSED ? "Down" : "Up"), ctrl, alt, time);
369  }
370 
371  if ( state == WL_KEYBOARD_KEY_STATE_PRESSED )
372  {
373  processInput( ctx, sym );
374  }
375  }
376 }
377 
378 static void keyboardModifiers( void *data, struct wl_keyboard *keyboard, uint32_t serial,
379  uint32_t mods_depressed, uint32_t mods_latched,
380  uint32_t mods_locked, uint32_t group )
381 {
382  AppCtx *ctx= (AppCtx*)data;
383  if ( ctx->xkbState )
384  {
385  xkb_state_update_mask( ctx->xkbState, mods_depressed, mods_latched, mods_locked, 0, 0, group );
386  }
387 }
388 
389 static void keyboardRepeatInfo( void *data, struct wl_keyboard *keyboard, int32_t rate, int32_t delay )
390 {
391  UNUSED(data);
392  UNUSED(keyboard);
393  UNUSED(rate);
394  UNUSED(delay);
395 }
396 
397 static const struct wl_keyboard_listener keyboardListener= {
398  keyboardKeymap,
399  keyboardEnter,
400  keyboardLeave,
401  keyboardKey,
402  keyboardModifiers,
403  keyboardRepeatInfo
404 };
405 
406 static void pointerEnter( void* data, struct wl_pointer *pointer, uint32_t serial,
407  struct wl_surface *surface, wl_fixed_t sx, wl_fixed_t sy )
408 {
409  UNUSED(pointer);
410  UNUSED(serial);
411  AppCtx *ctx= (AppCtx*)data;
412  int x, y;
413 
414  x= wl_fixed_to_int( sx );
415  y= wl_fixed_to_int( sy );
416 
417  ctx->pointerX= x;
418  ctx->pointerY= y;
419 
420  printf("pointer enter surface %p (%d,%d)\n", surface, x, y );
421 }
422 
423 static void pointerLeave( void* data, struct wl_pointer *pointer, uint32_t serial, struct wl_surface *surface )
424 {
425  UNUSED(data);
426  UNUSED(pointer);
427  UNUSED(serial);
428 
429  printf("pointer leave surface %p\n", surface );
430 }
431 
432 static void pointerMotion( void *data, struct wl_pointer *pointer, uint32_t time, wl_fixed_t sx, wl_fixed_t sy )
433 {
434  UNUSED(pointer);
435  AppCtx *ctx= (AppCtx*)data;
436  int x, y;
437 
438  x= wl_fixed_to_int( sx );
439  y= wl_fixed_to_int( sy );
440 
441  ctx->pointerX= x;
442  ctx->pointerY= y;
443 
444  if ( ctx->verboseLog )
445  {
446  printf("pointer motion surface (%d,%d) time %u\n", x, y, time );
447  }
448 }
449 
450 static void pointerButton( void *data, struct wl_pointer *pointer, uint32_t serial,
451  uint32_t time, uint32_t button, uint32_t state )
452 {
453  UNUSED(pointer);
454  UNUSED(serial);
455  AppCtx *ctx= (AppCtx*)data;
456 
457  printf("pointer button %u state %u (%d, %d)\n", button, state, ctx->pointerX, ctx->pointerY);
458  ctx->verboseLog= (state == WL_POINTER_BUTTON_STATE_PRESSED);
459 }
460 
461 static void pointerAxis( void *data, struct wl_pointer *pointer, uint32_t time,
462  uint32_t axis, wl_fixed_t value )
463 {
464  UNUSED(data);
465  UNUSED(pointer);
466  UNUSED(time);
467  int v;
468 
469  v= wl_fixed_to_int( value );
470  printf("pointer axis %u value %d\n", axis, v);
471 }
472 
473 static const struct wl_pointer_listener pointerListener = {
474  pointerEnter,
475  pointerLeave,
476  pointerMotion,
477  pointerButton,
478  pointerAxis
479 };
480 
481 static void seatCapabilities( void *data, struct wl_seat *seat, uint32_t capabilities )
482 {
483  AppCtx *ctx = (AppCtx*)data;
484 
485  printf("seat %p caps: %X\n", seat, capabilities );
486 
487  if ( capabilities & WL_SEAT_CAPABILITY_KEYBOARD )
488  {
489  printf(" seat has keyboard\n");
490  ctx->keyboard= wl_seat_get_keyboard( ctx->seat );
491  printf(" keyboard %p\n", ctx->keyboard );
492  wl_keyboard_add_listener( ctx->keyboard, &keyboardListener, ctx );
493  }
494  if ( capabilities & WL_SEAT_CAPABILITY_POINTER )
495  {
496  printf(" seat has pointer\n");
497  ctx->pointer= wl_seat_get_pointer( ctx->seat );
498  printf(" pointer %p\n", ctx->pointer );
499  wl_pointer_add_listener( ctx->pointer, &pointerListener, ctx );
500  }
501  if ( capabilities & WL_SEAT_CAPABILITY_TOUCH )
502  {
503  printf(" seat has touch\n");
504  ctx->touch= wl_seat_get_touch( ctx->seat );
505  printf(" touch %p\n", ctx->touch );
506  }
507 }
508 
509 static void seatName( void *data, struct wl_seat *seat, const char *name )
510 {
511  AppCtx *ctx = (AppCtx*)data;
512  printf("seat %p name: %s\n", seat, name);
513 }
514 
515 static const struct wl_seat_listener seatListener = {
516  seatCapabilities,
517  seatName
518 };
519 
520 static void outputGeometry( void *data, struct wl_output *output, int32_t x, int32_t y,
521  int32_t physical_width, int32_t physical_height, int32_t subpixel,
522  const char *make, const char *model, int32_t transform )
523 {
524  UNUSED(data);
525  UNUSED(output);
526  UNUSED(x);
527  UNUSED(y);
528  UNUSED(physical_width);
529  UNUSED(physical_height);
530  UNUSED(subpixel);
531  UNUSED(make);
532  UNUSED(model);
533  UNUSED(transform);
534 }
535 
536 static void outputMode( void *data, struct wl_output *output, uint32_t flags,
537  int32_t width, int32_t height, int32_t refresh )
538 {
539  AppCtx *ctx = (AppCtx*)data;
540 
541  if ( flags & WL_OUTPUT_MODE_CURRENT )
542  {
543  if ( (width != ctx->planeWidth) || (height != ctx->planeHeight) )
544  {
545  ctx->planeWidth= width;
546  ctx->planeHeight= height;
547  if ( ctx->verboseLog )
548  {
549  printf("outputMode: resize egl window to (%d,%d)\n", ctx->planeWidth, ctx->planeHeight );
550  }
551  resizeSurface( ctx, 0, 0, ctx->planeWidth, ctx->planeHeight);
552  }
553  }
554 }
555 
556 static void outputDone( void *data, struct wl_output *output )
557 {
558  UNUSED(data);
559  UNUSED(output);
560 }
561 
562 static void outputScale( void *data, struct wl_output *output, int32_t factor )
563 {
564  UNUSED(data);
565  UNUSED(output);
566  UNUSED(factor);
567 }
568 
569 static const struct wl_output_listener outputListener = {
570  outputGeometry,
571  outputMode,
572  outputDone,
573  outputScale
574 };
575 
576 static void registryHandleGlobal(void *data,
577  struct wl_registry *registry, uint32_t id,
578  const char *interface, uint32_t version)
579 {
580  AppCtx *ctx = (AppCtx*)data;
581  int len;
582 
583  printf("graphics-lifecycle: registry: id %d interface (%s) version %d\n", id, interface, version );
584 
585  len= strlen(interface);
586  if ( (len==6) && !strncmp(interface, "wl_shm", len)) {
587  ctx->shm= (struct wl_shm*)wl_registry_bind(registry, id, &wl_shm_interface, 1);
588  printf("shm %p\n", ctx->shm);
589  wl_shm_add_listener(ctx->shm, &shmListener, ctx);
590  }
591  else if ( (len==13) && !strncmp(interface, "wl_compositor", len) ) {
592  ctx->compositor= (struct wl_compositor*)wl_registry_bind(registry, id, &wl_compositor_interface, 1);
593  printf("compositor %p\n", ctx->compositor);
594  }
595  else if ( (len==7) && !strncmp(interface, "wl_seat", len) ) {
596  ctx->seat= (struct wl_seat*)wl_registry_bind(registry, id, &wl_seat_interface, 4);
597  printf("seat %p\n", ctx->seat);
598  wl_seat_add_listener(ctx->seat, &seatListener, ctx);
599  }
600  else if ( (len==9) && !strncmp(interface, "wl_output", len) ) {
601  ctx->output= (struct wl_output*)wl_registry_bind(registry, id, &wl_output_interface, 2);
602  printf("output %p\n", ctx->output);
603  wl_output_add_listener(ctx->output, &outputListener, ctx);
604  }
605  else if ( (len==15) && !strncmp(interface, "wl_simple_shell", len) ) {
606  if ( ctx->getShell ) {
607  ctx->shell= (struct wl_simple_shell*)wl_registry_bind(registry, id, &wl_simple_shell_interface, 1);
608  printf("shell %p\n", ctx->shell );
609  wl_simple_shell_add_listener(ctx->shell, &shellListener, ctx);
610  }
611  }
612 }
613 
614 static void registryHandleGlobalRemove(void *data,
615  struct wl_registry *registry,
616  uint32_t name)
617 {
618 }
619 
620 static void shellSurfaceId(void *data,
621  struct wl_simple_shell *wl_simple_shell,
622  struct wl_surface *surface,
623  uint32_t surfaceId)
624 {
625  AppCtx *ctx = (AppCtx*)data;
626  char name[32];
627 
628  sprintf( name, "graphics-lifecycle-surface-%x", surfaceId );
629  printf("shell: surface created: %p id %x\n", surface, surfaceId);
630  wl_simple_shell_set_name( ctx->shell, surfaceId, name );
631 }
632 
633 static void shellSurfaceCreated(void *data,
634  struct wl_simple_shell *wl_simple_shell,
635  uint32_t surfaceId,
636  const char *name)
637 {
638  AppCtx *ctx = (AppCtx*)data;
639 
640  printf("shell: surface created: %x name: %s\n", surfaceId, name);
641  ctx->surfaceIdOther= ctx->surfaceIdCurrent;
642  ctx->surfaceIdCurrent= surfaceId;
643  wl_simple_shell_get_status( ctx->shell, ctx->surfaceIdCurrent );
644  printf("shell: surfaceCurrent: %x surfaceOther: %x\n", ctx->surfaceIdCurrent, ctx->surfaceIdOther);
645 }
646 
647 static void shellSurfaceDestroyed(void *data,
648  struct wl_simple_shell *wl_simple_shell,
649  uint32_t surfaceId,
650  const char *name)
651 {
652  AppCtx *ctx = (AppCtx*)data;
653 
654  printf("shell: surface destroyed: %x name: %s\n", surfaceId, name);
655 
656  if ( ctx->surfaceIdCurrent == surfaceId )
657  {
658  ctx->surfaceIdCurrent= ctx->surfaceIdOther;
659  ctx->surfaceIdOther= 0;
660  wl_simple_shell_get_status( ctx->shell, ctx->surfaceIdCurrent );
661  }
662  if ( ctx->surfaceIdOther == surfaceId )
663  {
664  ctx->surfaceIdOther= 0;
665  }
666  printf("shell: surfaceCurrent: %x surfaceOther: %x\n", ctx->surfaceIdCurrent, ctx->surfaceIdOther);
667 }
668 
669 static void shellSurfaceStatus(void *data,
670  struct wl_simple_shell *wl_simple_shell,
671  uint32_t surfaceId,
672  const char *name,
673  uint32_t visible,
674  int32_t x,
675  int32_t y,
676  int32_t width,
677  int32_t height,
678  wl_fixed_t opacity,
679  wl_fixed_t zorder)
680 {
681  AppCtx *ctx = (AppCtx*)data;
682 
683  printf("shell: surface: %x name: %s\n", surfaceId, name);
684  printf("shell: position (%d,%d,%d,%d) visible %d opacity %f zorder %f\n",
685  x, y, width, height, visible, wl_fixed_to_double(opacity), wl_fixed_to_double(zorder) );
686 
687  ctx->surfaceVisible= visible;
688  ctx->surfaceX= x;
689  ctx->surfaceY= y;
690  ctx->surfaceWidth= width;
691  ctx->surfaceHeight= height;
692  ctx->surfaceOpacity= wl_fixed_to_double(opacity);
693  ctx->surfaceZOrder= wl_fixed_to_double(zorder);
694 }
695 
696 static void shellGetSurfacesDone(void *data,
697  struct wl_simple_shell *wl_simple_shell)
698 {
699  AppCtx *ctx = (AppCtx*)data;
700  printf("shell: get all surfaces done\n");
701 }
702 
703 #define NON_BLOCKING_ENABLED (0)
704 #define NON_BLOCKING_DISABLED (1)
705 
706 static void setBlockingMode(int blockingState )
707 {
708  struct termios ttystate;
709  int mask, bits;
710 
711  mask= (blockingState == NON_BLOCKING_ENABLED) ? ~(ICANON|ECHO) : -1;
712  bits= (blockingState == NON_BLOCKING_ENABLED) ? 0 : (ICANON|ECHO);
713 
714  // Obtain the current terminal state and alter the attributes to achieve
715  // the requested blocking behaviour
716  tcgetattr(STDIN_FILENO, &ttystate);
717 
718  ttystate.c_lflag= ((ttystate.c_lflag & mask) | bits);
719 
720  if (blockingState == NON_BLOCKING_ENABLED)
721  {
722  ttystate.c_cc[VMIN]= 1;
723  }
724 
725  tcsetattr(STDIN_FILENO, TCSANOW, &ttystate);
726 }
727 
728 static bool isKeyHit()
729 {
730  bool keyHit= false;
731  fd_set fdset;
732  struct timeval tval;
733 
734  // do a non-blocking check to see if any keys
735  // are ready to read from stdin
736  tval.tv_sec= 0;
737  tval.tv_usec= 0;
738  FD_ZERO(&fdset);
739  FD_SET(STDIN_FILENO, &fdset);
740  select(STDIN_FILENO+1, &fdset, NULL, NULL, &tval);
741 
742  keyHit= FD_ISSET(STDIN_FILENO, &fdset);
743 
744  return keyHit;
745 }
746 
747 static void adjustAttribute( AppCtx *ctx, uint32_t sym )
748 {
749  switch( ctx->attribute )
750  {
751  case Attribute_position:
752  switch( sym )
753  {
754  case XKB_KEY_Up:
755  --ctx->surfaceDY;
756  break;
757  case XKB_KEY_Down:
758  ++ctx->surfaceDY;
759  break;
760  case XKB_KEY_Right:
761  ++ctx->surfaceDX;
762  break;
763  case XKB_KEY_Left:
764  --ctx->surfaceDX;
765  break;
766  }
767  break;
768  case Attribute_size:
769  switch( sym )
770  {
771  case XKB_KEY_Up:
772  --ctx->surfaceDHeight;
773  break;
774  case XKB_KEY_Down:
775  ++ctx->surfaceDHeight;
776  break;
777  case XKB_KEY_Right:
778  ++ctx->surfaceDWidth;
779  break;
780  case XKB_KEY_Left:
781  --ctx->surfaceDWidth;
782  break;
783  }
784  break;
785  case Attribute_visibility:
786  switch( sym )
787  {
788  case XKB_KEY_Up:
789  case XKB_KEY_Right:
790  case XKB_KEY_Down:
791  case XKB_KEY_Left:
792  ctx->surfaceVisible= !ctx->surfaceVisible;
793  wl_simple_shell_set_visible( ctx->shell, ctx->surfaceIdCurrent, (ctx->surfaceVisible ? 1 : 0) );
794  break;
795  }
796  break;
797  case Attribute_opacity:
798  switch( sym )
799  {
800  case XKB_KEY_Up:
801  case XKB_KEY_Right:
802  ctx->surfaceOpacity += 0.1;
803  if ( ctx->surfaceOpacity > 1.0 )
804  {
805  ctx->surfaceOpacity= 1.0;
806  }
807  wl_simple_shell_set_opacity( ctx->shell, ctx->surfaceIdCurrent, wl_fixed_from_double(ctx->surfaceOpacity) );
808  break;
809  case XKB_KEY_Down:
810  case XKB_KEY_Left:
811  ctx->surfaceOpacity -= 0.1;
812  if ( ctx->surfaceOpacity < 0.0 )
813  {
814  ctx->surfaceOpacity= 0.0;
815  }
816  wl_simple_shell_set_opacity( ctx->shell, ctx->surfaceIdCurrent, wl_fixed_from_double(ctx->surfaceOpacity) );
817  break;
818  }
819  break;
820  case Attribute_zorder:
821  switch( sym )
822  {
823  case XKB_KEY_Up:
824  case XKB_KEY_Right:
825  ctx->surfaceZOrder += 0.1;
826  if ( ctx->surfaceZOrder > 1.0 )
827  {
828  ctx->surfaceZOrder= 1.0;
829  }
830  wl_simple_shell_set_zorder( ctx->shell, ctx->surfaceIdCurrent, wl_fixed_from_double(ctx->surfaceZOrder) );
831  break;
832  case XKB_KEY_Down:
833  case XKB_KEY_Left:
834  ctx->surfaceZOrder -= 0.1;
835  if ( ctx->surfaceZOrder < 0.0 )
836  {
837  ctx->surfaceZOrder= 0.0;
838  }
839  wl_simple_shell_set_zorder( ctx->shell, ctx->surfaceIdCurrent, wl_fixed_from_double(ctx->surfaceZOrder) );
840  break;
841  }
842  break;
843  }
844 }
845 
846 static void processInputMain( AppCtx *ctx, uint32_t sym )
847 {
848  switch( sym )
849  {
850  case XKB_KEY_Left:
851  case XKB_KEY_Up:
852  case XKB_KEY_Right:
853  case XKB_KEY_Down:
854  if ( ctx->surfaceIdCurrent )
855  {
856  adjustAttribute( ctx, sym );
857  }
858  break;
859  case XKB_KEY_a:
860  ctx->inputState= InputState_attribute;
861  printf("attribute: (p) osition, (s) ize, (v) isible, (o) pacity, (z) order (x) back to main\n");
862  break;
863  case XKB_KEY_s:
864  if ( ctx->surfaceIdCurrent )
865  {
866  wl_simple_shell_get_status( ctx->shell, ctx->surfaceIdCurrent );
867  }
868  break;
869  case XKB_KEY_n:
870  if ( ctx->surfaceIdOther )
871  {
872  uint32_t temp= ctx->surfaceIdCurrent;
873  ctx->surfaceIdCurrent= ctx->surfaceIdOther;
874  ctx->surfaceIdOther= temp;
875  printf("shell: surfaceCurrent: %x surfaceOther: %x\n", ctx->surfaceIdCurrent, ctx->surfaceIdOther);
876  wl_simple_shell_get_status( ctx->shell, ctx->surfaceIdCurrent );
877  }
878  break;
879  case XKB_KEY_l:
880  if ( ctx->shell )
881  {
882  printf("get all surfaces:\n");
883  wl_simple_shell_get_surfaces( ctx->shell );
884  }
885  break;
886  case XKB_KEY_r:
887  ctx->planeWidth= (ctx->planeWidth == 1280) ? 640 : 1280;
888  ctx->planeHeight= (ctx->planeHeight == 720) ? 360 : 720;
889  printf("resize egl window to (%d,%d)\n", ctx->planeWidth, ctx->planeHeight );
890  resizeSurface( ctx, 0, 0, ctx->planeWidth, ctx->planeHeight);
891  break;
892  }
893 }
894 
895 static void processInputAttribute( AppCtx *ctx, uint32_t sym )
896 {
897  switch( sym )
898  {
899  case XKB_KEY_p:
900  ctx->attribute= Attribute_position;
901  break;
902  case XKB_KEY_s:
903  ctx->attribute= Attribute_size;
904  break;
905  case XKB_KEY_v:
906  ctx->attribute= Attribute_visibility;
907  break;
908  case XKB_KEY_o:
909  ctx->attribute= Attribute_opacity;
910  break;
911  case XKB_KEY_z:
912  ctx->attribute= Attribute_zorder;
913  break;
914  default:
915  case 'x':
916  break;
917  }
918  ctx->inputState= InputState_main;
919 }
920 
921 static void processInput( AppCtx *ctx, uint32_t sym )
922 {
923  switch( ctx->inputState )
924  {
925  case InputState_main:
926  processInputMain( ctx, sym );
927  break;
928  case InputState_attribute:
929  processInputAttribute( ctx, sym );
930  break;
931  }
932 }
933 
934 static void showUsage()
935 {
936  printf("usage:\n");
937  printf(" graphics_lifecycle [options]\n" );
938  printf("where [options] are:\n" );
939  printf(" --delay <delay> : render loop delay\n" );
940  printf(" --shell : use wl_simple_shell protocol\n" );
941  printf(" --display <name> : wayland display to connect to\n" );
942  printf(" --noframe : don't pace rendering with frame requests\n" );
943  printf(" --noanimate : don't use animation\n" );
944  printf(" -? : show usage\n" );
945  printf("\n" );
946 }
947 
948 static void redraw( void *data, struct wl_callback *callback, uint32_t time )
949 {
950  AppCtx *ctx= (AppCtx*)data;
951 
952  if ( g_log ) printf("redraw: time %u\n", time);
953  wl_callback_destroy( callback );
954 
955  ctx->needRedraw= true;
956 }
957 
958 static struct wl_callback_listener frameListener=
959 {
960  redraw
961 };
962 
963 static void drawFrame( AppCtx *ctx )
964 {
965  if ( ctx->surfaceDX || ctx->surfaceDY || ctx->surfaceDWidth || ctx->surfaceDHeight )
966  {
967  ctx->surfaceX += ctx->surfaceDX;
968  ctx->surfaceY += ctx->surfaceDY;
969  ctx->surfaceWidth += ctx->surfaceDWidth;
970  ctx->surfaceHeight += ctx->surfaceDHeight;
971 
972  wl_simple_shell_set_geometry( ctx->shell, ctx->surfaceIdCurrent,
973  ctx->surfaceX, ctx->surfaceY, ctx->surfaceWidth, ctx->surfaceHeight );
974  }
975 
976  renderGL(ctx);
977 
978  ctx->frameCallback= wl_surface_frame( ctx->surface );
979  wl_callback_add_listener( ctx->frameCallback, &frameListener, ctx );
980 
981  eglSwapBuffers(ctx->eglDisplay, ctx->eglSurfaceWindow);
982 }
983 
984 int initGraphics(const char* display_name, bool paceRendering, AppCtx *ctx)
985 {
986  if ( display_name )
987  {
988  printf("calling wl_display_connect for display name %s\n", display_name);
989  }
990  else
991  {
992  printf("calling wl_display_connect for default display\n");
993  }
994  ctx->display= wl_display_connect(display_name);
995  printf("wl_display_connect: display=%p\n", ctx->display);
996  if ( !ctx->display )
997  {
998  printf("error: unable to connect to primary display\n");
999  return -1;
1000  }
1001 
1002  printf("calling wl_display_get_registry\n");
1003  ctx->registry= wl_display_get_registry(ctx->display);
1004  printf("wl_display_get_registry: registry=%p\n", ctx->registry);
1005  if ( !ctx->registry )
1006  {
1007  printf("error: unable to get display registry\n");
1008  return -2;
1009  }
1010 
1011  ctx->planeX= 0;
1012  ctx->planeY= 0;
1013  ctx->planeWidth= 1280;
1014  ctx->planeHeight= 720;
1015  wl_registry_add_listener(ctx->registry, &registryListener, ctx);
1016 
1017  wl_display_roundtrip(ctx->display);
1018 
1019  setupEGL(ctx);
1020 
1021  ctx->surfaceWidth= 1280;
1022  ctx->surfaceHeight= 720;
1023  ctx->surfaceX= 0;
1024  ctx->surfaceY= 0;
1025 
1026  createSurface(ctx);
1027 
1028  setupGL(ctx);
1029 
1030  if ( paceRendering )
1031  {
1032  drawFrame(ctx);
1033  }
1034 
1035  return 0;
1036 }
1037 
1038 void destroyGraphics(AppCtx* ctx)
1039 {
1040  if ( ctx->compositor )
1041  {
1042  wl_compositor_destroy( ctx->compositor );
1043  ctx->compositor= 0;
1044  }
1045 
1046  if ( ctx->shell )
1047  {
1048  wl_simple_shell_destroy( ctx->shell );
1049  ctx->shell= 0;
1050  }
1051 
1052  termEGL(ctx);
1053 
1054  if ( ctx->xkbState )
1055  {
1056  xkb_state_unref( ctx->xkbState );
1057  ctx->xkbState= 0;
1058  }
1059 
1060  if ( ctx->xkbKeymap )
1061  {
1062  xkb_keymap_unref( ctx->xkbKeymap );
1063  ctx->xkbKeymap= 0;
1064  }
1065 
1066  if ( ctx->xkbCtx )
1067  {
1068  xkb_context_unref( ctx->xkbCtx );
1069  ctx->xkbCtx= 0;
1070  }
1071 
1072  if ( ctx->pointer )
1073  {
1074  wl_pointer_destroy(ctx->pointer);
1075  ctx->pointer= 0;
1076  }
1077 
1078  if ( ctx->keyboard )
1079  {
1080  wl_keyboard_destroy(ctx->keyboard);
1081  ctx->keyboard= 0;
1082  }
1083 
1084  if ( ctx->seat )
1085  {
1086  wl_seat_destroy(ctx->seat);
1087  ctx->seat= 0;
1088  }
1089 
1090  if ( ctx->output )
1091  {
1092  wl_output_destroy(ctx->output);
1093  ctx->output= 0;
1094  }
1095 
1096  if ( ctx->registry )
1097  {
1098  wl_registry_destroy(ctx->registry);
1099  ctx->registry= 0;
1100  }
1101 
1102  if ( ctx->display )
1103  {
1104  wl_display_disconnect(ctx->display);
1105  ctx->display= 0;
1106  }
1107 }
1108 
1109 void runGraphicsIteration(AppCtx* ctx, bool paceRendering, int delay)
1110 {
1111  if ( wl_display_dispatch( ctx->display ) == -1 )
1112  {
1113  return;
1114  }
1115 
1116  if ( !paceRendering )
1117  {
1118  if ( delay > 0 )
1119  {
1120  usleep(delay);
1121  }
1122  renderGL(ctx);
1123  eglSwapBuffers(ctx->eglDisplay, ctx->eglSurfaceWindow);
1124  }
1125  else if ( ctx->needRedraw )
1126  {
1127  ctx->needRedraw= false;
1128  drawFrame(ctx);
1129  }
1130 
1131  if ( ctx->getShell )
1132  {
1133  if ( isKeyHit() )
1134  {
1135  uint32_t sym= XKB_KEY_NoSymbol;
1136  int c= fgetc(stdin);
1137  switch( c )
1138  {
1139  case 0x1B:
1140  c= fgetc(stdin);
1141  if ( c == 0x5B )
1142  {
1143  c= fgetc(stdin);
1144  switch( c )
1145  {
1146  case 0x41: //UP
1147  sym= XKB_KEY_Up;
1148  break;
1149  case 0x42: //DOWN
1150  sym= XKB_KEY_Down;
1151  break;
1152  case 0x43: //RIGHT
1153  sym= XKB_KEY_Right;
1154  break;
1155  case 0x44: // LEFT
1156  sym= XKB_KEY_Left;
1157  break;
1158  }
1159  }
1160  break;
1161  default:
1162  sym= c;
1163  break;
1164  }
1165  processInput(ctx, sym);
1166 
1167  // Prevent keys from building up while held down
1168  tcflush(STDIN_FILENO,TCIFLUSH);
1169  }
1170  else
1171  {
1172  if ( ctx->surfaceDX || ctx->surfaceDY || ctx->surfaceDWidth || ctx->surfaceDHeight )
1173  {
1174  // Key has been released - reset deltas
1175  ctx->surfaceDX= ctx->surfaceDY= ctx->surfaceDWidth= ctx->surfaceDHeight= 0;
1176  }
1177  }
1178  }
1179 }
1180 
1181 
1182 //callbacks from the life cycle object
1183 void onSuspend()
1184 {
1185  pthread_mutex_lock(&g_mutex);
1186  g_requestMode = AppMode_Suspended;
1187  pthread_mutex_unlock(&g_mutex);
1188 }
1189 
1190 void onResume(const char * p)
1191 {
1192  pthread_mutex_lock(&g_mutex);
1193  g_requestMode = AppMode_Running;
1194  pthread_cond_signal(&g_cond);
1195  pthread_mutex_unlock(&g_mutex);
1196 }
1197 
1198 bool initRt()
1199 {
1200  rtError rc;
1201  sRtUtils = new RtUtils();
1202  rc = sRtUtils->initRt();
1203 
1204  if(rc != RT_OK)
1205  return false;
1206 
1207  const char* objectName = getenv("PX_WAYLAND_CLIENT_REMOTE_OBJECT_NAME");
1208  if (!objectName) objectName = "GRAPHICS_LIFECYLE_RT";
1209  printf("Register RT object: %s\n", objectName);
1210 
1211  sLifeCycle = new GraphicsLifeCycle();
1212  sLifeCycle->setRtUtils(sRtUtils);
1213  rc = rtRemoteRegisterObject(objectName, sLifeCycle);
1214 
1215  if(rc != RT_OK)
1216  {
1217  printf("Failed to register Graphics LifeCycle client to rt!\n");
1218  return false;
1219  }
1220 
1221  static GraphicsLifeCycle::Callbacks cb = {
1222  onResume, onSuspend
1223  };
1224  sLifeCycle->setCallbacks(cb);
1225 
1226  return true;
1227 }
1228 
1229 void destroyRt()
1230 {
1231  printf("before Graphics LifeCycle destruction\n"); fflush(stdout);
1232  //delete sLifeCycle; // handled by rt now that this object is registered
1233  sLifeCycle = NULL;
1234  printf("after Graphics LifeCycle destruction\n"); fflush(stdout);
1235 
1236  printf("before rt utils destruction\n"); fflush(stdout);
1237  if(sRtUtils) delete sRtUtils;
1238  sRtUtils = NULL;
1239  printf("after rt utils destruction\n"); fflush(stdout);
1240 }
1241 
1242 void processLifeCycleChange(const char* display_name, bool paceRendering, AppCtx *ctx)
1243 {
1244  pthread_mutex_lock(&g_mutex);
1245 
1246  //handle suspend transition
1247  if(g_requestMode == AppMode_Suspended)
1248  {
1249  //if a suspend is requested destroy all graphics connections
1250  //and go into a waiting state
1251  printf("Graphics App is going into a suspend state\n");
1252  destroyGraphics(ctx);
1253  ctx->appMode = g_requestMode;
1254  pthread_cond_wait(&g_cond, &g_mutex);
1255  }
1256 
1257  //handle resume transition
1258  if(g_requestMode == AppMode_Running && ctx->appMode != g_requestMode)
1259  {
1260  printf("Graphics App is going into a resume state\n");
1261  initGraphics(display_name, paceRendering, ctx);
1262  ctx->appMode = g_requestMode;
1263  }
1264 
1265  pthread_mutex_unlock(&g_mutex);
1266 }
1267 
1268 
1269 #define NUM_EVENTS (20)
1270 int main( int argc, char** argv)
1271 {
1272  int nRC= 0;
1273  AppCtx ctx;
1274  struct sigaction sigint;
1275  int delay= 16667;
1276  const char *display_name= 0;
1277  bool paceRendering= true;
1278  EGLBoolean swapok;
1279  int loopCnt=0;
1280 
1281  printf("graphics_lifecycle: v1.0\n" );
1282 
1283  memset( &ctx, 0, sizeof(AppCtx) );
1284  ctx.verboseLog = true;
1285 
1286  pthread_cond_init(&g_cond,NULL);
1287  pthread_mutex_init(&g_mutex,NULL);
1288 
1289  initRt();
1290 
1291  for( int i= 1; i < argc; ++i )
1292  {
1293  if ( !strcmp( (const char*)argv[i], "--delay") )
1294  {
1295  printf("got delay: i %d argc %d\n", i, argc );
1296  if ( i+1 < argc )
1297  {
1298  int v= atoi(argv[++i]);
1299  printf("v=%d\n", v);
1300  if ( v > 0 )
1301  {
1302  delay= v;
1303  printf("using delay=%d\n", delay );
1304  }
1305  }
1306  }
1307  else if (!strcmp( (const char*)argv[i], "--shell" ) )
1308  {
1309  ctx.getShell= true;
1310  }
1311  else if ( !strcmp( (const char*)argv[i], "--display") )
1312  {
1313  if ( i+1 < argc )
1314  {
1315  ++i;
1316  display_name= argv[i];
1317  }
1318  }
1319  else if (!strcmp( (const char*)argv[i], "--noframe" ) )
1320  {
1321  paceRendering= false;
1322  }
1323  else if (!strcmp( (const char*)argv[i], "--log" ) )
1324  {
1325  g_log= true;
1326  }
1327  else if (!strcmp( (const char*)argv[i], "--noanimate" ) )
1328  {
1329  ctx.noAnimation= true;
1330  }
1331  else if ( !strcmp( (const char*)argv[i], "-?" ) )
1332  {
1333  showUsage();
1334  goto exit;
1335  }
1336  }
1337 
1338  ctx.startTime= currentTimeMillis();
1339 
1340  sigint.sa_handler = signalHandler;
1341  sigemptyset(&sigint.sa_mask);
1342  sigint.sa_flags = SA_RESETHAND;
1343  sigaction(SIGINT, &sigint, NULL);
1344 
1345  setBlockingMode(NON_BLOCKING_ENABLED);
1346 
1347  ctx.inputState= InputState_main;
1348  ctx.attribute= Attribute_position;
1349 
1350  nRC = initGraphics(display_name, paceRendering, &ctx);
1351  if(nRC < 0)
1352  goto exit;
1353 
1354  g_running= 1;
1355  while( g_running )
1356  {
1357  runGraphicsIteration(&ctx, paceRendering, delay);
1358  processLifeCycleChange(display_name, paceRendering, &ctx);
1359  }
1360 
1361 exit:
1362 
1363  printf("graphics_lifecycle: exiting...\n");
1364 
1365  setBlockingMode(NON_BLOCKING_DISABLED);
1366  if(ctx.appMode != AppMode_Suspended)
1367  {
1368  printf("Destroying graphics on exit because not suspended!\n");
1369  destroyGraphics(&ctx);
1370  }
1371  destroyRt();
1372 
1373  printf("graphics_lifecycle: exit\n");
1374 
1375  return nRC;
1376 }
1377 
1378 #define RED_SIZE (8)
1379 #define GREEN_SIZE (8)
1380 #define BLUE_SIZE (8)
1381 #define ALPHA_SIZE (8)
1382 #define DEPTH_SIZE (0)
1383 
1384 static bool setupEGL( AppCtx *ctx )
1385 {
1386  bool result= false;
1387  EGLint major, minor;
1388  EGLBoolean b;
1389  EGLint configCount;
1390  EGLConfig *eglConfigs= 0;
1391  EGLint attr[32];
1392  EGLint redSize, greenSize, blueSize, alphaSize, depthSize;
1393  EGLint ctxAttrib[3];
1394  int i;
1395 
1396  /*
1397  * Get default EGL display
1398  */
1399  ctx->eglDisplay = eglGetDisplay((NativeDisplayType)ctx->display);
1400  printf("eglDisplay=%p\n", ctx->eglDisplay );
1401  if ( ctx->eglDisplay == EGL_NO_DISPLAY )
1402  {
1403  printf("error: EGL not available\n" );
1404  goto exit;
1405  }
1406 
1407  /*
1408  * Initialize display
1409  */
1410  b= eglInitialize( ctx->eglDisplay, &major, &minor );
1411  if ( !b )
1412  {
1413  printf("error: unable to initialize EGL display\n" );
1414  goto exit;
1415  }
1416  printf("eglInitiialize: major: %d minor: %d\n", major, minor );
1417 
1418  /*
1419  * Get number of available configurations
1420  */
1421  b= eglGetConfigs( ctx->eglDisplay, NULL, 0, &configCount );
1422  if ( !b )
1423  {
1424  printf("error: unable to get count of EGL configurations: %X\n", eglGetError() );
1425  goto exit;
1426  }
1427  printf("Number of EGL configurations: %d\n", configCount );
1428 
1429  eglConfigs= (EGLConfig*)malloc( configCount*sizeof(EGLConfig) );
1430  if ( !eglConfigs )
1431  {
1432  printf("error: unable to alloc memory for EGL configurations\n");
1433  goto exit;
1434  }
1435 
1436  i= 0;
1437  attr[i++]= EGL_RED_SIZE;
1438  attr[i++]= RED_SIZE;
1439  attr[i++]= EGL_GREEN_SIZE;
1440  attr[i++]= GREEN_SIZE;
1441  attr[i++]= EGL_BLUE_SIZE;
1442  attr[i++]= BLUE_SIZE;
1443  attr[i++]= EGL_DEPTH_SIZE;
1444  attr[i++]= DEPTH_SIZE;
1445  attr[i++]= EGL_STENCIL_SIZE;
1446  attr[i++]= 0;
1447  attr[i++]= EGL_SURFACE_TYPE;
1448  attr[i++]= EGL_WINDOW_BIT;
1449  attr[i++]= EGL_RENDERABLE_TYPE;
1450  attr[i++]= EGL_OPENGL_ES2_BIT;
1451  attr[i++]= EGL_NONE;
1452 
1453  /*
1454  * Get a list of configurations that meet or exceed our requirements
1455  */
1456  b= eglChooseConfig( ctx->eglDisplay, attr, eglConfigs, configCount, &configCount );
1457  if ( !b )
1458  {
1459  printf("error: eglChooseConfig failed: %X\n", eglGetError() );
1460  goto exit;
1461  }
1462  printf("eglChooseConfig: matching configurations: %d\n", configCount );
1463 
1464  /*
1465  * Choose a suitable configuration
1466  */
1467  for( i= 0; i < configCount; ++i )
1468  {
1469  eglGetConfigAttrib( ctx->eglDisplay, eglConfigs[i], EGL_RED_SIZE, &redSize );
1470  eglGetConfigAttrib( ctx->eglDisplay, eglConfigs[i], EGL_GREEN_SIZE, &greenSize );
1471  eglGetConfigAttrib( ctx->eglDisplay, eglConfigs[i], EGL_BLUE_SIZE, &blueSize );
1472  eglGetConfigAttrib( ctx->eglDisplay, eglConfigs[i], EGL_ALPHA_SIZE, &alphaSize );
1473  eglGetConfigAttrib( ctx->eglDisplay, eglConfigs[i], EGL_DEPTH_SIZE, &depthSize );
1474 
1475  printf("config %d: red: %d green: %d blue: %d alpha: %d depth: %d\n",
1476  i, redSize, greenSize, blueSize, alphaSize, depthSize );
1477  if ( (redSize == RED_SIZE) &&
1478  (greenSize == GREEN_SIZE) &&
1479  (blueSize == BLUE_SIZE) &&
1480  (alphaSize == ALPHA_SIZE) &&
1481  (depthSize >= DEPTH_SIZE) )
1482  {
1483  printf( "choosing config %d\n", i);
1484  break;
1485  }
1486  }
1487  if ( i == configCount )
1488  {
1489  printf("error: no suitable configuration available\n");
1490  goto exit;
1491  }
1492  ctx->eglConfig= eglConfigs[i];
1493 
1494  ctxAttrib[0]= EGL_CONTEXT_CLIENT_VERSION;
1495  ctxAttrib[1]= 2; // ES2
1496  ctxAttrib[2]= EGL_NONE;
1497 
1498  /*
1499  * Create an EGL context
1500  */
1501  ctx->eglContext= eglCreateContext( ctx->eglDisplay, ctx->eglConfig, EGL_NO_CONTEXT, ctxAttrib );
1502  if ( ctx->eglContext == EGL_NO_CONTEXT )
1503  {
1504  printf( "eglCreateContext failed: %X\n", eglGetError() );
1505  goto exit;
1506  }
1507  printf("eglCreateContext: eglContext %p\n", ctx->eglContext );
1508 
1509  result= true;
1510 
1511 exit:
1512 
1513  if ( eglConfigs )
1514  {
1515  free( eglConfigs );
1516  eglConfigs= 0;
1517  }
1518 
1519  return result;
1520 }
1521 
1522 static void termEGL( AppCtx *ctx )
1523 {
1524  if ( ctx->display )
1525  {
1526  eglMakeCurrent( ctx->eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );
1527 
1528  destroySurface( ctx );
1529 
1530  eglTerminate( ctx->eglDisplay );
1531  eglReleaseThread();
1532  }
1533 }
1534 
1535 static bool createSurface( AppCtx *ctx )
1536 {
1537  bool result= false;
1538  EGLBoolean b;
1539 
1540  ctx->surface= wl_compositor_create_surface(ctx->compositor);
1541  printf("surface=%p\n", ctx->surface);
1542  if ( !ctx->surface )
1543  {
1544  printf("error: unable to create wayland surface\n");
1545  goto exit;
1546  }
1547 
1548  ctx->native= wl_egl_window_create(ctx->surface, ctx->planeWidth, ctx->planeHeight);
1549  if ( !ctx->native )
1550  {
1551  printf("error: unable to create wl_egl_window\n");
1552  goto exit;
1553  }
1554  printf("wl_egl_window %p\n", ctx->native);
1555 
1556  /*
1557  * Create a window surface
1558  */
1559  ctx->eglSurfaceWindow= eglCreateWindowSurface( ctx->eglDisplay,
1560  ctx->eglConfig,
1561  (EGLNativeWindowType)ctx->native,
1562  NULL );
1563  if ( ctx->eglSurfaceWindow == EGL_NO_SURFACE )
1564  {
1565  printf("eglCreateWindowSurface: A: error %X\n", eglGetError() );
1566  ctx->eglSurfaceWindow= eglCreateWindowSurface( ctx->eglDisplay,
1567  ctx->eglConfig,
1568  (EGLNativeWindowType)NULL,
1569  NULL );
1570  if ( ctx->eglSurfaceWindow == EGL_NO_SURFACE )
1571  {
1572  printf("eglCreateWindowSurface: B: error %X\n", eglGetError() );
1573  goto exit;
1574  }
1575  }
1576  printf("eglCreateWindowSurface: eglSurfaceWindow %p\n", ctx->eglSurfaceWindow );
1577 
1578  /*
1579  * Establish EGL context for this thread
1580  */
1581  b= eglMakeCurrent( ctx->eglDisplay, ctx->eglSurfaceWindow, ctx->eglSurfaceWindow, ctx->eglContext );
1582  if ( !b )
1583  {
1584  printf("error: eglMakeCurrent failed: %X\n", eglGetError() );
1585  goto exit;
1586  }
1587 
1588  eglSwapInterval( ctx->eglDisplay, 1 );
1589 
1590 exit:
1591 
1592  return result;
1593 }
1594 
1595 static void destroySurface( AppCtx *ctx )
1596 {
1597  if ( ctx->eglSurfaceWindow )
1598  {
1599  eglDestroySurface( ctx->eglDisplay, ctx->eglSurfaceWindow );
1600 
1601  wl_egl_window_destroy( ctx->native );
1602  }
1603  eglDestroyContext(ctx->eglDisplay, ctx->eglContext);
1604  if ( ctx->surface )
1605  {
1606  wl_surface_destroy( ctx->surface );
1607  ctx->surface= 0;
1608  }
1609 }
1610 
1611 static void resizeSurface( AppCtx *ctx, int dx, int dy, int width, int height )
1612 {
1613  wl_egl_window_resize( ctx->native, width, height, dx, dy );
1614 }
1615 
1616 static const char *vert_shader_text =
1617  "uniform mat4 rotation;\n"
1618  "attribute vec4 pos;\n"
1619  "attribute vec4 color;\n"
1620  "varying vec4 v_color;\n"
1621  "void main() {\n"
1622  " gl_Position = rotation * pos;\n"
1623  " v_color = color;\n"
1624  "}\n";
1625 
1626 static const char *frag_shader_text =
1627  "precision mediump float;\n"
1628  "varying vec4 v_color;\n"
1629  "void main() {\n"
1630  " gl_FragColor = v_color;\n"
1631  "}\n";
1632 
1633 static GLuint createShader(AppCtx *ctx, GLenum shaderType, const char *shaderSource )
1634 {
1635  GLuint shader= 0;
1636  GLint shaderStatus;
1637  GLsizei length;
1638  char logText[1000];
1639 
1640  shader= glCreateShader( shaderType );
1641  if ( shader )
1642  {
1643  glShaderSource( shader, 1, (const char **)&shaderSource, NULL );
1644  glCompileShader( shader );
1645  glGetShaderiv( shader, GL_COMPILE_STATUS, &shaderStatus );
1646  if ( !shaderStatus )
1647  {
1648  glGetShaderInfoLog( shader, sizeof(logText), &length, logText );
1649  printf("Error compiling %s shader: %*s\n",
1650  ((shaderType == GL_VERTEX_SHADER) ? "vertex" : "fragment"),
1651  length,
1652  logText );
1653  }
1654  }
1655 
1656  return shader;
1657 }
1658 
1659 static bool setupGL( AppCtx *ctx )
1660 {
1661  bool result= false;
1662  GLuint frag, vert;
1663  GLuint program;
1664  GLint status;
1665 
1666  frag= createShader(ctx, GL_FRAGMENT_SHADER, frag_shader_text);
1667  vert= createShader(ctx, GL_VERTEX_SHADER, vert_shader_text);
1668 
1669  program= glCreateProgram();
1670  glAttachShader(program, frag);
1671  glAttachShader(program, vert);
1672  glLinkProgram(program);
1673 
1674  glGetProgramiv(program, GL_LINK_STATUS, &status);
1675  if (!status)
1676  {
1677  char log[1000];
1678  GLsizei len;
1679  glGetProgramInfoLog(program, 1000, &len, log);
1680  fprintf(stderr, "Error: linking:\n%*s\n", len, log);
1681  goto exit;
1682  }
1683 
1684  glUseProgram(program);
1685 
1686  ctx->gl.pos= 0;
1687  ctx->gl.col= 1;
1688 
1689  glBindAttribLocation(program, ctx->gl.pos, "pos");
1690  glBindAttribLocation(program, ctx->gl.col, "color");
1691  glLinkProgram(program);
1692 
1693  ctx->gl.rotation_uniform= glGetUniformLocation(program, "rotation");
1694 
1695 exit:
1696  return result;
1697 }
1698 
1699 static bool renderGL( AppCtx *ctx )
1700 {
1701  static const GLfloat verts[3][2] = {
1702  { -0.5, -0.5 },
1703  { 0.5, -0.5 },
1704  { 0, 0.5 }
1705  };
1706  static const GLfloat colors[3][4] = {
1707  { 1, 0, 0, 1.0 },
1708  { 0, 1, 0, 1.0 },
1709  { 0, 0, 1, 1.0 }
1710  };
1711  GLfloat angle;
1712  GLfloat rotation[4][4] = {
1713  { 1, 0, 0, 0 },
1714  { 0, 1, 0, 0 },
1715  { 0, 0, 1, 0 },
1716  { 0, 0, 0, 1 }
1717  };
1718  static const uint32_t speed_div = 5;
1719  EGLint rect[4];
1720 
1721  glViewport( 0, 0, ctx->planeWidth, ctx->planeHeight );
1722  glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
1723  glClear(GL_COLOR_BUFFER_BIT);
1724 
1725  ctx->currTime= currentTimeMillis();
1726 
1727  angle = ctx->noAnimation ? 0.0 : ((ctx->currTime-ctx->startTime) / speed_div) % 360 * M_PI / 180.0;
1728  rotation[0][0] = cos(angle);
1729  rotation[0][2] = sin(angle);
1730  rotation[2][0] = -sin(angle);
1731  rotation[2][2] = cos(angle);
1732 
1733  glUniformMatrix4fv(ctx->gl.rotation_uniform, 1, GL_FALSE, (GLfloat *) rotation);
1734 
1735  glVertexAttribPointer(ctx->gl.pos, 2, GL_FLOAT, GL_FALSE, 0, verts);
1736  glVertexAttribPointer(ctx->gl.col, 4, GL_FLOAT, GL_FALSE, 0, colors);
1737  glEnableVertexAttribArray(ctx->gl.pos);
1738  glEnableVertexAttribArray(ctx->gl.col);
1739 
1740  glDrawArrays(GL_TRIANGLES, 0, 3);
1741 
1742  glDisableVertexAttribArray(ctx->gl.pos);
1743  glDisableVertexAttribArray(ctx->gl.col);
1744 
1745  GLenum err= glGetError();
1746  if ( err != GL_NO_ERROR )
1747  {
1748  printf( "renderGL: glGetError() = %X\n", err );
1749  }
1750 }
1751 
RtUtils
Definition: RtUtils.h:27
GraphicsLifeCycle::Callbacks
Definition: LifeCycle.h:117
GraphicsLifeCycle::setRtUtils
void setRtUtils(RtUtils *rtUtils)
This initializes the rt object, sets the event listeners and also set the remote ready flag.
Definition: LifeCycle.cpp:37
GraphicsLifeCycle
Definition: LifeCycle.h:81
GraphicsLifeCycle::setCallbacks
void setCallbacks(const Callbacks &cb)
Definition: LifeCycle.cpp:42
_AppCtx
Definition: rne-triangle.cpp:136