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.

220 lines
7.9KB

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