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.

380 lines
15KB

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