[core] BackendScope prevent double (de-)activation
- Guards against duplicate activations by checking wether the backend of the prior scope is the same as the current ones - Makes sure that only the most outer backend scope deactivates by tracking activation state
This commit is contained in:
committed by
Ivo van Dongen
parent
2d147470a5
commit
733661948c
@@ -42,6 +42,7 @@ set(MBGL_TEST_FILES
|
||||
test/programs/binary_program.test.cpp
|
||||
|
||||
# renderer
|
||||
test/renderer/backend_scope.test.cpp
|
||||
test/renderer/group_by_layout.test.cpp
|
||||
|
||||
# sprite
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <mbgl/map/map_observer.hpp>
|
||||
#include <mbgl/util/image.hpp>
|
||||
#include <mbgl/util/size.hpp>
|
||||
#include <mbgl/util/util.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
@@ -80,4 +81,8 @@ private:
|
||||
friend class BackendScope;
|
||||
};
|
||||
|
||||
constexpr bool operator==(const Backend& a, const Backend& b) {
|
||||
return &a == &b;
|
||||
}
|
||||
|
||||
} // namespace mbgl
|
||||
|
||||
@@ -22,10 +22,14 @@ public:
|
||||
static bool exists();
|
||||
|
||||
private:
|
||||
void activate();
|
||||
void deactivate();
|
||||
|
||||
BackendScope* priorScope;
|
||||
BackendScope* nextScope;
|
||||
Backend& backend;
|
||||
const ScopeType scopeType;
|
||||
bool activated = false;
|
||||
};
|
||||
|
||||
} // namespace mbgl
|
||||
|
||||
@@ -16,30 +16,49 @@ BackendScope::BackendScope(Backend& backend_, ScopeType scopeType_)
|
||||
if (priorScope) {
|
||||
assert(priorScope->nextScope == nullptr);
|
||||
priorScope->nextScope = this;
|
||||
priorScope->deactivate();
|
||||
}
|
||||
if (scopeType == ScopeType::Explicit) {
|
||||
backend.activate();
|
||||
}
|
||||
|
||||
activate();
|
||||
|
||||
currentScope.set(this);
|
||||
}
|
||||
|
||||
BackendScope::~BackendScope() {
|
||||
assert(nextScope == nullptr);
|
||||
deactivate();
|
||||
|
||||
if (priorScope) {
|
||||
priorScope->backend.activate();
|
||||
priorScope->activate();
|
||||
currentScope.set(priorScope);
|
||||
assert(priorScope->nextScope == this);
|
||||
priorScope->nextScope = nullptr;
|
||||
} else {
|
||||
if (scopeType == ScopeType::Explicit) {
|
||||
backend.deactivate();
|
||||
}
|
||||
|
||||
currentScope.set(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void BackendScope::activate() {
|
||||
if (scopeType == ScopeType::Explicit &&
|
||||
!(priorScope && this->backend == priorScope->backend) &&
|
||||
!(nextScope && this->backend == nextScope->backend)) {
|
||||
// Only activate when set to Explicit and
|
||||
// only once per RenderBackend
|
||||
backend.activate();
|
||||
activated = true;
|
||||
}
|
||||
}
|
||||
|
||||
void BackendScope::deactivate() {
|
||||
if (activated &&
|
||||
!(nextScope && this->backend == nextScope->backend)) {
|
||||
// Only deactivate when set to Explicit and
|
||||
// only once per RenderBackend
|
||||
backend.deactivate();
|
||||
activated = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool BackendScope::exists() {
|
||||
return currentScope.get();
|
||||
}
|
||||
|
||||
113
test/renderer/backend_scope.test.cpp
Normal file
113
test/renderer/backend_scope.test.cpp
Normal file
@@ -0,0 +1,113 @@
|
||||
#include <mbgl/test/util.hpp>
|
||||
|
||||
#include <mbgl/map/backend.hpp>
|
||||
#include <mbgl/map/backend_scope.hpp>
|
||||
|
||||
#include <functional>
|
||||
|
||||
using namespace mbgl;
|
||||
|
||||
class StubBackend: public Backend {
|
||||
public:
|
||||
|
||||
void activate() override {
|
||||
if (activateFunction) activateFunction();
|
||||
}
|
||||
|
||||
void deactivate() override {
|
||||
if (deactivateFunction) deactivateFunction();
|
||||
}
|
||||
|
||||
void updateAssumedState() override {
|
||||
if (updateAssumedStateFunction) updateAssumedStateFunction();
|
||||
}
|
||||
|
||||
void invalidate() override {}
|
||||
|
||||
gl::ProcAddress initializeExtension(const char* ext) override {
|
||||
if (initializeExtensionFunction) {
|
||||
return initializeExtensionFunction(ext);
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
std::function<void ()> activateFunction;
|
||||
std::function<void ()> deactivateFunction;
|
||||
std::function<void ()> updateAssumedStateFunction;
|
||||
std::function<gl::ProcAddress (const char*)> initializeExtensionFunction;
|
||||
};
|
||||
|
||||
// A scope should activate on construction
|
||||
// and deactivate on descruction (going out
|
||||
// of scope)
|
||||
TEST(BackendScope, SingleScope) {
|
||||
bool activated;
|
||||
bool deactivated;
|
||||
|
||||
StubBackend backend;
|
||||
backend.activateFunction = [&] { activated = true; };
|
||||
backend.deactivateFunction = [&] { deactivated = true; };
|
||||
|
||||
{
|
||||
BackendScope test { backend };
|
||||
}
|
||||
|
||||
ASSERT_TRUE(activated);
|
||||
ASSERT_TRUE(deactivated);
|
||||
}
|
||||
|
||||
// With nested scopes, only the outer scope
|
||||
// should activate/deactivate
|
||||
TEST(BackendScope, NestedScopes) {
|
||||
int activated = 0;
|
||||
int deactivated = 0;
|
||||
|
||||
StubBackend backend;
|
||||
backend.activateFunction = [&] { activated++; };
|
||||
backend.deactivateFunction = [&] { deactivated++; };
|
||||
|
||||
{
|
||||
BackendScope outer { backend };
|
||||
ASSERT_EQ(1, activated);
|
||||
{
|
||||
BackendScope inner { backend };
|
||||
ASSERT_EQ(1, activated);
|
||||
}
|
||||
ASSERT_EQ(0, deactivated);
|
||||
}
|
||||
|
||||
ASSERT_EQ(1, deactivated);
|
||||
}
|
||||
|
||||
// With chained scopes, where scopes have
|
||||
// different backends, the scopes should each
|
||||
// activate the scope on entering and de-activating
|
||||
// on leaving the scope
|
||||
TEST(BackendScope, ChainedScopes) {
|
||||
bool activatedA = false;
|
||||
bool activatedB = false;
|
||||
|
||||
StubBackend backendA;
|
||||
backendA.activateFunction = [&] { activatedA = true; };
|
||||
backendA.deactivateFunction = [&] { activatedA = false; };
|
||||
|
||||
StubBackend backendB;
|
||||
backendB.activateFunction = [&] { activatedB = true; };
|
||||
backendB.deactivateFunction = [&] { activatedB = false; };
|
||||
|
||||
{
|
||||
BackendScope scopeA { backendA };
|
||||
ASSERT_TRUE(activatedA);
|
||||
{
|
||||
BackendScope scopeB { backendB };
|
||||
ASSERT_FALSE(activatedA);
|
||||
ASSERT_TRUE(activatedB);
|
||||
}
|
||||
ASSERT_FALSE(activatedB);
|
||||
ASSERT_TRUE(activatedA);
|
||||
}
|
||||
|
||||
ASSERT_FALSE(activatedA);
|
||||
ASSERT_FALSE(activatedB);
|
||||
}
|
||||
Reference in New Issue
Block a user