mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
OpenGL: Ensure flushBuffer can't be called simultaneously from multiple threads on macOS 10.13 or earlier
On these platforms, calling flushBuffer from multiple threads simultaneously will lead to deadlocks.
This commit is contained in:
parent
6df7e46e26
commit
c08a1827b5
1 changed files with 64 additions and 31 deletions
|
|
@ -186,12 +186,22 @@ public:
|
|||
{
|
||||
renderThread->remove (this);
|
||||
|
||||
if ((state.fetch_and (~StateFlags::initialised) & StateFlags::initialised) != 0)
|
||||
{
|
||||
context.makeActive();
|
||||
shutdownOnThread();
|
||||
OpenGLContext::deactivateCurrentContext();
|
||||
}
|
||||
if ((state.fetch_and (~StateFlags::initialised) & StateFlags::initialised) == 0)
|
||||
return;
|
||||
|
||||
ScopedContextActivator activator;
|
||||
activator.activate (context);
|
||||
|
||||
if (context.renderer != nullptr)
|
||||
context.renderer->openGLContextClosing();
|
||||
|
||||
if (vertexArrayObject != 0)
|
||||
context.extensions.glDeleteVertexArrays (1, &vertexArrayObject);
|
||||
|
||||
associatedObjectNames.clear();
|
||||
associatedObjects.clear();
|
||||
cachedImageFrameBuffer.release();
|
||||
nativeContext->shutdownOnRenderThread();
|
||||
}
|
||||
|
||||
void resume()
|
||||
|
|
@ -375,12 +385,12 @@ public:
|
|||
abortScope = true;
|
||||
}
|
||||
|
||||
if (! contextActivator.activate (context))
|
||||
return RenderStatus::noWork;
|
||||
|
||||
{
|
||||
NativeContext::Locker locker (*nativeContext);
|
||||
|
||||
if (! contextActivator.activate (context))
|
||||
return RenderStatus::noWork;
|
||||
|
||||
JUCE_CHECK_OPENGL_ERROR
|
||||
|
||||
doWorkWhileWaitingForLock (contextActivator);
|
||||
|
|
@ -416,7 +426,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
nativeContext->swapBuffers();
|
||||
bufferSwapper.swap();
|
||||
return RenderStatus::nominal;
|
||||
}
|
||||
|
||||
|
|
@ -520,9 +530,6 @@ public:
|
|||
paintOwner (*g);
|
||||
JUCE_CHECK_OPENGL_ERROR
|
||||
}
|
||||
|
||||
if (! context.isActive())
|
||||
context.makeActive();
|
||||
}
|
||||
|
||||
JUCE_CHECK_OPENGL_ERROR
|
||||
|
|
@ -667,20 +674,6 @@ public:
|
|||
return InitResult::success;
|
||||
}
|
||||
|
||||
void shutdownOnThread()
|
||||
{
|
||||
if (context.renderer != nullptr)
|
||||
context.renderer->openGLContextClosing();
|
||||
|
||||
if (vertexArrayObject != 0)
|
||||
context.extensions.glDeleteVertexArrays (1, &vertexArrayObject);
|
||||
|
||||
associatedObjectNames.clear();
|
||||
associatedObjects.clear();
|
||||
cachedImageFrameBuffer.release();
|
||||
nativeContext->shutdownOnRenderThread();
|
||||
}
|
||||
|
||||
/* Returns true if the context requires a non-zero vertex array object (VAO) to be bound.
|
||||
|
||||
If the context is a compatibility context, we can just pretend that VAOs don't exist,
|
||||
|
|
@ -840,7 +833,6 @@ public:
|
|||
case RenderStatus::nominal: result = RenderStatus::nominal; break;
|
||||
case RenderStatus::messageThreadAborted: return RenderStatus::messageThreadAborted;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
@ -950,6 +942,49 @@ public:
|
|||
#endif
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
class BufferSwapper : private AsyncUpdater
|
||||
{
|
||||
public:
|
||||
explicit BufferSwapper (CachedImage& img)
|
||||
: image (img) {}
|
||||
|
||||
~BufferSwapper() override
|
||||
{
|
||||
cancelPendingUpdate();
|
||||
}
|
||||
|
||||
void swap()
|
||||
{
|
||||
static const auto swapBuffersOnMainThread = []
|
||||
{
|
||||
const auto os = SystemStats::getOperatingSystemType();
|
||||
|
||||
if ((os & SystemStats::MacOSX) != 0)
|
||||
return (os != SystemStats::MacOSX && os < SystemStats::MacOSX_10_14);
|
||||
|
||||
return false;
|
||||
}();
|
||||
|
||||
if (swapBuffersOnMainThread && ! MessageManager::getInstance()->isThisTheMessageThread())
|
||||
triggerAsyncUpdate();
|
||||
else
|
||||
image.nativeContext->swapBuffers();
|
||||
}
|
||||
|
||||
private:
|
||||
void handleAsyncUpdate() override
|
||||
{
|
||||
ScopedContextActivator activator;
|
||||
activator.activate (image.context);
|
||||
|
||||
NativeContext::Locker locker (*image.nativeContext);
|
||||
image.nativeContext->swapBuffers();
|
||||
}
|
||||
|
||||
CachedImage& image;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
friend class NativeContext;
|
||||
std::unique_ptr<NativeContext> nativeContext;
|
||||
|
|
@ -977,6 +1012,7 @@ public:
|
|||
#endif
|
||||
bool textureNpotSupported = false;
|
||||
std::chrono::steady_clock::time_point lastMMLockReleaseTime{};
|
||||
BufferSwapper bufferSwapper { *this };
|
||||
|
||||
#if JUCE_MAC
|
||||
NSView* getCurrentView() const
|
||||
|
|
@ -1055,9 +1091,6 @@ public:
|
|||
pendingDestruction = 1 << 2,
|
||||
initialised = 1 << 3,
|
||||
|
||||
// Flags that may change state after each frame
|
||||
transient = pendingRender | paintComponents,
|
||||
|
||||
// Flags that should retain their state after each frame
|
||||
persistent = initialised | pendingDestruction
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue