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.

287 lines
10KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2020 - Raw Material Software Limited
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. By using JUCE, you agree to the terms of both the JUCE 6 End-User License
  8. Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
  9. End User License Agreement: www.juce.com/juce-6-licence
  10. Privacy Policy: www.juce.com/juce-privacy-policy
  11. Or: You may also use this code under the terms of the GPL v3 (see
  12. www.gnu.org/licenses).
  13. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  14. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  15. DISCLAIMED.
  16. ==============================================================================
  17. */
  18. namespace juce
  19. {
  20. extern XContext windowHandleXContext;
  21. //==============================================================================
  22. // Defined juce_linux_Windowing.cpp
  23. void juce_LinuxAddRepaintListener (ComponentPeer*, Component* dummy);
  24. void juce_LinuxRemoveRepaintListener (ComponentPeer*, Component* dummy);
  25. //==============================================================================
  26. class OpenGLContext::NativeContext
  27. {
  28. private:
  29. struct DummyComponent : public Component
  30. {
  31. DummyComponent (OpenGLContext::NativeContext& nativeParentContext)
  32. : native (nativeParentContext)
  33. {
  34. }
  35. void handleCommandMessage (int commandId) override
  36. {
  37. if (commandId == 0)
  38. native.triggerRepaint();
  39. }
  40. OpenGLContext::NativeContext& native;
  41. };
  42. public:
  43. NativeContext (Component& comp,
  44. const OpenGLPixelFormat& cPixelFormat,
  45. void* shareContext,
  46. bool useMultisamplingIn,
  47. OpenGLVersion)
  48. : component (comp), contextToShareWith (shareContext), dummy (*this)
  49. {
  50. display = XWindowSystem::getInstance()->getDisplay();
  51. XWindowSystemUtilities::ScopedXLock xLock;
  52. X11Symbols::getInstance()->xSync (display, False);
  53. const std::vector<GLint> optionalAttribs
  54. {
  55. GLX_SAMPLE_BUFFERS, useMultisamplingIn ? 1 : 0,
  56. GLX_SAMPLES, cPixelFormat.multisamplingLevel
  57. };
  58. if (! tryChooseVisual (cPixelFormat, optionalAttribs) && ! tryChooseVisual (cPixelFormat, {}))
  59. return;
  60. auto* peer = component.getPeer();
  61. jassert (peer != nullptr);
  62. auto windowH = (Window) peer->getNativeHandle();
  63. auto colourMap = X11Symbols::getInstance()->xCreateColormap (display, windowH, bestVisual->visual, AllocNone);
  64. XSetWindowAttributes swa;
  65. swa.colormap = colourMap;
  66. swa.border_pixel = 0;
  67. swa.event_mask = embeddedWindowEventMask;
  68. auto glBounds = component.getTopLevelComponent()
  69. ->getLocalArea (&component, component.getLocalBounds());
  70. glBounds = Desktop::getInstance().getDisplays().logicalToPhysical (glBounds);
  71. embeddedWindow = X11Symbols::getInstance()->xCreateWindow (display, windowH,
  72. glBounds.getX(), glBounds.getY(),
  73. (unsigned int) jmax (1, glBounds.getWidth()),
  74. (unsigned int) jmax (1, glBounds.getHeight()),
  75. 0, bestVisual->depth,
  76. InputOutput,
  77. bestVisual->visual,
  78. CWBorderPixel | CWColormap | CWEventMask,
  79. &swa);
  80. X11Symbols::getInstance()->xSaveContext (display, (XID) embeddedWindow, windowHandleXContext, (XPointer) peer);
  81. X11Symbols::getInstance()->xMapWindow (display, embeddedWindow);
  82. X11Symbols::getInstance()->xFreeColormap (display, colourMap);
  83. X11Symbols::getInstance()->xSync (display, False);
  84. juce_LinuxAddRepaintListener (peer, &dummy);
  85. }
  86. ~NativeContext()
  87. {
  88. if (auto* peer = component.getPeer())
  89. {
  90. juce_LinuxRemoveRepaintListener (peer, &dummy);
  91. if (embeddedWindow != 0)
  92. {
  93. XWindowSystemUtilities::ScopedXLock xLock;
  94. X11Symbols::getInstance()->xUnmapWindow (display, embeddedWindow);
  95. X11Symbols::getInstance()->xDestroyWindow (display, embeddedWindow);
  96. X11Symbols::getInstance()->xSync (display, False);
  97. XEvent event;
  98. while (X11Symbols::getInstance()->xCheckWindowEvent (display,
  99. embeddedWindow,
  100. embeddedWindowEventMask,
  101. &event) == True)
  102. {
  103. }
  104. }
  105. }
  106. if (bestVisual != nullptr)
  107. X11Symbols::getInstance()->xFree (bestVisual);
  108. }
  109. bool initialiseOnRenderThread (OpenGLContext& c)
  110. {
  111. XWindowSystemUtilities::ScopedXLock xLock;
  112. renderContext = glXCreateContext (display, bestVisual, (GLXContext) contextToShareWith, GL_TRUE);
  113. c.makeActive();
  114. context = &c;
  115. return true;
  116. }
  117. void shutdownOnRenderThread()
  118. {
  119. XWindowSystemUtilities::ScopedXLock xLock;
  120. context = nullptr;
  121. deactivateCurrentContext();
  122. glXDestroyContext (display, renderContext);
  123. renderContext = nullptr;
  124. }
  125. bool makeActive() const noexcept
  126. {
  127. XWindowSystemUtilities::ScopedXLock xLock;
  128. return renderContext != nullptr
  129. && glXMakeCurrent (display, embeddedWindow, renderContext);
  130. }
  131. bool isActive() const noexcept
  132. {
  133. XWindowSystemUtilities::ScopedXLock xLock;
  134. return glXGetCurrentContext() == renderContext && renderContext != nullptr;
  135. }
  136. static void deactivateCurrentContext()
  137. {
  138. if (auto* display = XWindowSystem::getInstance()->getDisplay())
  139. {
  140. XWindowSystemUtilities::ScopedXLock xLock;
  141. glXMakeCurrent (display, None, nullptr);
  142. }
  143. }
  144. void swapBuffers()
  145. {
  146. XWindowSystemUtilities::ScopedXLock xLock;
  147. glXSwapBuffers (display, embeddedWindow);
  148. }
  149. void updateWindowPosition (Rectangle<int> newBounds)
  150. {
  151. bounds = newBounds;
  152. auto physicalBounds = Desktop::getInstance().getDisplays().logicalToPhysical (bounds);
  153. XWindowSystemUtilities::ScopedXLock xLock;
  154. X11Symbols::getInstance()->xMoveResizeWindow (display, embeddedWindow,
  155. physicalBounds.getX(), physicalBounds.getY(),
  156. (unsigned int) jmax (1, physicalBounds.getWidth()),
  157. (unsigned int) jmax (1, physicalBounds.getHeight()));
  158. }
  159. bool setSwapInterval (int numFramesPerSwap)
  160. {
  161. if (numFramesPerSwap == swapFrames)
  162. return true;
  163. if (auto GLXSwapIntervalSGI
  164. = (PFNGLXSWAPINTERVALSGIPROC) OpenGLHelpers::getExtensionFunction ("glXSwapIntervalSGI"))
  165. {
  166. XWindowSystemUtilities::ScopedXLock xLock;
  167. swapFrames = numFramesPerSwap;
  168. GLXSwapIntervalSGI (numFramesPerSwap);
  169. return true;
  170. }
  171. return false;
  172. }
  173. int getSwapInterval() const { return swapFrames; }
  174. bool createdOk() const noexcept { return true; }
  175. void* getRawContext() const noexcept { return renderContext; }
  176. GLuint getFrameBufferID() const noexcept { return 0; }
  177. void triggerRepaint()
  178. {
  179. if (context != nullptr)
  180. context->triggerRepaint();
  181. }
  182. struct Locker { Locker (NativeContext&) {} };
  183. private:
  184. bool tryChooseVisual (const OpenGLPixelFormat& format, const std::vector<GLint>& optionalAttribs)
  185. {
  186. std::vector<GLint> allAttribs
  187. {
  188. GLX_RGBA,
  189. GLX_DOUBLEBUFFER,
  190. GLX_RED_SIZE, format.redBits,
  191. GLX_GREEN_SIZE, format.greenBits,
  192. GLX_BLUE_SIZE, format.blueBits,
  193. GLX_ALPHA_SIZE, format.alphaBits,
  194. GLX_DEPTH_SIZE, format.depthBufferBits,
  195. GLX_STENCIL_SIZE, format.stencilBufferBits,
  196. GLX_ACCUM_RED_SIZE, format.accumulationBufferRedBits,
  197. GLX_ACCUM_GREEN_SIZE, format.accumulationBufferGreenBits,
  198. GLX_ACCUM_BLUE_SIZE, format.accumulationBufferBlueBits,
  199. GLX_ACCUM_ALPHA_SIZE, format.accumulationBufferAlphaBits
  200. };
  201. allAttribs.insert (allAttribs.end(), optionalAttribs.begin(), optionalAttribs.end());
  202. allAttribs.push_back (None);
  203. bestVisual = glXChooseVisual (display, X11Symbols::getInstance()->xDefaultScreen (display), allAttribs.data());
  204. return bestVisual != nullptr;
  205. }
  206. static constexpr int embeddedWindowEventMask = ExposureMask | StructureNotifyMask;
  207. Component& component;
  208. GLXContext renderContext = {};
  209. Window embeddedWindow = {};
  210. int swapFrames = 1;
  211. Rectangle<int> bounds;
  212. XVisualInfo* bestVisual = nullptr;
  213. void* contextToShareWith;
  214. OpenGLContext* context = nullptr;
  215. DummyComponent dummy;
  216. ::Display* display = nullptr;
  217. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NativeContext)
  218. };
  219. //==============================================================================
  220. bool OpenGLHelpers::isContextActive()
  221. {
  222. XWindowSystemUtilities::ScopedXLock xLock;
  223. return glXGetCurrentContext() != nullptr;
  224. }
  225. } // namespace juce