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.

227 lines
8.2KB

  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. class OpenGLContext::NativeContext
  18. {
  19. public:
  20. NativeContext (Component& component,
  21. const OpenGLPixelFormat& pixFormat,
  22. void* contextToShare,
  23. bool /*useMultisampling*/,
  24. OpenGLVersion version)
  25. : lastSwapTime (0), minSwapTimeMs (0), underrunCounter (0)
  26. {
  27. (void) version;
  28. NSOpenGLPixelFormatAttribute attribs[] =
  29. {
  30. #if JUCE_OPENGL3
  31. NSOpenGLPFAOpenGLProfile, version >= openGL3_2 ? NSOpenGLProfileVersion3_2Core : NSOpenGLProfileVersionLegacy,
  32. #endif
  33. NSOpenGLPFADoubleBuffer,
  34. NSOpenGLPFAMPSafe,
  35. NSOpenGLPFAClosestPolicy,
  36. NSOpenGLPFANoRecovery,
  37. NSOpenGLPFAColorSize, (NSOpenGLPixelFormatAttribute) (pixFormat.redBits + pixFormat.greenBits + pixFormat.blueBits),
  38. NSOpenGLPFAAlphaSize, (NSOpenGLPixelFormatAttribute) pixFormat.alphaBits,
  39. NSOpenGLPFADepthSize, (NSOpenGLPixelFormatAttribute) pixFormat.depthBufferBits,
  40. NSOpenGLPFAStencilSize, (NSOpenGLPixelFormatAttribute) pixFormat.stencilBufferBits,
  41. NSOpenGLPFAAccumSize, (NSOpenGLPixelFormatAttribute) (pixFormat.accumulationBufferRedBits + pixFormat.accumulationBufferGreenBits
  42. + pixFormat.accumulationBufferBlueBits + pixFormat.accumulationBufferAlphaBits),
  43. pixFormat.multisamplingLevel > 0 ? NSOpenGLPFASamples : (NSOpenGLPixelFormatAttribute) 0,
  44. (NSOpenGLPixelFormatAttribute) pixFormat.multisamplingLevel,
  45. 0
  46. };
  47. NSOpenGLPixelFormat* format = [[NSOpenGLPixelFormat alloc] initWithAttributes: attribs];
  48. static MouseForwardingNSOpenGLViewClass cls;
  49. view = [cls.createInstance() initWithFrame: NSMakeRect (0, 0, 100.0f, 100.0f)
  50. pixelFormat: format];
  51. #if defined (MAC_OS_X_VERSION_10_7) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7)
  52. if ([view respondsToSelector: @selector (setWantsBestResolutionOpenGLSurface:)])
  53. [view setWantsBestResolutionOpenGLSurface: YES];
  54. #endif
  55. [[NSNotificationCenter defaultCenter] addObserver: view
  56. selector: @selector (_surfaceNeedsUpdate:)
  57. name: NSViewGlobalFrameDidChangeNotification
  58. object: view];
  59. renderContext = [[[NSOpenGLContext alloc] initWithFormat: format
  60. shareContext: (NSOpenGLContext*) contextToShare] autorelease];
  61. [view setOpenGLContext: renderContext];
  62. [format release];
  63. viewAttachment = NSViewComponent::attachViewToComponent (component, view);
  64. }
  65. ~NativeContext()
  66. {
  67. [[NSNotificationCenter defaultCenter] removeObserver: view];
  68. [renderContext clearDrawable];
  69. [renderContext setView: nil];
  70. [view setOpenGLContext: nil];
  71. renderContext = nil;
  72. }
  73. void initialiseOnRenderThread (OpenGLContext&) {}
  74. void shutdownOnRenderThread() { deactivateCurrentContext(); }
  75. bool createdOk() const noexcept { return getRawContext() != nullptr; }
  76. void* getRawContext() const noexcept { return static_cast <void*> (renderContext); }
  77. GLuint getFrameBufferID() const noexcept { return 0; }
  78. bool makeActive() const noexcept
  79. {
  80. jassert (renderContext != nil);
  81. if ([renderContext view] != view)
  82. [renderContext setView: view];
  83. if (NSOpenGLContext* context = [view openGLContext])
  84. {
  85. [context makeCurrentContext];
  86. return true;
  87. }
  88. return false;
  89. }
  90. bool isActive() const noexcept
  91. {
  92. return [NSOpenGLContext currentContext] == renderContext;
  93. }
  94. static void deactivateCurrentContext()
  95. {
  96. [NSOpenGLContext clearCurrentContext];
  97. }
  98. struct Locker
  99. {
  100. Locker (NativeContext& nc) : cglContext ((CGLContextObj) [nc.renderContext CGLContextObj])
  101. {
  102. CGLLockContext (cglContext);
  103. }
  104. ~Locker()
  105. {
  106. CGLUnlockContext (cglContext);
  107. }
  108. private:
  109. CGLContextObj cglContext;
  110. };
  111. void swapBuffers()
  112. {
  113. [renderContext flushBuffer];
  114. sleepIfRenderingTooFast();
  115. }
  116. void updateWindowPosition (const Rectangle<int>&) {}
  117. bool setSwapInterval (int numFramesPerSwap)
  118. {
  119. minSwapTimeMs = (numFramesPerSwap * 1000) / 60;
  120. [renderContext setValues: (const GLint*) &numFramesPerSwap
  121. forParameter: NSOpenGLCPSwapInterval];
  122. return true;
  123. }
  124. int getSwapInterval() const
  125. {
  126. GLint numFrames = 0;
  127. [renderContext getValues: &numFrames
  128. forParameter: NSOpenGLCPSwapInterval];
  129. return numFrames;
  130. }
  131. void sleepIfRenderingTooFast()
  132. {
  133. // When our window is entirely occluded by other windows, the system
  134. // fails to correctly implement the swap interval time, so the render
  135. // loop spins at full speed, burning CPU. This hack detects when things
  136. // are going too fast and slows things down if necessary.
  137. if (minSwapTimeMs > 0)
  138. {
  139. const double now = Time::getMillisecondCounterHiRes();
  140. const int elapsed = (int) (now - lastSwapTime);
  141. lastSwapTime = now;
  142. if (isPositiveAndBelow (elapsed, minSwapTimeMs - 3))
  143. {
  144. if (underrunCounter > 3)
  145. Thread::sleep (minSwapTimeMs - elapsed);
  146. else
  147. ++underrunCounter;
  148. }
  149. else
  150. {
  151. underrunCounter = 0;
  152. }
  153. }
  154. }
  155. NSOpenGLContext* renderContext;
  156. NSOpenGLView* view;
  157. ReferenceCountedObjectPtr<ReferenceCountedObject> viewAttachment;
  158. double lastSwapTime;
  159. int minSwapTimeMs, underrunCounter;
  160. //==============================================================================
  161. struct MouseForwardingNSOpenGLViewClass : public ObjCClass <NSOpenGLView>
  162. {
  163. MouseForwardingNSOpenGLViewClass() : ObjCClass <NSOpenGLView> ("JUCEGLView_")
  164. {
  165. addMethod (@selector (rightMouseDown:), rightMouseDown, "v@:@");
  166. addMethod (@selector (rightMouseUp:), rightMouseUp, "v@:@");
  167. addMethod (@selector (acceptsFirstMouse:), acceptsFirstMouse, "v@:@");
  168. registerClass();
  169. }
  170. private:
  171. static void rightMouseDown (id self, SEL, NSEvent* ev) { [[(NSOpenGLView*) self superview] rightMouseDown: ev]; }
  172. static void rightMouseUp (id self, SEL, NSEvent* ev) { [[(NSOpenGLView*) self superview] rightMouseUp: ev]; }
  173. static BOOL acceptsFirstMouse (id, SEL, NSEvent*) { return YES; }
  174. };
  175. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NativeContext)
  176. };
  177. //==============================================================================
  178. bool OpenGLHelpers::isContextActive()
  179. {
  180. return CGLGetCurrentContext() != 0;
  181. }