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.

245 lines
7.5KB

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