NativeWindowAndroid.cpp 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. // Copyright (C) 2009-2021, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. #include <AnKi/Core/NativeWindowAndroid.h>
  6. #include <AnKi/Core/App.h>
  7. #include <AnKi/Util/Logger.h>
  8. #include <AnKi/Util/Array.h>
  9. #include <AnKi/Util/StdTypes.h>
  10. #include <AnKi/Core/Counters.h>
  11. namespace anki
  12. {
  13. static void loopUntilWindowIsReady(android_app& app)
  14. {
  15. while(app.window == nullptr)
  16. {
  17. int ident;
  18. int events;
  19. android_poll_source* source;
  20. const U timeoutMs = 5;
  21. while((ident = ALooper_pollAll(timeoutMs, NULL, &events, (void**)&source)) >= 0)
  22. {
  23. if(source != NULL)
  24. {
  25. source->process(&app, source);
  26. }
  27. }
  28. }
  29. }
  30. void NativeWindowImpl::create(NativeWindowInitInfo& init)
  31. {
  32. Array<EGLint, 256> attribs;
  33. U attr = 0;
  34. EGLint configsCount;
  35. EGLint format;
  36. EGLConfig config;
  37. ANKI_CORE_LOGI("Creating native window");
  38. ANKI_ASSERT(gAndroidApp);
  39. android_app& andApp = *gAndroidApp;
  40. loopUntilWindowIsReady(andApp);
  41. // EGL init
  42. //
  43. display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
  44. if(display == EGL_NO_DISPLAY)
  45. {
  46. throw ANKI_EXCEPTION("Failed to create display");
  47. }
  48. int major, minor;
  49. if(eglInitialize(display, &major, &minor) == EGL_FALSE)
  50. {
  51. throw ANKI_EXCEPTION("Failed to initialize EGL");
  52. }
  53. //
  54. // EGL config
  55. //
  56. attribs[attr++] = EGL_SURFACE_TYPE;
  57. attribs[attr++] = EGL_WINDOW_BIT;
  58. attribs[attr++] = EGL_RENDERABLE_TYPE;
  59. attribs[attr++] = EGL_OPENGL_ES2_BIT;
  60. if(init.samplesCount > 1)
  61. {
  62. attribs[attr++] = EGL_SAMPLES;
  63. attribs[attr++] = init.samplesCount;
  64. }
  65. attribs[attr++] = EGL_RED_SIZE;
  66. attribs[attr++] = init.rgbaBits[0];
  67. attribs[attr++] = EGL_GREEN_SIZE;
  68. attribs[attr++] = init.rgbaBits[1];
  69. attribs[attr++] = EGL_BLUE_SIZE;
  70. attribs[attr++] = init.rgbaBits[2];
  71. attribs[attr++] = EGL_ALPHA_SIZE;
  72. attribs[attr++] = init.rgbaBits[3];
  73. attribs[attr++] = EGL_DEPTH_SIZE;
  74. attribs[attr++] = init.depthBits;
  75. attribs[attr++] = EGL_STENCIL_SIZE;
  76. attribs[attr++] = init.stencilBits;
  77. attribs[attr++] = EGL_NONE;
  78. if(eglChooseConfig(display, &attribs[0], &config, 1, &configsCount) == EGL_FALSE)
  79. {
  80. throw ANKI_EXCEPTION("Failed to query required EGL configs");
  81. }
  82. if(configsCount == 0)
  83. {
  84. throw ANKI_EXCEPTION("No matching EGL configs found");
  85. }
  86. eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format);
  87. ANKI_ASSERT(andApp.window);
  88. ANativeWindow_setBuffersGeometry(andApp.window, 0, 0, format);
  89. // Surface
  90. //
  91. surface = eglCreateWindowSurface(display, config, andApp.window, NULL);
  92. if(surface == EGL_NO_SURFACE)
  93. {
  94. throw ANKI_EXCEPTION("Cannot create surface");
  95. }
  96. // Context
  97. //
  98. EGLint ctxAttribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
  99. context = eglCreateContext(display, config, EGL_NO_CONTEXT, ctxAttribs);
  100. if(context == EGL_NO_CONTEXT)
  101. {
  102. throw ANKI_EXCEPTION("Cannot create context");
  103. }
  104. if(eglMakeCurrent(display, surface, surface, context) == EGL_FALSE)
  105. {
  106. throw ANKI_EXCEPTION("Cannot make the context current");
  107. }
  108. // Query width and height
  109. //
  110. EGLint w, h;
  111. eglQuerySurface(display, surface, EGL_WIDTH, &w);
  112. eglQuerySurface(display, surface, EGL_HEIGHT, &h);
  113. init.width = w;
  114. init.height = h;
  115. }
  116. void NativeWindowImpl::destroy()
  117. {
  118. if(display != EGL_NO_DISPLAY)
  119. {
  120. eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
  121. if(context != EGL_NO_CONTEXT)
  122. {
  123. eglDestroyContext(display, context);
  124. }
  125. if(surface != EGL_NO_SURFACE)
  126. {
  127. eglDestroySurface(display, surface);
  128. }
  129. eglTerminate(display);
  130. }
  131. }
  132. NativeWindow::~NativeWindow()
  133. {
  134. }
  135. void NativeWindow::init(NativeWindowInitInfo& initializer)
  136. {
  137. impl.reset(new NativeWindowImpl);
  138. impl->create(initializer);
  139. // Set the size after because the create may have changed it to something
  140. // more nice
  141. width = initializer.width;
  142. height = initializer.height;
  143. }
  144. void NativeWindow::destroy()
  145. {
  146. impl.reset();
  147. }
  148. void NativeWindow::swapBuffers()
  149. {
  150. ANKI_COUNTER_START_TIMER(SWAP_BUFFERS_TIME);
  151. ANKI_ASSERT(isCreated());
  152. if(eglSwapBuffers(impl->display, impl->surface) == EGL_FALSE)
  153. {
  154. throw ANKI_EXCEPTION("eglSwapBuffers() failed");
  155. }
  156. ANKI_COUNTER_STOP_TIMER_INC(SWAP_BUFFERS_TIME);
  157. }
  158. } // end namespace anki