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.

309 lines
9.7KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE 7 technical preview.
  4. Copyright (c) 2022 - 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 the technical preview this file cannot be licensed commercially.
  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. gl::loadFunctions();
  71. createGLBuffers();
  72. deactivateCurrentContext();
  73. }
  74. else
  75. {
  76. jassertfalse;
  77. }
  78. }
  79. else
  80. {
  81. jassertfalse;
  82. }
  83. }
  84. }
  85. ~NativeContext()
  86. {
  87. releaseContext();
  88. [view removeFromSuperview];
  89. [view release];
  90. }
  91. bool initialiseOnRenderThread (OpenGLContext&) { return true; }
  92. void shutdownOnRenderThread()
  93. {
  94. JUCE_CHECK_OPENGL_ERROR
  95. freeGLBuffers();
  96. deactivateCurrentContext();
  97. }
  98. bool createdOk() const noexcept { return getRawContext() != nullptr; }
  99. void* getRawContext() const noexcept { return context; }
  100. GLuint getFrameBufferID() const noexcept { return useMSAA ? msaaBufferHandle : frameBufferHandle; }
  101. bool makeActive() const noexcept
  102. {
  103. if (! [EAGLContext setCurrentContext: context])
  104. return false;
  105. glBindFramebuffer (GL_FRAMEBUFFER, useMSAA ? msaaBufferHandle
  106. : frameBufferHandle);
  107. return true;
  108. }
  109. bool isActive() const noexcept
  110. {
  111. return [EAGLContext currentContext] == context;
  112. }
  113. static void deactivateCurrentContext()
  114. {
  115. [EAGLContext setCurrentContext: nil];
  116. }
  117. void swapBuffers()
  118. {
  119. if (useMSAA)
  120. {
  121. glBindFramebuffer (GL_DRAW_FRAMEBUFFER, frameBufferHandle);
  122. glBindFramebuffer (GL_READ_FRAMEBUFFER, msaaBufferHandle);
  123. if (openGLversion >= openGL3_2)
  124. {
  125. auto w = roundToInt (lastBounds.getWidth() * glLayer.contentsScale);
  126. auto h = roundToInt (lastBounds.getHeight() * glLayer.contentsScale);
  127. glBlitFramebuffer (0, 0, w, h,
  128. 0, 0, w, h,
  129. GL_COLOR_BUFFER_BIT,
  130. GL_NEAREST);
  131. }
  132. else
  133. {
  134. ::glResolveMultisampleFramebufferAPPLE();
  135. }
  136. }
  137. glBindRenderbuffer (GL_RENDERBUFFER, colorBufferHandle);
  138. [context presentRenderbuffer: GL_RENDERBUFFER];
  139. if (needToRebuildBuffers)
  140. {
  141. needToRebuildBuffers = false;
  142. freeGLBuffers();
  143. createGLBuffers();
  144. makeActive();
  145. }
  146. }
  147. void updateWindowPosition (Rectangle<int> bounds)
  148. {
  149. view.frame = convertToCGRect (bounds);
  150. glLayer.contentsScale = (CGFloat) (Desktop::getInstance().getDisplays().getPrimaryDisplay()->scale
  151. / component.getDesktopScaleFactor());
  152. if (lastBounds != bounds)
  153. {
  154. lastBounds = bounds;
  155. needToRebuildBuffers = true;
  156. }
  157. }
  158. bool setSwapInterval (int numFramesPerSwap) noexcept
  159. {
  160. swapFrames = numFramesPerSwap;
  161. return false;
  162. }
  163. int getSwapInterval() const noexcept { return swapFrames; }
  164. struct Locker { Locker (NativeContext&) {} };
  165. private:
  166. Component& component;
  167. JuceGLView* view = nil;
  168. CAEAGLLayer* glLayer = nil;
  169. EAGLContext* context = nil;
  170. const OpenGLVersion openGLversion;
  171. const bool useDepthBuffer, useMSAA;
  172. GLuint frameBufferHandle = 0, colorBufferHandle = 0, depthBufferHandle = 0,
  173. msaaColorHandle = 0, msaaBufferHandle = 0;
  174. Rectangle<int> lastBounds;
  175. int swapFrames = 0;
  176. bool needToRebuildBuffers = false;
  177. bool createContext (EAGLRenderingAPI type, void* contextToShare)
  178. {
  179. jassert (context == nil);
  180. context = [EAGLContext alloc];
  181. context = contextToShare != nullptr
  182. ? [context initWithAPI: type sharegroup: [(EAGLContext*) contextToShare sharegroup]]
  183. : [context initWithAPI: type];
  184. return context != nil;
  185. }
  186. void releaseContext()
  187. {
  188. [context release];
  189. context = nil;
  190. }
  191. //==============================================================================
  192. void createGLBuffers()
  193. {
  194. glGenFramebuffers (1, &frameBufferHandle);
  195. glGenRenderbuffers (1, &colorBufferHandle);
  196. glBindFramebuffer (GL_FRAMEBUFFER, frameBufferHandle);
  197. glBindRenderbuffer (GL_RENDERBUFFER, colorBufferHandle);
  198. glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorBufferHandle);
  199. bool ok = [context renderbufferStorage: GL_RENDERBUFFER fromDrawable: glLayer];
  200. jassert (ok); ignoreUnused (ok);
  201. GLint width, height;
  202. glGetRenderbufferParameteriv (GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &width);
  203. glGetRenderbufferParameteriv (GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &height);
  204. if (useMSAA)
  205. {
  206. glGenFramebuffers (1, &msaaBufferHandle);
  207. glGenRenderbuffers (1, &msaaColorHandle);
  208. glBindFramebuffer (GL_FRAMEBUFFER, msaaBufferHandle);
  209. glBindRenderbuffer (GL_RENDERBUFFER, msaaColorHandle);
  210. glRenderbufferStorageMultisample (GL_RENDERBUFFER, 4, GL_RGBA8, width, height);
  211. glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, msaaColorHandle);
  212. }
  213. if (useDepthBuffer)
  214. {
  215. glGenRenderbuffers (1, &depthBufferHandle);
  216. glBindRenderbuffer (GL_RENDERBUFFER, depthBufferHandle);
  217. if (useMSAA)
  218. glRenderbufferStorageMultisample (GL_RENDERBUFFER, 4, GL_DEPTH_COMPONENT16, width, height);
  219. else
  220. glRenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height);
  221. glFramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthBufferHandle);
  222. }
  223. jassert (glCheckFramebufferStatus (GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
  224. JUCE_CHECK_OPENGL_ERROR
  225. }
  226. void freeGLBuffers()
  227. {
  228. JUCE_CHECK_OPENGL_ERROR
  229. [context renderbufferStorage: GL_RENDERBUFFER fromDrawable: nil];
  230. deleteFrameBuffer (frameBufferHandle);
  231. deleteFrameBuffer (msaaBufferHandle);
  232. deleteRenderBuffer (colorBufferHandle);
  233. deleteRenderBuffer (depthBufferHandle);
  234. deleteRenderBuffer (msaaColorHandle);
  235. JUCE_CHECK_OPENGL_ERROR
  236. }
  237. static void deleteFrameBuffer (GLuint& i) { if (i != 0) glDeleteFramebuffers (1, &i); i = 0; }
  238. static void deleteRenderBuffer (GLuint& i) { if (i != 0) glDeleteRenderbuffers (1, &i); i = 0; }
  239. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NativeContext)
  240. };
  241. //==============================================================================
  242. bool OpenGLHelpers::isContextActive()
  243. {
  244. return [EAGLContext currentContext] != nil;
  245. }
  246. } // namespace juce