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.

283 lines
9.2KB

  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), frameBufferHandle (0), colorBufferHandle (0),
  40. depthBufferHandle (0), msaaColorHandle (0), msaaBufferHandle (0),
  41. lastWidth (0), lastHeight (0), needToRebuildBuffers (false),
  42. swapFrames (0), useDepthBuffer (pixFormat.depthBufferBits > 0),
  43. useMSAA (multisampling)
  44. {
  45. JUCE_AUTORELEASEPOOL
  46. {
  47. ComponentPeer* const peer = component.getPeer();
  48. jassert (peer != nullptr);
  49. const Rectangle<int> bounds (peer->getComponent().getLocalArea (&component, component.getLocalBounds()));
  50. lastWidth = bounds.getWidth();
  51. lastHeight = bounds.getHeight();
  52. view = [[JuceGLView alloc] initWithFrame: convertToCGRect (bounds)];
  53. view.opaque = YES;
  54. view.hidden = NO;
  55. view.backgroundColor = [UIColor blackColor];
  56. view.userInteractionEnabled = NO;
  57. glLayer = (CAEAGLLayer*) [view layer];
  58. glLayer.contentsScale = Desktop::getInstance().getDisplays().getMainDisplay().scale;
  59. glLayer.opaque = true;
  60. [((UIView*) peer->getNativeHandle()) addSubview: view];
  61. #if defined (__IPHONE_7_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_7_0
  62. if (version == OpenGLContext::openGL3_2 && [[UIDevice currentDevice].systemVersion floatValue] >= 7.0)
  63. {
  64. if (! createContext (kEAGLRenderingAPIOpenGLES3, contextToShare))
  65. {
  66. releaseContext();
  67. createContext (kEAGLRenderingAPIOpenGLES2, contextToShare);
  68. }
  69. }
  70. else
  71. #endif
  72. {
  73. createContext (kEAGLRenderingAPIOpenGLES2, contextToShare);
  74. }
  75. jassert (context != nil);
  76. // I'd prefer to put this stuff in the initialiseOnRenderThread() call, but doing
  77. // so causes myserious timing-related failures.
  78. [EAGLContext setCurrentContext: context];
  79. createGLBuffers();
  80. deactivateCurrentContext();
  81. }
  82. }
  83. ~NativeContext()
  84. {
  85. releaseContext();
  86. [view removeFromSuperview];
  87. [view release];
  88. }
  89. void initialiseOnRenderThread (OpenGLContext&) {}
  90. void shutdownOnRenderThread()
  91. {
  92. JUCE_CHECK_OPENGL_ERROR
  93. freeGLBuffers();
  94. deactivateCurrentContext();
  95. }
  96. bool createdOk() const noexcept { return getRawContext() != nullptr; }
  97. void* getRawContext() const noexcept { return context; }
  98. GLuint getFrameBufferID() const noexcept { return frameBufferHandle; }
  99. bool makeActive() const noexcept
  100. {
  101. if (! [EAGLContext setCurrentContext: context])
  102. return false;
  103. glBindFramebuffer (GL_FRAMEBUFFER, useMSAA ? msaaBufferHandle
  104. : frameBufferHandle);
  105. return true;
  106. }
  107. bool isActive() const noexcept
  108. {
  109. return [EAGLContext currentContext] == context;
  110. }
  111. static void deactivateCurrentContext()
  112. {
  113. [EAGLContext setCurrentContext: nil];
  114. }
  115. void swapBuffers()
  116. {
  117. glBindRenderbuffer (GL_RENDERBUFFER, colorBufferHandle);
  118. [context presentRenderbuffer: GL_RENDERBUFFER];
  119. if (needToRebuildBuffers)
  120. {
  121. needToRebuildBuffers = false;
  122. freeGLBuffers();
  123. createGLBuffers();
  124. makeActive();
  125. }
  126. }
  127. void updateWindowPosition (const Rectangle<int>& bounds)
  128. {
  129. view.frame = convertToCGRect (bounds);
  130. if (lastWidth != bounds.getWidth() || lastHeight != bounds.getHeight())
  131. {
  132. lastWidth = bounds.getWidth();
  133. lastHeight = bounds.getHeight();
  134. needToRebuildBuffers = true;
  135. }
  136. }
  137. bool setSwapInterval (const int numFramesPerSwap) noexcept
  138. {
  139. swapFrames = numFramesPerSwap;
  140. return false;
  141. }
  142. int getSwapInterval() const noexcept { return swapFrames; }
  143. struct Locker { Locker (NativeContext&) {} };
  144. private:
  145. JuceGLView* view;
  146. CAEAGLLayer* glLayer;
  147. EAGLContext* context;
  148. GLuint frameBufferHandle, colorBufferHandle, depthBufferHandle,
  149. msaaColorHandle, msaaBufferHandle;
  150. int volatile lastWidth, lastHeight;
  151. bool volatile needToRebuildBuffers;
  152. int swapFrames;
  153. bool useDepthBuffer, useMSAA;
  154. bool createContext (NSUInteger type, void* contextToShare)
  155. {
  156. jassert (context == nil);
  157. context = [EAGLContext alloc];
  158. context = contextToShare != nullptr
  159. ? [context initWithAPI: type sharegroup: [(EAGLContext*) contextToShare sharegroup]]
  160. : [context initWithAPI: type];
  161. return context != nil;
  162. }
  163. void releaseContext()
  164. {
  165. [context release];
  166. context = nil;
  167. }
  168. //==============================================================================
  169. void createGLBuffers()
  170. {
  171. glGenFramebuffers (1, &frameBufferHandle);
  172. glGenRenderbuffers (1, &colorBufferHandle);
  173. glBindFramebuffer (GL_FRAMEBUFFER, frameBufferHandle);
  174. glBindRenderbuffer (GL_RENDERBUFFER, colorBufferHandle);
  175. glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorBufferHandle);
  176. bool ok = [context renderbufferStorage: GL_RENDERBUFFER fromDrawable: glLayer];
  177. jassert (ok); (void) ok;
  178. GLint width, height;
  179. glGetRenderbufferParameteriv (GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &width);
  180. glGetRenderbufferParameteriv (GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &height);
  181. if (useMSAA)
  182. {
  183. glGenFramebuffers (1, &msaaBufferHandle);
  184. glGenRenderbuffers (1, &msaaColorHandle);
  185. glBindFramebuffer (GL_FRAMEBUFFER, msaaBufferHandle);
  186. glBindRenderbuffer (GL_RENDERBUFFER, msaaColorHandle);
  187. glRenderbufferStorageMultisampleAPPLE (GL_RENDERBUFFER, 4, GL_RGBA8_OES, width, height);
  188. glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, msaaColorHandle);
  189. }
  190. if (useDepthBuffer)
  191. {
  192. glGenRenderbuffers (1, &depthBufferHandle);
  193. glBindRenderbuffer (GL_RENDERBUFFER, depthBufferHandle);
  194. if (useMSAA)
  195. glRenderbufferStorageMultisampleAPPLE (GL_RENDERBUFFER, 4, GL_DEPTH_COMPONENT16, width, height);
  196. else
  197. glRenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height);
  198. glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthBufferHandle);
  199. }
  200. jassert (glCheckFramebufferStatus (GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
  201. JUCE_CHECK_OPENGL_ERROR
  202. }
  203. void freeGLBuffers()
  204. {
  205. JUCE_CHECK_OPENGL_ERROR
  206. [context renderbufferStorage: GL_RENDERBUFFER fromDrawable: nil];
  207. deleteFrameBuffer (frameBufferHandle);
  208. deleteFrameBuffer (msaaBufferHandle);
  209. deleteRenderBuffer (colorBufferHandle);
  210. deleteRenderBuffer (depthBufferHandle);
  211. deleteRenderBuffer (msaaColorHandle);
  212. JUCE_CHECK_OPENGL_ERROR
  213. }
  214. static void deleteFrameBuffer (GLuint& i) { if (i != 0) glDeleteFramebuffers (1, &i); i = 0; }
  215. static void deleteRenderBuffer (GLuint& i) { if (i != 0) glDeleteRenderbuffers (1, &i); i = 0; }
  216. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NativeContext)
  217. };
  218. //==============================================================================
  219. bool OpenGLHelpers::isContextActive()
  220. {
  221. return [EAGLContext currentContext] != nil;
  222. }