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.

267 lines
9.9KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE 6 technical preview.
  4. Copyright (c) 2017 - ROLI Ltd.
  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. namespace juce
  14. {
  15. #if JUCE_CLANG && ! (defined (MAC_OS_X_VERSION_10_16) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_16)
  16. #pragma clang diagnostic push
  17. #pragma clang diagnostic ignored "-Wdeprecated-declarations"
  18. #define JUCE_DEPRECATION_IGNORED 1
  19. #endif
  20. class OpenGLContext::NativeContext
  21. {
  22. public:
  23. NativeContext (Component& component,
  24. const OpenGLPixelFormat& pixFormat,
  25. void* contextToShare,
  26. bool shouldUseMultisampling,
  27. OpenGLVersion version)
  28. {
  29. NSOpenGLPixelFormatAttribute attribs[64] = { 0 };
  30. createAttribs (attribs, version, pixFormat, shouldUseMultisampling);
  31. NSOpenGLPixelFormat* format = [[NSOpenGLPixelFormat alloc] initWithAttributes: attribs];
  32. static MouseForwardingNSOpenGLViewClass cls;
  33. view = [cls.createInstance() initWithFrame: NSMakeRect (0, 0, 100.0f, 100.0f)
  34. pixelFormat: format];
  35. if ([view respondsToSelector: @selector (setWantsBestResolutionOpenGLSurface:)])
  36. [view setWantsBestResolutionOpenGLSurface: YES];
  37. [[NSNotificationCenter defaultCenter] addObserver: view
  38. selector: @selector (_surfaceNeedsUpdate:)
  39. name: NSViewGlobalFrameDidChangeNotification
  40. object: view];
  41. renderContext = [[[NSOpenGLContext alloc] initWithFormat: format
  42. shareContext: (NSOpenGLContext*) contextToShare] autorelease];
  43. [view setOpenGLContext: renderContext];
  44. [format release];
  45. viewAttachment = NSViewComponent::attachViewToComponent (component, view);
  46. }
  47. ~NativeContext()
  48. {
  49. [[NSNotificationCenter defaultCenter] removeObserver: view];
  50. [renderContext clearDrawable];
  51. [renderContext setView: nil];
  52. [view setOpenGLContext: nil];
  53. [view release];
  54. }
  55. static void createAttribs (NSOpenGLPixelFormatAttribute* attribs, OpenGLVersion version,
  56. const OpenGLPixelFormat& pixFormat, bool shouldUseMultisampling)
  57. {
  58. ignoreUnused (version);
  59. int numAttribs = 0;
  60. #if JUCE_OPENGL3
  61. attribs[numAttribs++] = NSOpenGLPFAOpenGLProfile;
  62. attribs[numAttribs++] = version >= openGL3_2 ? NSOpenGLProfileVersion3_2Core
  63. : NSOpenGLProfileVersionLegacy;
  64. #endif
  65. attribs[numAttribs++] = NSOpenGLPFADoubleBuffer;
  66. attribs[numAttribs++] = NSOpenGLPFAClosestPolicy;
  67. attribs[numAttribs++] = NSOpenGLPFANoRecovery;
  68. attribs[numAttribs++] = NSOpenGLPFAColorSize;
  69. attribs[numAttribs++] = (NSOpenGLPixelFormatAttribute) (pixFormat.redBits + pixFormat.greenBits + pixFormat.blueBits);
  70. attribs[numAttribs++] = NSOpenGLPFAAlphaSize;
  71. attribs[numAttribs++] = (NSOpenGLPixelFormatAttribute) pixFormat.alphaBits;
  72. attribs[numAttribs++] = NSOpenGLPFADepthSize;
  73. attribs[numAttribs++] = (NSOpenGLPixelFormatAttribute) pixFormat.depthBufferBits;
  74. attribs[numAttribs++] = NSOpenGLPFAStencilSize;
  75. attribs[numAttribs++] = (NSOpenGLPixelFormatAttribute) pixFormat.stencilBufferBits;
  76. attribs[numAttribs++] = NSOpenGLPFAAccumSize;
  77. attribs[numAttribs++] = (NSOpenGLPixelFormatAttribute) (pixFormat.accumulationBufferRedBits + pixFormat.accumulationBufferGreenBits
  78. + pixFormat.accumulationBufferBlueBits + pixFormat.accumulationBufferAlphaBits);
  79. if (shouldUseMultisampling)
  80. {
  81. attribs[numAttribs++] = NSOpenGLPFAMultisample;
  82. attribs[numAttribs++] = NSOpenGLPFASampleBuffers;
  83. attribs[numAttribs++] = (NSOpenGLPixelFormatAttribute) 1;
  84. attribs[numAttribs++] = NSOpenGLPFASamples;
  85. attribs[numAttribs++] = (NSOpenGLPixelFormatAttribute) pixFormat.multisamplingLevel;
  86. }
  87. }
  88. bool initialiseOnRenderThread (OpenGLContext&) { return true; }
  89. void shutdownOnRenderThread() { deactivateCurrentContext(); }
  90. bool createdOk() const noexcept { return getRawContext() != nullptr; }
  91. void* getRawContext() const noexcept { return static_cast<void*> (renderContext); }
  92. GLuint getFrameBufferID() const noexcept { return 0; }
  93. bool makeActive() const noexcept
  94. {
  95. jassert (renderContext != nil);
  96. if ([renderContext view] != view)
  97. [renderContext setView: view];
  98. if (NSOpenGLContext* context = [view openGLContext])
  99. {
  100. [context makeCurrentContext];
  101. return true;
  102. }
  103. return false;
  104. }
  105. bool isActive() const noexcept
  106. {
  107. return [NSOpenGLContext currentContext] == renderContext;
  108. }
  109. static void deactivateCurrentContext()
  110. {
  111. [NSOpenGLContext clearCurrentContext];
  112. }
  113. struct Locker
  114. {
  115. Locker (NativeContext& nc) : cglContext ((CGLContextObj) [nc.renderContext CGLContextObj])
  116. {
  117. CGLLockContext (cglContext);
  118. }
  119. ~Locker()
  120. {
  121. CGLUnlockContext (cglContext);
  122. }
  123. private:
  124. CGLContextObj cglContext;
  125. };
  126. void swapBuffers()
  127. {
  128. auto now = Time::getMillisecondCounterHiRes();
  129. [renderContext flushBuffer];
  130. if (minSwapTimeMs > 0)
  131. {
  132. // When our window is entirely occluded by other windows, flushBuffer
  133. // fails to wait for the swap interval, so the render loop spins at full
  134. // speed, burning CPU. This hack detects when things are going too fast
  135. // and sleeps if necessary.
  136. auto swapTime = Time::getMillisecondCounterHiRes() - now;
  137. auto frameTime = (int) (now - lastSwapTime);
  138. if (swapTime < 0.5 && frameTime < minSwapTimeMs - 3)
  139. {
  140. if (underrunCounter > 3)
  141. {
  142. Thread::sleep (2 * (minSwapTimeMs - frameTime));
  143. now = Time::getMillisecondCounterHiRes();
  144. }
  145. else
  146. {
  147. ++underrunCounter;
  148. }
  149. }
  150. else
  151. {
  152. if (underrunCounter > 0)
  153. --underrunCounter;
  154. }
  155. }
  156. lastSwapTime = now;
  157. }
  158. void updateWindowPosition (Rectangle<int>) {}
  159. bool setSwapInterval (int numFramesPerSwap)
  160. {
  161. // The macOS OpenGL programming guide says that numFramesPerSwap
  162. // can only be 0 or 1.
  163. jassert (isPositiveAndBelow (numFramesPerSwap, 2));
  164. minSwapTimeMs = (numFramesPerSwap * 1000) / 60;
  165. [renderContext setValues: (const GLint*) &numFramesPerSwap
  166. #if defined (MAC_OS_X_VERSION_10_12) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12
  167. forParameter: NSOpenGLContextParameterSwapInterval];
  168. #else
  169. forParameter: NSOpenGLCPSwapInterval];
  170. #endif
  171. return true;
  172. }
  173. int getSwapInterval() const
  174. {
  175. GLint numFrames = 0;
  176. [renderContext getValues: &numFrames
  177. #if defined (MAC_OS_X_VERSION_10_12) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12
  178. forParameter: NSOpenGLContextParameterSwapInterval];
  179. #else
  180. forParameter: NSOpenGLCPSwapInterval];
  181. #endif
  182. return numFrames;
  183. }
  184. NSOpenGLContext* renderContext = nil;
  185. NSOpenGLView* view = nil;
  186. ReferenceCountedObjectPtr<ReferenceCountedObject> viewAttachment;
  187. double lastSwapTime = 0;
  188. int minSwapTimeMs = 0, underrunCounter = 0;
  189. //==============================================================================
  190. struct MouseForwardingNSOpenGLViewClass : public ObjCClass<NSOpenGLView>
  191. {
  192. MouseForwardingNSOpenGLViewClass() : ObjCClass<NSOpenGLView> ("JUCEGLView_")
  193. {
  194. addMethod (@selector (rightMouseDown:), rightMouseDown, "v@:@");
  195. addMethod (@selector (rightMouseUp:), rightMouseUp, "v@:@");
  196. addMethod (@selector (acceptsFirstMouse:), acceptsFirstMouse, "v@:@");
  197. registerClass();
  198. }
  199. private:
  200. static void rightMouseDown (id self, SEL, NSEvent* ev) { [[(NSOpenGLView*) self superview] rightMouseDown: ev]; }
  201. static void rightMouseUp (id self, SEL, NSEvent* ev) { [[(NSOpenGLView*) self superview] rightMouseUp: ev]; }
  202. static BOOL acceptsFirstMouse (id, SEL, NSEvent*) { return YES; }
  203. };
  204. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NativeContext)
  205. };
  206. //==============================================================================
  207. bool OpenGLHelpers::isContextActive()
  208. {
  209. return CGLGetCurrentContext() != CGLContextObj();
  210. }
  211. #if JUCE_DEPRECATION_IGNORED
  212. #pragma clang diagnostic pop
  213. #undef JUCE_DEPRECATION_IGNORED
  214. #endif
  215. } // namespace juce