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.

420 lines
11KB

  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. multisamplingLevel (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. multisamplingLevel (other.multisamplingLevel)
  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. multisamplingLevel = other.multisamplingLevel;
  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. && multisamplingLevel == other.multisamplingLevel;
  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. OpenGLComponentWatcher (OpenGLComponent* const owner_)
  105. : ComponentMovementWatcher (owner_),
  106. owner (owner_)
  107. {
  108. }
  109. void componentMovedOrResized (bool /*wasMoved*/, bool /*wasResized*/)
  110. {
  111. owner->updateContextPosition();
  112. }
  113. void componentPeerChanged()
  114. {
  115. owner->recreateContextAsync();
  116. }
  117. void componentVisibilityChanged()
  118. {
  119. if (! owner->isShowing())
  120. owner->stopBackgroundThread();
  121. }
  122. private:
  123. OpenGLComponent* const owner;
  124. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpenGLComponentWatcher);
  125. };
  126. //==============================================================================
  127. class OpenGLComponent::OpenGLComponentRenderThread : public Thread
  128. {
  129. public:
  130. OpenGLComponentRenderThread (OpenGLComponent& owner_)
  131. : Thread ("OpenGL Render"),
  132. owner (owner_)
  133. {
  134. }
  135. void run()
  136. {
  137. #if JUCE_LINUX
  138. {
  139. MessageManagerLock mml (this);
  140. if (! mml.lockWasGained())
  141. return;
  142. owner.updateContext();
  143. owner.updateContextPosition();
  144. }
  145. #endif
  146. while (! threadShouldExit())
  147. {
  148. const uint32 startOfRendering = Time::getMillisecondCounter();
  149. if (! owner.renderAndSwapBuffers())
  150. break;
  151. const int elapsed = (int) (Time::getMillisecondCounter() - startOfRendering);
  152. Thread::sleep (jmax (1, 20 - elapsed));
  153. }
  154. #if JUCE_LINUX
  155. owner.deleteContext();
  156. #endif
  157. }
  158. private:
  159. OpenGLComponent& owner;
  160. JUCE_DECLARE_NON_COPYABLE (OpenGLComponentRenderThread);
  161. };
  162. void OpenGLComponent::startRenderThread()
  163. {
  164. if (renderThread == nullptr)
  165. renderThread = new OpenGLComponentRenderThread (*this);
  166. renderThread->startThread (6);
  167. }
  168. void OpenGLComponent::stopRenderThread()
  169. {
  170. if (renderThread != nullptr)
  171. {
  172. renderThread->stopThread (5000);
  173. renderThread = nullptr;
  174. }
  175. #if ! JUCE_LINUX
  176. deleteContext();
  177. #endif
  178. }
  179. //==============================================================================
  180. OpenGLComponent::OpenGLComponent (const OpenGLType type_, const bool useBackgroundThread)
  181. : type (type_),
  182. contextToShareListsWith (nullptr),
  183. needToUpdateViewport (true),
  184. needToDeleteContext (false),
  185. threadStarted (false),
  186. useThread (useBackgroundThread)
  187. {
  188. setOpaque (true);
  189. componentWatcher = new OpenGLComponentWatcher (this);
  190. }
  191. OpenGLComponent::~OpenGLComponent()
  192. {
  193. stopBackgroundThread();
  194. componentWatcher = nullptr;
  195. }
  196. void OpenGLComponent::setPixelFormat (const OpenGLPixelFormat& formatToUse)
  197. {
  198. if (! (preferredPixelFormat == formatToUse))
  199. {
  200. const ScopedLock sl (contextLock);
  201. preferredPixelFormat = formatToUse;
  202. recreateContextAsync();
  203. }
  204. }
  205. void OpenGLComponent::shareWith (OpenGLContext* c)
  206. {
  207. if (contextToShareListsWith != c)
  208. {
  209. const ScopedLock sl (contextLock);
  210. contextToShareListsWith = c;
  211. recreateContextAsync();
  212. }
  213. }
  214. void OpenGLComponent::recreateContextAsync()
  215. {
  216. const ScopedLock sl (contextLock);
  217. needToDeleteContext = true;
  218. repaint();
  219. }
  220. bool OpenGLComponent::makeCurrentRenderingTarget()
  221. {
  222. return context != nullptr && context->makeActive();
  223. }
  224. void OpenGLComponent::releaseAsRenderingTarget()
  225. {
  226. if (context != nullptr)
  227. context->makeInactive();
  228. }
  229. void OpenGLComponent::swapBuffers()
  230. {
  231. if (context != nullptr)
  232. context->swapBuffers();
  233. }
  234. void OpenGLComponent::updateContext()
  235. {
  236. if (needToDeleteContext)
  237. deleteContext();
  238. if (context == nullptr)
  239. {
  240. const ScopedLock sl (contextLock);
  241. if (context == nullptr)
  242. {
  243. context = createContext();
  244. if (context != nullptr)
  245. {
  246. #if JUCE_LINUX
  247. if (! useThread)
  248. #endif
  249. updateContextPosition();
  250. if (context->makeActive())
  251. {
  252. newOpenGLContextCreated();
  253. context->makeInactive();
  254. }
  255. }
  256. }
  257. }
  258. }
  259. void OpenGLComponent::deleteContext()
  260. {
  261. const ScopedLock sl (contextLock);
  262. if (context != nullptr)
  263. {
  264. if (context->makeActive())
  265. {
  266. releaseOpenGLContext();
  267. context->makeInactive();
  268. }
  269. context = nullptr;
  270. }
  271. needToDeleteContext = false;
  272. }
  273. void OpenGLComponent::updateContextPosition()
  274. {
  275. needToUpdateViewport = true;
  276. if (getWidth() > 0 && getHeight() > 0)
  277. {
  278. Component* const topComp = getTopLevelComponent();
  279. if (topComp->getPeer() != nullptr)
  280. {
  281. const ScopedLock sl (contextLock);
  282. updateEmbeddedPosition (topComp->getLocalArea (this, getLocalBounds()));
  283. }
  284. }
  285. }
  286. void OpenGLComponent::stopBackgroundThread()
  287. {
  288. if (threadStarted)
  289. {
  290. stopRenderThread();
  291. threadStarted = false;
  292. }
  293. }
  294. void OpenGLComponent::paint (Graphics&)
  295. {
  296. ComponentPeer* const peer = getPeer();
  297. if (useThread)
  298. {
  299. if (peer != nullptr && isShowing())
  300. {
  301. #if ! JUCE_LINUX
  302. updateContext();
  303. #endif
  304. if (! threadStarted)
  305. {
  306. threadStarted = true;
  307. startRenderThread();
  308. }
  309. }
  310. }
  311. else
  312. {
  313. updateContext();
  314. if (! renderAndSwapBuffers())
  315. return;
  316. }
  317. if (peer != nullptr)
  318. {
  319. const Point<int> topLeft (getScreenPosition() - peer->getScreenPosition());
  320. peer->addMaskedRegion (topLeft.getX(), topLeft.getY(), getWidth(), getHeight());
  321. }
  322. }
  323. bool OpenGLComponent::renderAndSwapBuffers()
  324. {
  325. const ScopedLock sl (contextLock);
  326. #if JUCE_LINUX
  327. updateContext();
  328. #endif
  329. if (context != nullptr)
  330. {
  331. if (! makeCurrentRenderingTarget())
  332. return false;
  333. if (needToUpdateViewport)
  334. {
  335. needToUpdateViewport = false;
  336. glViewport (0, 0, getWidth(), getHeight());
  337. }
  338. renderOpenGL();
  339. swapBuffers();
  340. }
  341. return true;
  342. }
  343. unsigned int OpenGLComponent::getFrameBufferID() const
  344. {
  345. return context != nullptr ? context->getFrameBufferID() : 0;
  346. }
  347. END_JUCE_NAMESPACE