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.

304 lines
9.9KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2013 - Raw Material Software Ltd.
  5. Permission is granted to use this software under the terms of either:
  6. a) the GPL v2 (or any later version)
  7. b) the Affero GPL v3
  8. Details of these licenses can be found at: www.gnu.org/licenses
  9. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  11. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  12. ------------------------------------------------------------------------------
  13. To release a closed-source product which uses JUCE, commercial licenses are
  14. available: visit www.juce.com for more information.
  15. ==============================================================================
  16. */
  17. } // (juce namespace)
  18. @interface JuceGLView : UIView
  19. {
  20. }
  21. + (Class) layerClass;
  22. @end
  23. @implementation JuceGLView
  24. + (Class) layerClass
  25. {
  26. return [CAEAGLLayer class];
  27. }
  28. @end
  29. namespace juce
  30. {
  31. class OpenGLContext::NativeContext
  32. {
  33. public:
  34. NativeContext (Component& component,
  35. const OpenGLPixelFormat& pixFormat,
  36. void* contextToShare,
  37. bool multisampling,
  38. OpenGLVersion version)
  39. : context (nil), openGLversion (version),
  40. frameBufferHandle (0), colorBufferHandle (0),
  41. depthBufferHandle (0), msaaColorHandle (0), msaaBufferHandle (0),
  42. lastWidth (0), lastHeight (0), needToRebuildBuffers (false),
  43. swapFrames (0), useDepthBuffer (pixFormat.depthBufferBits > 0),
  44. useMSAA (multisampling)
  45. {
  46. JUCE_AUTORELEASEPOOL
  47. {
  48. ComponentPeer* const peer = component.getPeer();
  49. jassert (peer != nullptr);
  50. const Rectangle<int> bounds (peer->getComponent().getLocalArea (&component, component.getLocalBounds()));
  51. lastWidth = bounds.getWidth();
  52. lastHeight = bounds.getHeight();
  53. view = [[JuceGLView alloc] initWithFrame: convertToCGRect (bounds)];
  54. view.opaque = YES;
  55. view.hidden = NO;
  56. view.backgroundColor = [UIColor blackColor];
  57. view.userInteractionEnabled = NO;
  58. glLayer = (CAEAGLLayer*) [view layer];
  59. glLayer.contentsScale = (CGFloat) Desktop::getInstance().getDisplays().getMainDisplay().scale;
  60. glLayer.opaque = true;
  61. [((UIView*) peer->getNativeHandle()) addSubview: view];
  62. #if defined (__IPHONE_7_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_7_0
  63. if (version == openGL3_2 && [[UIDevice currentDevice].systemVersion floatValue] >= 7.0)
  64. {
  65. if (! createContext (kEAGLRenderingAPIOpenGLES3, contextToShare))
  66. {
  67. releaseContext();
  68. createContext (kEAGLRenderingAPIOpenGLES2, contextToShare);
  69. }
  70. }
  71. else
  72. #endif
  73. {
  74. createContext (kEAGLRenderingAPIOpenGLES2, contextToShare);
  75. }
  76. jassert (context != nil);
  77. // I'd prefer to put this stuff in the initialiseOnRenderThread() call, but doing
  78. // so causes myserious timing-related failures.
  79. [EAGLContext setCurrentContext: context];
  80. createGLBuffers();
  81. deactivateCurrentContext();
  82. }
  83. }
  84. ~NativeContext()
  85. {
  86. releaseContext();
  87. [view removeFromSuperview];
  88. [view release];
  89. }
  90. void initialiseOnRenderThread (OpenGLContext&) {}
  91. void shutdownOnRenderThread()
  92. {
  93. JUCE_CHECK_OPENGL_ERROR
  94. freeGLBuffers();
  95. deactivateCurrentContext();
  96. }
  97. bool createdOk() const noexcept { return getRawContext() != nullptr; }
  98. void* getRawContext() const noexcept { return context; }
  99. GLuint getFrameBufferID() const noexcept { return useMSAA ? msaaBufferHandle : frameBufferHandle; }
  100. bool makeActive() const noexcept
  101. {
  102. if (! [EAGLContext setCurrentContext: context])
  103. return false;
  104. glBindFramebuffer (GL_FRAMEBUFFER, useMSAA ? msaaBufferHandle
  105. : frameBufferHandle);
  106. return true;
  107. }
  108. bool isActive() const noexcept
  109. {
  110. return [EAGLContext currentContext] == context;
  111. }
  112. static void deactivateCurrentContext()
  113. {
  114. [EAGLContext setCurrentContext: nil];
  115. }
  116. void swapBuffers()
  117. {
  118. if (useMSAA)
  119. {
  120. glBindFramebuffer (GL_DRAW_FRAMEBUFFER, frameBufferHandle);
  121. glBindFramebuffer (GL_READ_FRAMEBUFFER, msaaBufferHandle);
  122. #if defined (__IPHONE_7_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_7_0
  123. if (openGLversion >= openGL3_2)
  124. {
  125. glBlitFramebuffer (0, 0, lastWidth, lastHeight, 0, 0, lastWidth, lastHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST);
  126. }
  127. else
  128. #endif
  129. {
  130. #ifdef GL_APPLE_framebuffer_multisample
  131. glResolveMultisampleFramebufferAPPLE();
  132. #endif
  133. }
  134. }
  135. glBindRenderbuffer (GL_RENDERBUFFER, colorBufferHandle);
  136. [context presentRenderbuffer: GL_RENDERBUFFER];
  137. if (needToRebuildBuffers)
  138. {
  139. needToRebuildBuffers = false;
  140. freeGLBuffers();
  141. createGLBuffers();
  142. makeActive();
  143. }
  144. }
  145. void updateWindowPosition (const Rectangle<int>& bounds)
  146. {
  147. view.frame = convertToCGRect (bounds);
  148. if (lastWidth != bounds.getWidth() || lastHeight != bounds.getHeight())
  149. {
  150. lastWidth = bounds.getWidth();
  151. lastHeight = bounds.getHeight();
  152. needToRebuildBuffers = true;
  153. }
  154. }
  155. bool setSwapInterval (const int numFramesPerSwap) noexcept
  156. {
  157. swapFrames = numFramesPerSwap;
  158. return false;
  159. }
  160. int getSwapInterval() const noexcept { return swapFrames; }
  161. struct Locker { Locker (NativeContext&) {} };
  162. private:
  163. JuceGLView* view;
  164. CAEAGLLayer* glLayer;
  165. EAGLContext* context;
  166. const OpenGLVersion openGLversion;
  167. GLuint frameBufferHandle, colorBufferHandle, depthBufferHandle,
  168. msaaColorHandle, msaaBufferHandle;
  169. int volatile lastWidth, lastHeight;
  170. bool volatile needToRebuildBuffers;
  171. int swapFrames;
  172. bool useDepthBuffer, useMSAA;
  173. bool createContext (EAGLRenderingAPI type, void* contextToShare)
  174. {
  175. jassert (context == nil);
  176. context = [EAGLContext alloc];
  177. context = contextToShare != nullptr
  178. ? [context initWithAPI: type sharegroup: [(EAGLContext*) contextToShare sharegroup]]
  179. : [context initWithAPI: type];
  180. return context != nil;
  181. }
  182. void releaseContext()
  183. {
  184. [context release];
  185. context = nil;
  186. }
  187. //==============================================================================
  188. void createGLBuffers()
  189. {
  190. glGenFramebuffers (1, &frameBufferHandle);
  191. glGenRenderbuffers (1, &colorBufferHandle);
  192. glBindFramebuffer (GL_FRAMEBUFFER, frameBufferHandle);
  193. glBindRenderbuffer (GL_RENDERBUFFER, colorBufferHandle);
  194. glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorBufferHandle);
  195. bool ok = [context renderbufferStorage: GL_RENDERBUFFER fromDrawable: glLayer];
  196. jassert (ok); (void) ok;
  197. GLint width, height;
  198. glGetRenderbufferParameteriv (GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &width);
  199. glGetRenderbufferParameteriv (GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &height);
  200. if (useMSAA)
  201. {
  202. glGenFramebuffers (1, &msaaBufferHandle);
  203. glGenRenderbuffers (1, &msaaColorHandle);
  204. glBindFramebuffer (GL_FRAMEBUFFER, msaaBufferHandle);
  205. glBindRenderbuffer (GL_RENDERBUFFER, msaaColorHandle);
  206. glRenderbufferStorageMultisample (GL_RENDERBUFFER, 4, GL_RGBA8, width, height);
  207. glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, msaaColorHandle);
  208. }
  209. if (useDepthBuffer)
  210. {
  211. glGenRenderbuffers (1, &depthBufferHandle);
  212. glBindRenderbuffer (GL_RENDERBUFFER, depthBufferHandle);
  213. if (useMSAA)
  214. glRenderbufferStorageMultisample (GL_RENDERBUFFER, 4, GL_DEPTH_COMPONENT16, width, height);
  215. else
  216. glRenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height);
  217. glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthBufferHandle);
  218. }
  219. jassert (glCheckFramebufferStatus (GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
  220. JUCE_CHECK_OPENGL_ERROR
  221. }
  222. void freeGLBuffers()
  223. {
  224. JUCE_CHECK_OPENGL_ERROR
  225. [context renderbufferStorage: GL_RENDERBUFFER fromDrawable: nil];
  226. deleteFrameBuffer (frameBufferHandle);
  227. deleteFrameBuffer (msaaBufferHandle);
  228. deleteRenderBuffer (colorBufferHandle);
  229. deleteRenderBuffer (depthBufferHandle);
  230. deleteRenderBuffer (msaaColorHandle);
  231. JUCE_CHECK_OPENGL_ERROR
  232. }
  233. static void deleteFrameBuffer (GLuint& i) { if (i != 0) glDeleteFramebuffers (1, &i); i = 0; }
  234. static void deleteRenderBuffer (GLuint& i) { if (i != 0) glDeleteRenderbuffers (1, &i); i = 0; }
  235. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NativeContext)
  236. };
  237. //==============================================================================
  238. bool OpenGLHelpers::isContextActive()
  239. {
  240. return [EAGLContext currentContext] != nil;
  241. }