The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

371 lines
15KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE 6 technical preview.
  4. Copyright (c) 2020 - Raw Material Software Limited
  5. You may use this code under the terms of the GPL v3
  6. (see www.gnu.org/licenses).
  7. For this technical preview, this file is not subject to commercial licensing.
  8. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  9. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  10. DISCLAIMED.
  11. ==============================================================================
  12. */
  13. namespace juce
  14. {
  15. //==============================================================================
  16. // This byte-code is generated from native/java/com/rmsl/juce/JuceOpenGLView.java with min sdk version 16
  17. // See juce_core/native/java/README.txt on how to generate this byte-code.
  18. static const uint8 javaJuceOpenGLView[] =
  19. {31,139,8,8,95,114,161,94,0,3,74,117,99,101,79,112,101,110,71,76,86,105,101,119,83,117,114,102,97,99,101,46,100,101,120,0,109,
  20. 84,75,107,19,81,20,62,119,230,38,169,105,76,99,218,138,86,144,32,5,55,173,83,53,98,33,173,86,90,170,196,193,34,173,81,106,93,
  21. 12,147,169,153,210,204,196,100,154,22,65,40,110,234,170,43,23,34,46,93,22,87,62,138,27,65,168,235,174,213,133,11,23,254,129,
  22. 162,136,130,223,125,196,164,208,129,239,126,231,125,206,188,78,217,91,75,142,156,191,64,151,223,190,187,182,183,251,251,212,240,
  23. 247,216,223,197,205,174,170,255,233,209,230,135,123,183,222,252,225,68,53,34,90,43,229,179,164,175,5,216,142,145,178,199,129,
  24. 93,205,63,0,6,140,224,72,129,71,153,210,159,225,152,50,137,182,193,239,13,162,143,192,14,240,25,216,3,50,240,13,1,54,48,3,204,
  25. 2,119,128,5,192,1,124,224,1,240,16,120,2,108,2,207,129,87,192,14,240,5,248,9,196,184,234,7,145,32,82,76,207,149,208,136,233,
  26. 249,187,180,252,20,189,15,105,249,5,228,164,150,95,66,238,214,242,86,135,253,181,161,234,102,100,15,83,214,50,225,233,209,61,179,
  27. 154,251,100,127,46,253,226,76,73,86,113,92,199,113,76,218,171,245,62,173,247,75,54,232,168,182,183,238,69,92,134,230,188,42,139,
  28. 251,226,210,214,205,213,124,181,28,209,57,153,57,15,105,126,144,40,141,92,38,99,251,185,154,191,229,77,203,124,67,246,56,129,
  29. 227,8,56,204,49,154,163,217,9,68,161,236,89,52,28,197,51,19,122,109,162,155,248,205,180,124,6,76,206,51,216,202,201,136,26,7,
  30. 230,140,116,17,103,157,57,67,58,231,224,232,36,162,67,124,6,92,206,198,246,221,179,33,117,166,245,182,28,31,243,3,63,186,68,172,
  31. 72,189,197,21,215,155,169,121,193,85,187,228,123,171,103,150,156,166,67,199,109,39,40,215,67,191,108,185,97,16,121,65,100,77,
  32. 10,94,139,10,29,174,251,117,167,86,241,221,134,53,233,4,77,167,81,160,129,255,174,38,42,89,179,43,245,69,199,245,68,213,2,157,
  33. 180,221,176,106,213,171,141,101,107,9,13,173,253,93,11,196,74,100,148,138,100,150,138,54,4,27,130,93,164,184,235,4,174,183,44,
  34. 25,29,40,225,170,41,40,85,246,27,53,39,114,43,83,117,103,149,120,37,108,68,148,12,156,200,111,122,115,21,191,65,217,48,184,18,
  35. 69,142,91,241,202,115,225,109,63,40,135,171,212,47,109,194,164,12,55,100,56,245,133,193,148,167,66,167,235,97,85,7,15,28,100,
  36. 213,25,41,248,208,86,107,60,18,13,79,27,61,217,68,250,226,204,48,13,83,34,125,157,166,89,58,145,30,223,152,167,60,41,30,7,111,
  37. 220,29,195,11,224,248,248,248,250,58,223,54,249,99,131,12,128,1,49,246,213,100,252,23,176,197,13,254,141,31,214,239,145,117,
  38. 112,107,111,24,29,187,195,236,216,31,173,239,94,236,144,24,181,247,72,156,218,187,132,229,148,79,236,19,150,105,255,203,70,78,
  39. 213,23,59,198,212,49,226,255,160,156,202,205,235,159,87,200,98,135,253,3,40,26,5,36,252,4,0,0,0,0};
  40. //==============================================================================
  41. struct AndroidGLCallbacks
  42. {
  43. static void attachedToWindow (JNIEnv*, jobject, jlong);
  44. static void detachedFromWindow (JNIEnv*, jobject, jlong);
  45. static void dispatchDraw (JNIEnv*, jobject, jlong, jobject);
  46. };
  47. //==============================================================================
  48. #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
  49. METHOD (constructor, "<init>", "(Landroid/content/Context;J)V") \
  50. METHOD (getParent, "getParent", "()Landroid/view/ViewParent;") \
  51. METHOD (getHolder, "getHolder", "()Landroid/view/SurfaceHolder;") \
  52. METHOD (layout, "layout", "(IIII)V" ) \
  53. CALLBACK (AndroidGLCallbacks::attachedToWindow, "onAttchedWindowNative", "(J)V") \
  54. CALLBACK (AndroidGLCallbacks::detachedFromWindow, "onDetachedFromWindowNative", "(J)V") \
  55. CALLBACK (AndroidGLCallbacks::dispatchDraw, "onDrawNative", "(JLandroid/graphics/Canvas;)V")
  56. DECLARE_JNI_CLASS_WITH_BYTECODE (JuceOpenGLViewSurface, "com/rmsl/juce/JuceOpenGLView", 16, javaJuceOpenGLView, sizeof(javaJuceOpenGLView))
  57. #undef JNI_CLASS_MEMBERS
  58. //==============================================================================
  59. class OpenGLContext::NativeContext : private SurfaceHolderCallback
  60. {
  61. public:
  62. NativeContext (Component& comp,
  63. const OpenGLPixelFormat& /*pixelFormat*/,
  64. void* /*contextToShareWith*/,
  65. bool /*useMultisampling*/,
  66. OpenGLVersion)
  67. : component (comp),
  68. surface (EGL_NO_SURFACE), context (EGL_NO_CONTEXT)
  69. {
  70. auto env = getEnv();
  71. // Do we have a native peer that we can attach to?
  72. if (component.getPeer()->getNativeHandle() == nullptr)
  73. return;
  74. // Initialise the EGL display
  75. if (! initEGLDisplay())
  76. return;
  77. // create a native surface view
  78. surfaceView = GlobalRef (LocalRef<jobject>(env->NewObject (JuceOpenGLViewSurface,
  79. JuceOpenGLViewSurface.constructor,
  80. getAppContext().get(),
  81. reinterpret_cast<jlong> (this))));
  82. if (surfaceView.get() == nullptr)
  83. return;
  84. // add the view to the view hierarchy
  85. // after this the nativecontext can receive callbacks
  86. env->CallVoidMethod ((jobject) component.getPeer()->getNativeHandle(),
  87. AndroidViewGroup.addView, surfaceView.get());
  88. // initialise the geometry of the view
  89. auto bounds = component.getTopLevelComponent()->getLocalArea (&component, component.getLocalBounds());
  90. bounds *= component.getDesktopScaleFactor();
  91. updateWindowPosition (bounds);
  92. hasInitialised = true;
  93. }
  94. ~NativeContext() override
  95. {
  96. auto env = getEnv();
  97. if (jobject viewParent = env->CallObjectMethod (surfaceView.get(), JuceOpenGLViewSurface.getParent))
  98. env->CallVoidMethod (viewParent, AndroidViewGroup.removeView, surfaceView.get());
  99. }
  100. //==============================================================================
  101. bool initialiseOnRenderThread (OpenGLContext& aContext)
  102. {
  103. jassert (hasInitialised);
  104. // has the context already attached?
  105. jassert (surface == EGL_NO_SURFACE && context == EGL_NO_CONTEXT);
  106. auto env = getEnv();
  107. ANativeWindow* window = nullptr;
  108. LocalRef<jobject> holder (env->CallObjectMethod (surfaceView.get(), JuceOpenGLViewSurface.getHolder));
  109. if (holder != nullptr)
  110. {
  111. LocalRef<jobject> jSurface (env->CallObjectMethod (holder.get(), AndroidSurfaceHolder.getSurface));
  112. if (jSurface != nullptr)
  113. {
  114. window = ANativeWindow_fromSurface(env, jSurface.get());
  115. // if we didn't succeed the first time, wait 25ms and try again
  116. if (window == nullptr)
  117. {
  118. Thread::sleep (200);
  119. window = ANativeWindow_fromSurface (env, jSurface.get());
  120. }
  121. }
  122. }
  123. if (window == nullptr)
  124. {
  125. // failed to get a pointer to the native window after second try so bail out
  126. jassertfalse;
  127. return false;
  128. }
  129. // create the surface
  130. surface = eglCreateWindowSurface (display, config, window, nullptr);
  131. jassert (surface != EGL_NO_SURFACE);
  132. ANativeWindow_release (window);
  133. // create the OpenGL context
  134. EGLint contextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
  135. context = eglCreateContext (display, config, EGL_NO_CONTEXT, contextAttribs);
  136. jassert (context != EGL_NO_CONTEXT);
  137. juceContext = &aContext;
  138. return true;
  139. }
  140. void shutdownOnRenderThread()
  141. {
  142. jassert (hasInitialised);
  143. // is there a context available to detach?
  144. jassert (surface != EGL_NO_SURFACE && context != EGL_NO_CONTEXT);
  145. eglDestroyContext (display, context);
  146. context = EGL_NO_CONTEXT;
  147. eglDestroySurface (display, surface);
  148. surface = EGL_NO_SURFACE;
  149. }
  150. //==============================================================================
  151. bool makeActive() const noexcept
  152. {
  153. if (! hasInitialised)
  154. return false;
  155. if (surface == EGL_NO_SURFACE || context == EGL_NO_CONTEXT)
  156. return false;
  157. if (! eglMakeCurrent (display, surface, surface, context))
  158. return false;
  159. return true;
  160. }
  161. bool isActive() const noexcept { return eglGetCurrentContext() == context; }
  162. static void deactivateCurrentContext()
  163. {
  164. eglMakeCurrent (display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
  165. }
  166. //==============================================================================
  167. void swapBuffers() const noexcept { eglSwapBuffers (display, surface); }
  168. bool setSwapInterval (const int) { return false; }
  169. int getSwapInterval() const { return 0; }
  170. //==============================================================================
  171. bool createdOk() const noexcept { return hasInitialised; }
  172. void* getRawContext() const noexcept { return surfaceView.get(); }
  173. GLuint getFrameBufferID() const noexcept { return 0; }
  174. //==============================================================================
  175. void updateWindowPosition (Rectangle<int> bounds)
  176. {
  177. if (lastBounds != bounds)
  178. {
  179. auto env = getEnv();
  180. lastBounds = bounds;
  181. auto r = bounds * Desktop::getInstance().getDisplays().getMainDisplay().scale;
  182. env->CallVoidMethod (surfaceView.get(), JuceOpenGLViewSurface.layout,
  183. (jint) r.getX(), (jint) r.getY(), (jint) r.getRight(), (jint) r.getBottom());
  184. }
  185. }
  186. //==============================================================================
  187. // Android Surface Callbacks:
  188. void surfaceChanged (LocalRef<jobject> holder, int format, int width, int height) override
  189. {
  190. ignoreUnused (holder, format, width, height);
  191. }
  192. void surfaceCreated (LocalRef<jobject> holder) override;
  193. void surfaceDestroyed (LocalRef<jobject> holder) override;
  194. //==============================================================================
  195. struct Locker { Locker (NativeContext&) {} };
  196. Component& component;
  197. private:
  198. //==============================================================================
  199. friend struct AndroidGLCallbacks;
  200. void attachedToWindow()
  201. {
  202. auto* env = getEnv();
  203. LocalRef<jobject> holder (env->CallObjectMethod (surfaceView.get(), JuceOpenGLViewSurface.getHolder));
  204. if (surfaceHolderCallback == nullptr)
  205. surfaceHolderCallback = GlobalRef (CreateJavaInterface (this, "android/view/SurfaceHolder$Callback"));
  206. env->CallVoidMethod (holder, AndroidSurfaceHolder.addCallback, surfaceHolderCallback.get());
  207. }
  208. void detachedFromWindow()
  209. {
  210. if (surfaceHolderCallback != nullptr)
  211. {
  212. auto* env = getEnv();
  213. LocalRef<jobject> holder (env->CallObjectMethod (surfaceView.get(), JuceOpenGLViewSurface.getHolder));
  214. env->CallVoidMethod (holder.get(), AndroidSurfaceHolder.removeCallback, surfaceHolderCallback.get());
  215. surfaceHolderCallback.clear();
  216. }
  217. }
  218. void dispatchDraw (jobject /*canvas*/)
  219. {
  220. if (juceContext != nullptr)
  221. juceContext->triggerRepaint();
  222. }
  223. //==============================================================================
  224. bool initEGLDisplay()
  225. {
  226. // already initialised?
  227. if (display != EGL_NO_DISPLAY)
  228. return true;
  229. const EGLint attribs[] =
  230. {
  231. EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
  232. EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
  233. EGL_BLUE_SIZE, 8,
  234. EGL_GREEN_SIZE, 8,
  235. EGL_RED_SIZE, 8,
  236. EGL_ALPHA_SIZE, 0,
  237. EGL_DEPTH_SIZE, 16,
  238. EGL_NONE
  239. };
  240. EGLint numConfigs;
  241. if ((display = eglGetDisplay (EGL_DEFAULT_DISPLAY)) == EGL_NO_DISPLAY)
  242. {
  243. jassertfalse;
  244. return false;
  245. }
  246. if (! eglInitialize (display, nullptr, nullptr))
  247. {
  248. jassertfalse;
  249. return false;
  250. }
  251. if (! eglChooseConfig (display, attribs, &config, 1, &numConfigs))
  252. {
  253. eglTerminate (display);
  254. jassertfalse;
  255. return false;
  256. }
  257. return true;
  258. }
  259. //==============================================================================
  260. bool hasInitialised = false;
  261. GlobalRef surfaceView;
  262. Rectangle<int> lastBounds;
  263. OpenGLContext* juceContext = nullptr;
  264. EGLSurface surface;
  265. EGLContext context;
  266. GlobalRef surfaceHolderCallback;
  267. static EGLDisplay display;
  268. static EGLConfig config;
  269. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NativeContext)
  270. };
  271. //==============================================================================
  272. void AndroidGLCallbacks::attachedToWindow (JNIEnv*, jobject /*this*/, jlong host)
  273. {
  274. if (auto* nativeContext = reinterpret_cast<OpenGLContext::NativeContext*> (host))
  275. nativeContext->attachedToWindow();
  276. }
  277. void AndroidGLCallbacks::detachedFromWindow (JNIEnv*, jobject /*this*/, jlong host)
  278. {
  279. if (auto* nativeContext = reinterpret_cast<OpenGLContext::NativeContext*> (host))
  280. nativeContext->detachedFromWindow();
  281. }
  282. void AndroidGLCallbacks::dispatchDraw (JNIEnv*, jobject /*this*/, jlong host, jobject canvas)
  283. {
  284. if (auto* nativeContext = reinterpret_cast<OpenGLContext::NativeContext*> (host))
  285. nativeContext->dispatchDraw (canvas);
  286. }
  287. //==============================================================================
  288. bool OpenGLHelpers::isContextActive()
  289. {
  290. return eglGetCurrentContext() != EGL_NO_CONTEXT;
  291. }
  292. } // namespace juce