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.

312 lines
9.8KB

  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. } // (juce namespace)
  20. @interface JuceGLView : UIView
  21. {
  22. }
  23. + (Class) layerClass;
  24. @end
  25. @implementation JuceGLView
  26. + (Class) layerClass
  27. {
  28. return [CAEAGLLayer class];
  29. }
  30. @end
  31. extern "C" GLvoid glResolveMultisampleFramebufferAPPLE();
  32. namespace juce
  33. {
  34. class OpenGLContext::NativeContext
  35. {
  36. public:
  37. NativeContext (Component& c,
  38. const OpenGLPixelFormat& pixFormat,
  39. void* contextToShare,
  40. bool multisampling,
  41. OpenGLVersion version)
  42. : component (c), openGLversion (version),
  43. useDepthBuffer (pixFormat.depthBufferBits > 0),
  44. useMSAA (multisampling)
  45. {
  46. JUCE_AUTORELEASEPOOL
  47. {
  48. if (auto* peer = component.getPeer())
  49. {
  50. auto bounds = peer->getAreaCoveredBy (component);
  51. view = [[JuceGLView alloc] initWithFrame: convertToCGRect (bounds)];
  52. view.opaque = YES;
  53. view.hidden = NO;
  54. view.backgroundColor = [UIColor blackColor];
  55. view.userInteractionEnabled = NO;
  56. glLayer = (CAEAGLLayer*) [view layer];
  57. glLayer.opaque = true;
  58. updateWindowPosition (bounds);
  59. [((UIView*) peer->getNativeHandle()) addSubview: view];
  60. if (version == openGL3_2 && [[UIDevice currentDevice].systemVersion floatValue] >= 7.0)
  61. {
  62. if (! createContext (kEAGLRenderingAPIOpenGLES3, contextToShare))
  63. {
  64. releaseContext();
  65. createContext (kEAGLRenderingAPIOpenGLES2, contextToShare);
  66. }
  67. }
  68. else
  69. {
  70. createContext (kEAGLRenderingAPIOpenGLES2, contextToShare);
  71. }
  72. if (context != nil)
  73. {
  74. // I'd prefer to put this stuff in the initialiseOnRenderThread() call, but doing
  75. // so causes myserious timing-related failures.
  76. [EAGLContext setCurrentContext: context];
  77. createGLBuffers();
  78. deactivateCurrentContext();
  79. }
  80. else
  81. {
  82. jassertfalse;
  83. }
  84. }
  85. else
  86. {
  87. jassertfalse;
  88. }
  89. }
  90. }
  91. ~NativeContext()
  92. {
  93. releaseContext();
  94. [view removeFromSuperview];
  95. [view release];
  96. }
  97. void initialiseOnRenderThread (OpenGLContext&) {}
  98. void shutdownOnRenderThread()
  99. {
  100. JUCE_CHECK_OPENGL_ERROR
  101. freeGLBuffers();
  102. deactivateCurrentContext();
  103. }
  104. bool createdOk() const noexcept { return getRawContext() != nullptr; }
  105. void* getRawContext() const noexcept { return context; }
  106. GLuint getFrameBufferID() const noexcept { return useMSAA ? msaaBufferHandle : frameBufferHandle; }
  107. bool makeActive() const noexcept
  108. {
  109. if (! [EAGLContext setCurrentContext: context])
  110. return false;
  111. glBindFramebuffer (GL_FRAMEBUFFER, useMSAA ? msaaBufferHandle
  112. : frameBufferHandle);
  113. return true;
  114. }
  115. bool isActive() const noexcept
  116. {
  117. return [EAGLContext currentContext] == context;
  118. }
  119. static void deactivateCurrentContext()
  120. {
  121. [EAGLContext setCurrentContext: nil];
  122. }
  123. void swapBuffers()
  124. {
  125. if (useMSAA)
  126. {
  127. glBindFramebuffer (GL_DRAW_FRAMEBUFFER, frameBufferHandle);
  128. glBindFramebuffer (GL_READ_FRAMEBUFFER, msaaBufferHandle);
  129. if (openGLversion >= openGL3_2)
  130. {
  131. glBlitFramebuffer (0, 0, lastBounds.getWidth(), lastBounds.getHeight(),
  132. 0, 0, lastBounds.getWidth(), lastBounds.getHeight(),
  133. GL_COLOR_BUFFER_BIT, GL_NEAREST);
  134. }
  135. else
  136. {
  137. glResolveMultisampleFramebufferAPPLE();
  138. }
  139. }
  140. glBindRenderbuffer (GL_RENDERBUFFER, colorBufferHandle);
  141. [context presentRenderbuffer: GL_RENDERBUFFER];
  142. if (needToRebuildBuffers)
  143. {
  144. needToRebuildBuffers = false;
  145. freeGLBuffers();
  146. createGLBuffers();
  147. makeActive();
  148. }
  149. }
  150. void updateWindowPosition (Rectangle<int> bounds)
  151. {
  152. view.frame = convertToCGRect (bounds);
  153. glLayer.contentsScale = (CGFloat) (Desktop::getInstance().getDisplays().getMainDisplay().scale
  154. / component.getDesktopScaleFactor());
  155. if (lastBounds != bounds)
  156. {
  157. lastBounds = bounds;
  158. needToRebuildBuffers = true;
  159. }
  160. }
  161. bool setSwapInterval (int numFramesPerSwap) noexcept
  162. {
  163. swapFrames = numFramesPerSwap;
  164. return false;
  165. }
  166. int getSwapInterval() const noexcept { return swapFrames; }
  167. struct Locker { Locker (NativeContext&) {} };
  168. private:
  169. Component& component;
  170. JuceGLView* view = nil;
  171. CAEAGLLayer* glLayer = nil;
  172. EAGLContext* context = nil;
  173. const OpenGLVersion openGLversion;
  174. const bool useDepthBuffer, useMSAA;
  175. GLuint frameBufferHandle = 0, colorBufferHandle = 0, depthBufferHandle = 0,
  176. msaaColorHandle = 0, msaaBufferHandle = 0;
  177. Rectangle<int> lastBounds;
  178. int swapFrames = 0;
  179. bool needToRebuildBuffers = false;
  180. bool createContext (EAGLRenderingAPI type, void* contextToShare)
  181. {
  182. jassert (context == nil);
  183. context = [EAGLContext alloc];
  184. context = contextToShare != nullptr
  185. ? [context initWithAPI: type sharegroup: [(EAGLContext*) contextToShare sharegroup]]
  186. : [context initWithAPI: type];
  187. return context != nil;
  188. }
  189. void releaseContext()
  190. {
  191. [context release];
  192. context = nil;
  193. }
  194. //==============================================================================
  195. void createGLBuffers()
  196. {
  197. glGenFramebuffers (1, &frameBufferHandle);
  198. glGenRenderbuffers (1, &colorBufferHandle);
  199. glBindFramebuffer (GL_FRAMEBUFFER, frameBufferHandle);
  200. glBindRenderbuffer (GL_RENDERBUFFER, colorBufferHandle);
  201. glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorBufferHandle);
  202. bool ok = [context renderbufferStorage: GL_RENDERBUFFER fromDrawable: glLayer];
  203. jassert (ok); ignoreUnused (ok);
  204. GLint width, height;
  205. glGetRenderbufferParameteriv (GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &width);
  206. glGetRenderbufferParameteriv (GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &height);
  207. if (useMSAA)
  208. {
  209. glGenFramebuffers (1, &msaaBufferHandle);
  210. glGenRenderbuffers (1, &msaaColorHandle);
  211. glBindFramebuffer (GL_FRAMEBUFFER, msaaBufferHandle);
  212. glBindRenderbuffer (GL_RENDERBUFFER, msaaColorHandle);
  213. glRenderbufferStorageMultisample (GL_RENDERBUFFER, 4, GL_RGBA8, width, height);
  214. glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, msaaColorHandle);
  215. }
  216. if (useDepthBuffer)
  217. {
  218. glGenRenderbuffers (1, &depthBufferHandle);
  219. glBindRenderbuffer (GL_RENDERBUFFER, depthBufferHandle);
  220. if (useMSAA)
  221. glRenderbufferStorageMultisample (GL_RENDERBUFFER, 4, GL_DEPTH_COMPONENT16, width, height);
  222. else
  223. glRenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height);
  224. glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthBufferHandle);
  225. }
  226. jassert (glCheckFramebufferStatus (GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
  227. JUCE_CHECK_OPENGL_ERROR
  228. }
  229. void freeGLBuffers()
  230. {
  231. JUCE_CHECK_OPENGL_ERROR
  232. [context renderbufferStorage: GL_RENDERBUFFER fromDrawable: nil];
  233. deleteFrameBuffer (frameBufferHandle);
  234. deleteFrameBuffer (msaaBufferHandle);
  235. deleteRenderBuffer (colorBufferHandle);
  236. deleteRenderBuffer (depthBufferHandle);
  237. deleteRenderBuffer (msaaColorHandle);
  238. JUCE_CHECK_OPENGL_ERROR
  239. }
  240. static void deleteFrameBuffer (GLuint& i) { if (i != 0) glDeleteFramebuffers (1, &i); i = 0; }
  241. static void deleteRenderBuffer (GLuint& i) { if (i != 0) glDeleteRenderbuffers (1, &i); i = 0; }
  242. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NativeContext)
  243. };
  244. //==============================================================================
  245. bool OpenGLHelpers::isContextActive()
  246. {
  247. return [EAGLContext currentContext] != nil;
  248. }