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.

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