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.6KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE 6 technical preview.
  4. Copyright (c) 2020 - Raw Material Software Limited
  5. You may use this code under the terms of the GPL v3
  6. (see www.gnu.org/licenses).
  7. For this technical preview, this file is not subject to commercial licensing.
  8. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  9. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  10. DISCLAIMED.
  11. ==============================================================================
  12. */
  13. @interface JuceGLView : UIView
  14. {
  15. }
  16. + (Class) layerClass;
  17. @end
  18. @implementation JuceGLView
  19. + (Class) layerClass
  20. {
  21. return [CAEAGLLayer class];
  22. }
  23. @end
  24. extern "C" GLvoid glResolveMultisampleFramebufferAPPLE();
  25. namespace juce
  26. {
  27. class OpenGLContext::NativeContext
  28. {
  29. public:
  30. NativeContext (Component& c,
  31. const OpenGLPixelFormat& pixFormat,
  32. void* contextToShare,
  33. bool multisampling,
  34. OpenGLVersion version)
  35. : component (c), openGLversion (version),
  36. useDepthBuffer (pixFormat.depthBufferBits > 0),
  37. useMSAA (multisampling)
  38. {
  39. JUCE_AUTORELEASEPOOL
  40. {
  41. if (auto* peer = component.getPeer())
  42. {
  43. auto bounds = peer->getAreaCoveredBy (component);
  44. view = [[JuceGLView alloc] initWithFrame: convertToCGRect (bounds)];
  45. view.opaque = YES;
  46. view.hidden = NO;
  47. view.backgroundColor = [UIColor blackColor];
  48. view.userInteractionEnabled = NO;
  49. glLayer = (CAEAGLLayer*) [view layer];
  50. glLayer.opaque = true;
  51. updateWindowPosition (bounds);
  52. [((UIView*) peer->getNativeHandle()) addSubview: view];
  53. if (version == openGL3_2 && [[UIDevice currentDevice].systemVersion floatValue] >= 7.0)
  54. {
  55. if (! createContext (kEAGLRenderingAPIOpenGLES3, contextToShare))
  56. {
  57. releaseContext();
  58. createContext (kEAGLRenderingAPIOpenGLES2, contextToShare);
  59. }
  60. }
  61. else
  62. {
  63. createContext (kEAGLRenderingAPIOpenGLES2, contextToShare);
  64. }
  65. if (context != nil)
  66. {
  67. // I'd prefer to put this stuff in the initialiseOnRenderThread() call, but doing
  68. // so causes mysterious timing-related failures.
  69. [EAGLContext setCurrentContext: context];
  70. createGLBuffers();
  71. deactivateCurrentContext();
  72. }
  73. else
  74. {
  75. jassertfalse;
  76. }
  77. }
  78. else
  79. {
  80. jassertfalse;
  81. }
  82. }
  83. }
  84. ~NativeContext()
  85. {
  86. releaseContext();
  87. [view removeFromSuperview];
  88. [view release];
  89. }
  90. bool initialiseOnRenderThread (OpenGLContext&) { return true; }
  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 (openGLversion >= openGL3_2)
  123. {
  124. glBlitFramebuffer (0, 0, lastBounds.getWidth(), lastBounds.getHeight(),
  125. 0, 0, lastBounds.getWidth(), lastBounds.getHeight(),
  126. GL_COLOR_BUFFER_BIT, GL_NEAREST);
  127. }
  128. else
  129. {
  130. glResolveMultisampleFramebufferAPPLE();
  131. }
  132. }
  133. glBindRenderbuffer (GL_RENDERBUFFER, colorBufferHandle);
  134. [context presentRenderbuffer: GL_RENDERBUFFER];
  135. if (needToRebuildBuffers)
  136. {
  137. needToRebuildBuffers = false;
  138. freeGLBuffers();
  139. createGLBuffers();
  140. makeActive();
  141. }
  142. }
  143. void updateWindowPosition (Rectangle<int> bounds)
  144. {
  145. view.frame = convertToCGRect (bounds);
  146. glLayer.contentsScale = (CGFloat) (Desktop::getInstance().getDisplays().getMainDisplay().scale
  147. / component.getDesktopScaleFactor());
  148. if (lastBounds != bounds)
  149. {
  150. lastBounds = bounds;
  151. needToRebuildBuffers = true;
  152. }
  153. }
  154. bool setSwapInterval (int numFramesPerSwap) noexcept
  155. {
  156. swapFrames = numFramesPerSwap;
  157. return false;
  158. }
  159. int getSwapInterval() const noexcept { return swapFrames; }
  160. struct Locker { Locker (NativeContext&) {} };
  161. private:
  162. Component& component;
  163. JuceGLView* view = nil;
  164. CAEAGLLayer* glLayer = nil;
  165. EAGLContext* context = nil;
  166. const OpenGLVersion openGLversion;
  167. const bool useDepthBuffer, useMSAA;
  168. GLuint frameBufferHandle = 0, colorBufferHandle = 0, depthBufferHandle = 0,
  169. msaaColorHandle = 0, msaaBufferHandle = 0;
  170. Rectangle<int> lastBounds;
  171. int swapFrames = 0;
  172. bool needToRebuildBuffers = false;
  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); ignoreUnused (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. }
  242. } // namespace juce