Reduce TransientContextLock overhead if there is already a context active on the current thread.
This commit is contained in:
parent
05d9f2046a
commit
ccda8a9db0
@ -177,6 +177,7 @@ unsigned int resourceCount = 0;
|
|||||||
|
|
||||||
// This per-thread variable holds the current context for each thread
|
// This per-thread variable holds the current context for each thread
|
||||||
thread_local sf::priv::GlContext* currentContext(nullptr);
|
thread_local sf::priv::GlContext* currentContext(nullptr);
|
||||||
|
thread_local unsigned int currentContextTransientCount(0);
|
||||||
|
|
||||||
// The hidden, inactive context that will be shared with all other contexts
|
// The hidden, inactive context that will be shared with all other contexts
|
||||||
std::unique_ptr<ContextType> sharedContext;
|
std::unique_ptr<ContextType> sharedContext;
|
||||||
@ -201,14 +202,27 @@ struct TransientContext
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
TransientContext()
|
TransientContext()
|
||||||
{
|
{
|
||||||
|
// TransientContext should never be created if there is
|
||||||
|
// already a context active on the current thread
|
||||||
|
assert(!currentContext);
|
||||||
|
|
||||||
|
std::unique_lock lock(mutex);
|
||||||
|
|
||||||
if (resourceCount == 0)
|
if (resourceCount == 0)
|
||||||
{
|
{
|
||||||
|
// No GlResources, no shared context yet
|
||||||
|
assert(!sharedContext);
|
||||||
|
|
||||||
|
// Create a Context object for temporary use
|
||||||
context.emplace();
|
context.emplace();
|
||||||
}
|
}
|
||||||
else if (!currentContext)
|
else
|
||||||
{
|
{
|
||||||
sharedContextLock.emplace(mutex);
|
// GlResources exist, currentContext not yet set
|
||||||
useSharedContext = true;
|
assert(sharedContext);
|
||||||
|
|
||||||
|
// Lock the shared context for temporary use
|
||||||
|
sharedContextLock = std::move(lock);
|
||||||
sharedContext->setActive(true);
|
sharedContext->setActive(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -219,7 +233,7 @@ struct TransientContext
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
~TransientContext()
|
~TransientContext()
|
||||||
{
|
{
|
||||||
if (useSharedContext)
|
if (sharedContextLock)
|
||||||
sharedContext->setActive(false);
|
sharedContext->setActive(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -238,10 +252,8 @@ struct TransientContext
|
|||||||
///////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////
|
||||||
// Member data
|
// Member data
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
unsigned int referenceCount{};
|
std::optional<sf::Context> context;
|
||||||
std::optional<sf::Context> context;
|
std::unique_lock<std::recursive_mutex> sharedContextLock;
|
||||||
std::optional<std::lock_guard<std::recursive_mutex>> sharedContextLock;
|
|
||||||
bool useSharedContext{};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// This per-thread variable tracks if and how a transient
|
// This per-thread variable tracks if and how a transient
|
||||||
@ -328,7 +340,6 @@ namespace sf::priv
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
void GlContext::initResource()
|
void GlContext::initResource()
|
||||||
{
|
{
|
||||||
using GlContextImpl::currentContext;
|
|
||||||
using GlContextImpl::loadExtensions;
|
using GlContextImpl::loadExtensions;
|
||||||
using GlContextImpl::mutex;
|
using GlContextImpl::mutex;
|
||||||
using GlContextImpl::resourceCount;
|
using GlContextImpl::resourceCount;
|
||||||
@ -399,44 +410,50 @@ void GlContext::registerContextDestroyCallback(ContextDestroyCallback callback,
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
void GlContext::acquireTransientContext()
|
void GlContext::acquireTransientContext()
|
||||||
{
|
{
|
||||||
using GlContextImpl::mutex;
|
using GlContextImpl::currentContext;
|
||||||
|
using GlContextImpl::currentContextTransientCount;
|
||||||
using GlContextImpl::TransientContext;
|
using GlContextImpl::TransientContext;
|
||||||
using GlContextImpl::transientContext;
|
using GlContextImpl::transientContext;
|
||||||
|
|
||||||
// Protect from concurrent access
|
// Fast path if we already have a context active on this thread
|
||||||
std::lock_guard lock(mutex);
|
if (currentContext)
|
||||||
|
{
|
||||||
|
++currentContextTransientCount;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// If this is the first TransientContextLock on this thread
|
// If we don't already have a context active on this thread the count should be 0
|
||||||
// construct the state object
|
assert(!currentContextTransientCount);
|
||||||
if (!transientContext.has_value())
|
|
||||||
transientContext.emplace();
|
|
||||||
|
|
||||||
// Increase the reference count
|
// If currentContext is not set, this must be the first
|
||||||
++transientContext->referenceCount;
|
// TransientContextLock on this thread, construct the state object
|
||||||
|
transientContext.emplace();
|
||||||
|
|
||||||
|
// Make sure a context is active at this point
|
||||||
|
assert(currentContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
void GlContext::releaseTransientContext()
|
void GlContext::releaseTransientContext()
|
||||||
{
|
{
|
||||||
using GlContextImpl::mutex;
|
using GlContextImpl::currentContext;
|
||||||
|
using GlContextImpl::currentContextTransientCount;
|
||||||
using GlContextImpl::transientContext;
|
using GlContextImpl::transientContext;
|
||||||
|
|
||||||
// Protect from concurrent access
|
// Make sure a context was left active after acquireTransientContext() was called
|
||||||
std::lock_guard lock(mutex);
|
assert(currentContext);
|
||||||
|
|
||||||
// Make sure a matching acquireTransientContext() was called
|
// Fast path if we already had a context active on this thread before acquireTransientContext() was called
|
||||||
assert(transientContext.has_value());
|
if (currentContextTransientCount)
|
||||||
|
|
||||||
// Decrease the reference count
|
|
||||||
--transientContext->referenceCount;
|
|
||||||
|
|
||||||
// If this is the last TransientContextLock that is released
|
|
||||||
// destroy the state object
|
|
||||||
if (transientContext->referenceCount == 0)
|
|
||||||
{
|
{
|
||||||
transientContext.reset();
|
--currentContextTransientCount;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If currentContext is set and currentContextTransientCount is 0,
|
||||||
|
// this is the last TransientContextLock that is released, destroy the state object
|
||||||
|
transientContext.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user