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