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.

221 lines
8.0KB

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