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.

258 lines
8.4KB

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