Fixed GlContext not being activated if it shares the same address as a previously destroyed GlContext.
This commit is contained in:
parent
acba3e6165
commit
25da9833c2
@ -346,3 +346,14 @@ elseif(SFML_OS_IOS)
|
|||||||
elseif(SFML_OS_ANDROID)
|
elseif(SFML_OS_ANDROID)
|
||||||
target_link_libraries(sfml-window PRIVATE android)
|
target_link_libraries(sfml-window PRIVATE android)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# on some platforms (e.g. Raspberry Pi 3 armhf), GCC requires linking libatomic to use <atomic> features
|
||||||
|
# that aren't supported by native CPU instructions (64-bit atomic operations on 32-bit architecture)
|
||||||
|
if(SFML_COMPILER_GCC)
|
||||||
|
include(CheckCXXSourceCompiles)
|
||||||
|
check_cxx_source_compiles("#include <atomic>
|
||||||
|
int main(){std::atomic_ullong x(1); return x.fetch_add(1);}" ATOMIC_TEST)
|
||||||
|
if(NOT ATOMIC_TEST)
|
||||||
|
target_link_libraries(sfml-window PRIVATE atomic)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
#include <glad/gl.h>
|
#include <glad/gl.h>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <atomic>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
@ -175,15 +176,23 @@ std::recursive_mutex mutex;
|
|||||||
// OpenGL resources counter
|
// OpenGL resources counter
|
||||||
unsigned int resourceCount = 0;
|
unsigned int resourceCount = 0;
|
||||||
|
|
||||||
// This per-thread variable holds the current context for each thread
|
// This structure contains all the state necessary to
|
||||||
thread_local sf::priv::GlContext* currentContext(nullptr);
|
// track current context information for each thread
|
||||||
thread_local unsigned int currentContextTransientCount(0);
|
struct CurrentContext
|
||||||
|
{
|
||||||
|
std::uint64_t id{};
|
||||||
|
sf::priv::GlContext* ptr{};
|
||||||
|
unsigned int transientCount{};
|
||||||
|
};
|
||||||
|
|
||||||
|
// This per-thread variable holds the current context information for each thread
|
||||||
|
thread_local CurrentContext currentContext;
|
||||||
|
|
||||||
// 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;
|
||||||
|
|
||||||
// Unique identifier, used for identifying contexts when managing unshareable OpenGL resources
|
// Unique identifier, used for identifying contexts when managing unshareable OpenGL resources
|
||||||
std::uint64_t id = 1; // start at 1, zero is "no context"
|
std::atomic<std::uint64_t> nextContextId(1); // start at 1, zero is "no context"
|
||||||
|
|
||||||
// Set containing callback functions to be called whenever a
|
// Set containing callback functions to be called whenever a
|
||||||
// context is going to be destroyed
|
// context is going to be destroyed
|
||||||
@ -204,7 +213,7 @@ struct TransientContext
|
|||||||
{
|
{
|
||||||
// TransientContext should never be created if there is
|
// TransientContext should never be created if there is
|
||||||
// already a context active on the current thread
|
// already a context active on the current thread
|
||||||
assert(!currentContext);
|
assert(!currentContext.id);
|
||||||
|
|
||||||
std::unique_lock lock(mutex);
|
std::unique_lock lock(mutex);
|
||||||
|
|
||||||
@ -218,7 +227,7 @@ struct TransientContext
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// GlResources exist, currentContext not yet set
|
// GlResources exist, currentContextId not yet set
|
||||||
assert(sharedContext);
|
assert(sharedContext);
|
||||||
|
|
||||||
// Lock the shared context for temporary use
|
// Lock the shared context for temporary use
|
||||||
@ -411,26 +420,25 @@ void GlContext::registerContextDestroyCallback(ContextDestroyCallback callback,
|
|||||||
void GlContext::acquireTransientContext()
|
void GlContext::acquireTransientContext()
|
||||||
{
|
{
|
||||||
using GlContextImpl::currentContext;
|
using GlContextImpl::currentContext;
|
||||||
using GlContextImpl::currentContextTransientCount;
|
|
||||||
using GlContextImpl::TransientContext;
|
using GlContextImpl::TransientContext;
|
||||||
using GlContextImpl::transientContext;
|
using GlContextImpl::transientContext;
|
||||||
|
|
||||||
// Fast path if we already have a context active on this thread
|
// Fast path if we already have a context active on this thread
|
||||||
if (currentContext)
|
if (currentContext.id)
|
||||||
{
|
{
|
||||||
++currentContextTransientCount;
|
++currentContext.transientCount;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we don't already have a context active on this thread the count should be 0
|
// If we don't already have a context active on this thread the count should be 0
|
||||||
assert(!currentContextTransientCount);
|
assert(!currentContext.transientCount);
|
||||||
|
|
||||||
// If currentContext is not set, this must be the first
|
// If currentContextId is not set, this must be the first
|
||||||
// TransientContextLock on this thread, construct the state object
|
// TransientContextLock on this thread, construct the state object
|
||||||
transientContext.emplace();
|
transientContext.emplace();
|
||||||
|
|
||||||
// Make sure a context is active at this point
|
// Make sure a context is active at this point
|
||||||
assert(currentContext);
|
assert(currentContext.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -438,20 +446,19 @@ void GlContext::acquireTransientContext()
|
|||||||
void GlContext::releaseTransientContext()
|
void GlContext::releaseTransientContext()
|
||||||
{
|
{
|
||||||
using GlContextImpl::currentContext;
|
using GlContextImpl::currentContext;
|
||||||
using GlContextImpl::currentContextTransientCount;
|
|
||||||
using GlContextImpl::transientContext;
|
using GlContextImpl::transientContext;
|
||||||
|
|
||||||
// Make sure a context was left active after acquireTransientContext() was called
|
// Make sure a context was left active after acquireTransientContext() was called
|
||||||
assert(currentContext);
|
assert(currentContext.id);
|
||||||
|
|
||||||
// Fast path if we already had a context active on this thread before acquireTransientContext() was called
|
// Fast path if we already had a context active on this thread before acquireTransientContext() was called
|
||||||
if (currentContextTransientCount)
|
if (currentContext.transientCount)
|
||||||
{
|
{
|
||||||
--currentContextTransientCount;
|
--currentContext.transientCount;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If currentContext is set and currentContextTransientCount is 0,
|
// If currentContextId is set and currentContextTransientCount is 0,
|
||||||
// this is the last TransientContextLock that is released, destroy the state object
|
// this is the last TransientContextLock that is released, destroy the state object
|
||||||
transientContext.reset();
|
transientContext.reset();
|
||||||
}
|
}
|
||||||
@ -611,7 +618,8 @@ GlFunctionPointer GlContext::getFunction(const char* name)
|
|||||||
const GlContext* GlContext::getActiveContext()
|
const GlContext* GlContext::getActiveContext()
|
||||||
{
|
{
|
||||||
using GlContextImpl::currentContext;
|
using GlContextImpl::currentContext;
|
||||||
return currentContext;
|
|
||||||
|
return currentContext.ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -619,7 +627,8 @@ const GlContext* GlContext::getActiveContext()
|
|||||||
std::uint64_t GlContext::getActiveContextId()
|
std::uint64_t GlContext::getActiveContextId()
|
||||||
{
|
{
|
||||||
using GlContextImpl::currentContext;
|
using GlContextImpl::currentContext;
|
||||||
return currentContext ? currentContext->m_id : 0;
|
|
||||||
|
return currentContext.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -627,13 +636,11 @@ std::uint64_t GlContext::getActiveContextId()
|
|||||||
GlContext::~GlContext()
|
GlContext::~GlContext()
|
||||||
{
|
{
|
||||||
using GlContextImpl::currentContext;
|
using GlContextImpl::currentContext;
|
||||||
using GlContextImpl::sharedContext;
|
|
||||||
|
|
||||||
// Deactivate the context before killing it, unless we're inside Cleanup()
|
if (m_id == currentContext.id)
|
||||||
if (sharedContext)
|
|
||||||
{
|
{
|
||||||
if (this == currentContext)
|
currentContext.id = 0;
|
||||||
currentContext = nullptr;
|
currentContext.ptr = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -650,11 +657,10 @@ bool GlContext::setActive(bool active)
|
|||||||
{
|
{
|
||||||
using GlContextImpl::currentContext;
|
using GlContextImpl::currentContext;
|
||||||
using GlContextImpl::mutex;
|
using GlContextImpl::mutex;
|
||||||
using GlContextImpl::sharedContext;
|
|
||||||
|
|
||||||
if (active)
|
if (active)
|
||||||
{
|
{
|
||||||
if (this != currentContext)
|
if (m_id != currentContext.id)
|
||||||
{
|
{
|
||||||
std::lock_guard lock(mutex);
|
std::lock_guard lock(mutex);
|
||||||
|
|
||||||
@ -662,7 +668,8 @@ bool GlContext::setActive(bool active)
|
|||||||
if (makeCurrent(true))
|
if (makeCurrent(true))
|
||||||
{
|
{
|
||||||
// Set it as the new current context for this thread
|
// Set it as the new current context for this thread
|
||||||
currentContext = this;
|
currentContext.id = m_id;
|
||||||
|
currentContext.ptr = this;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -678,14 +685,15 @@ bool GlContext::setActive(bool active)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (this == currentContext)
|
if (m_id == currentContext.id)
|
||||||
{
|
{
|
||||||
std::lock_guard lock(mutex);
|
std::lock_guard lock(mutex);
|
||||||
|
|
||||||
// Deactivate the context
|
// Deactivate the context
|
||||||
if (makeCurrent(false))
|
if (makeCurrent(false))
|
||||||
{
|
{
|
||||||
currentContext = nullptr;
|
currentContext.id = 0;
|
||||||
|
currentContext.ptr = nullptr;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -703,7 +711,7 @@ bool GlContext::setActive(bool active)
|
|||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
GlContext::GlContext() : m_id(GlContextImpl::id++)
|
GlContext::GlContext() : m_id(GlContextImpl::nextContextId.fetch_add(1))
|
||||||
{
|
{
|
||||||
// Nothing to do
|
// Nothing to do
|
||||||
}
|
}
|
||||||
@ -754,10 +762,10 @@ void GlContext::cleanupUnsharedResources()
|
|||||||
using GlContextImpl::currentContext;
|
using GlContextImpl::currentContext;
|
||||||
|
|
||||||
// Save the current context so we can restore it later
|
// Save the current context so we can restore it later
|
||||||
GlContext* contextToRestore = currentContext;
|
GlContext* contextToRestore = currentContext.ptr;
|
||||||
|
|
||||||
// If this context is already active there is no need to save it
|
// If this context is already active there is no need to save it
|
||||||
if (contextToRestore == this)
|
if (m_id == currentContext.id)
|
||||||
contextToRestore = nullptr;
|
contextToRestore = nullptr;
|
||||||
|
|
||||||
// Make this context active so resources can be freed
|
// Make this context active so resources can be freed
|
||||||
|
Loading…
Reference in New Issue
Block a user