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.

445 lines
12KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-11 by Raw Material Software Ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the GNU General
  7. Public License (Version 2), as published by the Free Software Foundation.
  8. A copy of the license is included in the JUCE distribution, or can be found
  9. online at www.gnu.org/licenses.
  10. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. ------------------------------------------------------------------------------
  14. To release a closed-source product which uses JUCE, commercial licenses are
  15. available: visit www.rawmaterialsoftware.com/juce for more information.
  16. ==============================================================================
  17. */
  18. BEGIN_JUCE_NAMESPACE
  19. //==============================================================================
  20. OpenGLPixelFormat::OpenGLPixelFormat (const int bitsPerRGBComponent,
  21. const int alphaBits_,
  22. const int depthBufferBits_,
  23. const int stencilBufferBits_)
  24. : redBits (bitsPerRGBComponent),
  25. greenBits (bitsPerRGBComponent),
  26. blueBits (bitsPerRGBComponent),
  27. alphaBits (alphaBits_),
  28. depthBufferBits (depthBufferBits_),
  29. stencilBufferBits (stencilBufferBits_),
  30. accumulationBufferRedBits (0),
  31. accumulationBufferGreenBits (0),
  32. accumulationBufferBlueBits (0),
  33. accumulationBufferAlphaBits (0),
  34. fullSceneAntiAliasingNumSamples (0)
  35. {
  36. }
  37. OpenGLPixelFormat::OpenGLPixelFormat (const OpenGLPixelFormat& other)
  38. : redBits (other.redBits),
  39. greenBits (other.greenBits),
  40. blueBits (other.blueBits),
  41. alphaBits (other.alphaBits),
  42. depthBufferBits (other.depthBufferBits),
  43. stencilBufferBits (other.stencilBufferBits),
  44. accumulationBufferRedBits (other.accumulationBufferRedBits),
  45. accumulationBufferGreenBits (other.accumulationBufferGreenBits),
  46. accumulationBufferBlueBits (other.accumulationBufferBlueBits),
  47. accumulationBufferAlphaBits (other.accumulationBufferAlphaBits),
  48. fullSceneAntiAliasingNumSamples (other.fullSceneAntiAliasingNumSamples)
  49. {
  50. }
  51. OpenGLPixelFormat& OpenGLPixelFormat::operator= (const OpenGLPixelFormat& other)
  52. {
  53. redBits = other.redBits;
  54. greenBits = other.greenBits;
  55. blueBits = other.blueBits;
  56. alphaBits = other.alphaBits;
  57. depthBufferBits = other.depthBufferBits;
  58. stencilBufferBits = other.stencilBufferBits;
  59. accumulationBufferRedBits = other.accumulationBufferRedBits;
  60. accumulationBufferGreenBits = other.accumulationBufferGreenBits;
  61. accumulationBufferBlueBits = other.accumulationBufferBlueBits;
  62. accumulationBufferAlphaBits = other.accumulationBufferAlphaBits;
  63. fullSceneAntiAliasingNumSamples = other.fullSceneAntiAliasingNumSamples;
  64. return *this;
  65. }
  66. bool OpenGLPixelFormat::operator== (const OpenGLPixelFormat& other) const
  67. {
  68. return redBits == other.redBits
  69. && greenBits == other.greenBits
  70. && blueBits == other.blueBits
  71. && alphaBits == other.alphaBits
  72. && depthBufferBits == other.depthBufferBits
  73. && stencilBufferBits == other.stencilBufferBits
  74. && accumulationBufferRedBits == other.accumulationBufferRedBits
  75. && accumulationBufferGreenBits == other.accumulationBufferGreenBits
  76. && accumulationBufferBlueBits == other.accumulationBufferBlueBits
  77. && accumulationBufferAlphaBits == other.accumulationBufferAlphaBits
  78. && fullSceneAntiAliasingNumSamples == other.fullSceneAntiAliasingNumSamples;
  79. }
  80. //==============================================================================
  81. static Array<OpenGLContext*> knownContexts;
  82. OpenGLContext::OpenGLContext() noexcept
  83. {
  84. knownContexts.add (this);
  85. }
  86. OpenGLContext::~OpenGLContext()
  87. {
  88. knownContexts.removeValue (this);
  89. }
  90. OpenGLContext* OpenGLContext::getCurrentContext()
  91. {
  92. for (int i = knownContexts.size(); --i >= 0;)
  93. {
  94. OpenGLContext* const oglc = knownContexts.getUnchecked(i);
  95. if (oglc->isActive())
  96. return oglc;
  97. }
  98. return nullptr;
  99. }
  100. //==============================================================================
  101. class OpenGLComponent::OpenGLComponentWatcher : public ComponentMovementWatcher
  102. {
  103. public:
  104. //==============================================================================
  105. OpenGLComponentWatcher (OpenGLComponent* const owner_)
  106. : ComponentMovementWatcher (owner_),
  107. owner (owner_)
  108. {
  109. }
  110. //==============================================================================
  111. void componentMovedOrResized (bool /*wasMoved*/, bool /*wasResized*/)
  112. {
  113. owner->updateContextPosition();
  114. }
  115. void componentPeerChanged()
  116. {
  117. owner->recreateContextAsync();
  118. }
  119. void componentVisibilityChanged()
  120. {
  121. if (! owner->isShowing())
  122. owner->stopBackgroundThread();
  123. }
  124. //==============================================================================
  125. private:
  126. OpenGLComponent* const owner;
  127. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpenGLComponentWatcher);
  128. };
  129. //==============================================================================
  130. class OpenGLComponent::OpenGLComponentRenderThread : public Thread
  131. {
  132. public:
  133. OpenGLComponentRenderThread (OpenGLComponent& owner_)
  134. : Thread ("OpenGL Render"),
  135. owner (owner_)
  136. {
  137. }
  138. void run()
  139. {
  140. #if JUCE_LINUX
  141. {
  142. MessageManagerLock mml (this);
  143. if (! mml.lockWasGained())
  144. return;
  145. owner.updateContext();
  146. owner.updateContextPosition();
  147. }
  148. #endif
  149. while (! threadShouldExit())
  150. {
  151. const uint32 startOfRendering = Time::getMillisecondCounter();
  152. if (! owner.renderAndSwapBuffers())
  153. break;
  154. const int elapsed = (int) (Time::getMillisecondCounter() - startOfRendering);
  155. Thread::sleep (jmax (1, 20 - elapsed));
  156. }
  157. #if JUCE_LINUX
  158. owner.deleteContext();
  159. #endif
  160. }
  161. private:
  162. OpenGLComponent& owner;
  163. JUCE_DECLARE_NON_COPYABLE (OpenGLComponentRenderThread);
  164. };
  165. void OpenGLComponent::startRenderThread()
  166. {
  167. if (renderThread == nullptr)
  168. renderThread = new OpenGLComponentRenderThread (*this);
  169. renderThread->startThread (6);
  170. }
  171. void OpenGLComponent::stopRenderThread()
  172. {
  173. if (renderThread != nullptr)
  174. {
  175. renderThread->stopThread (5000);
  176. renderThread = nullptr;
  177. }
  178. #if ! JUCE_LINUX
  179. deleteContext();
  180. #endif
  181. }
  182. //==============================================================================
  183. OpenGLComponent::OpenGLComponent (const OpenGLType type_, const bool useBackgroundThread)
  184. : type (type_),
  185. contextToShareListsWith (nullptr),
  186. needToUpdateViewport (true),
  187. needToDeleteContext (false),
  188. threadStarted (false),
  189. useThread (useBackgroundThread)
  190. {
  191. setOpaque (true);
  192. componentWatcher = new OpenGLComponentWatcher (this);
  193. }
  194. OpenGLComponent::~OpenGLComponent()
  195. {
  196. stopBackgroundThread();
  197. componentWatcher = nullptr;
  198. }
  199. OpenGLPixelFormat OpenGLComponent::getPixelFormat() const
  200. {
  201. OpenGLPixelFormat pf;
  202. const ScopedLock sl (contextLock);
  203. if (context != nullptr)
  204. pf = context->getPixelFormat();
  205. return pf;
  206. }
  207. void OpenGLComponent::setPixelFormat (const OpenGLPixelFormat& formatToUse)
  208. {
  209. if (! (preferredPixelFormat == formatToUse))
  210. {
  211. const ScopedLock sl (contextLock);
  212. preferredPixelFormat = formatToUse;
  213. recreateContextAsync();
  214. }
  215. }
  216. void OpenGLComponent::shareWith (OpenGLContext* c)
  217. {
  218. if (contextToShareListsWith != c)
  219. {
  220. const ScopedLock sl (contextLock);
  221. contextToShareListsWith = c;
  222. recreateContextAsync();
  223. }
  224. }
  225. void OpenGLComponent::recreateContextAsync()
  226. {
  227. const ScopedLock sl (contextLock);
  228. needToDeleteContext = true;
  229. repaint();
  230. }
  231. bool OpenGLComponent::makeCurrentContextActive()
  232. {
  233. return context != nullptr && context->makeActive();
  234. }
  235. void OpenGLComponent::makeCurrentContextInactive()
  236. {
  237. if (context != nullptr)
  238. context->makeInactive();
  239. }
  240. bool OpenGLComponent::isActiveContext() const noexcept
  241. {
  242. return context != nullptr && context->isActive();
  243. }
  244. void OpenGLComponent::swapBuffers()
  245. {
  246. if (context != nullptr)
  247. context->swapBuffers();
  248. }
  249. void OpenGLComponent::updateContext()
  250. {
  251. if (needToDeleteContext)
  252. deleteContext();
  253. if (context == nullptr)
  254. {
  255. const ScopedLock sl (contextLock);
  256. if (context == nullptr)
  257. {
  258. context = createContext();
  259. if (context != nullptr)
  260. {
  261. #if JUCE_LINUX
  262. if (! useThread)
  263. #endif
  264. updateContextPosition();
  265. if (context->makeActive())
  266. {
  267. newOpenGLContextCreated();
  268. context->makeInactive();
  269. }
  270. }
  271. }
  272. }
  273. }
  274. void OpenGLComponent::deleteContext()
  275. {
  276. const ScopedLock sl (contextLock);
  277. if (context != nullptr)
  278. {
  279. if (context->makeActive())
  280. {
  281. releaseOpenGLContext();
  282. context->makeInactive();
  283. }
  284. context = nullptr;
  285. }
  286. needToDeleteContext = false;
  287. }
  288. void OpenGLComponent::updateContextPosition()
  289. {
  290. needToUpdateViewport = true;
  291. if (getWidth() > 0 && getHeight() > 0)
  292. {
  293. Component* const topComp = getTopLevelComponent();
  294. if (topComp->getPeer() != nullptr)
  295. {
  296. const ScopedLock sl (contextLock);
  297. if (context != nullptr)
  298. context->updateWindowPosition (topComp->getLocalArea (this, getLocalBounds()));
  299. }
  300. }
  301. }
  302. void OpenGLComponent::stopBackgroundThread()
  303. {
  304. if (threadStarted)
  305. {
  306. stopRenderThread();
  307. threadStarted = false;
  308. }
  309. }
  310. void OpenGLComponent::paint (Graphics&)
  311. {
  312. ComponentPeer* const peer = getPeer();
  313. if (useThread)
  314. {
  315. if (peer != nullptr && isShowing())
  316. {
  317. #if ! JUCE_LINUX
  318. updateContext();
  319. #endif
  320. if (! threadStarted)
  321. {
  322. threadStarted = true;
  323. startRenderThread();
  324. }
  325. }
  326. }
  327. else
  328. {
  329. updateContext();
  330. if (! renderAndSwapBuffers())
  331. return;
  332. }
  333. if (peer != nullptr)
  334. {
  335. const Point<int> topLeft (getScreenPosition() - peer->getScreenPosition());
  336. peer->addMaskedRegion (topLeft.getX(), topLeft.getY(), getWidth(), getHeight());
  337. }
  338. }
  339. bool OpenGLComponent::renderAndSwapBuffers()
  340. {
  341. const ScopedLock sl (contextLock);
  342. #if JUCE_LINUX
  343. updateContext();
  344. #endif
  345. if (context != nullptr)
  346. {
  347. if (! makeCurrentContextActive())
  348. return false;
  349. if (needToUpdateViewport)
  350. {
  351. needToUpdateViewport = false;
  352. glViewport (0, 0, getWidth(), getHeight());
  353. }
  354. renderOpenGL();
  355. swapBuffers();
  356. }
  357. return true;
  358. }
  359. void OpenGLComponent::internalRepaint (int x, int y, int w, int h)
  360. {
  361. Component::internalRepaint (x, y, w, h);
  362. if (context != nullptr)
  363. context->repaint();
  364. }
  365. END_JUCE_NAMESPACE