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.

386 lines
16KB

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