1
0
Fork 0
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:
reuk 2023-02-22 19:15:56 +00:00
parent 6df7e46e26
commit c08a1827b5
No known key found for this signature in database
GPG key ID: FCB43929F012EE5C

View file

@ -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
};