summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIvo van Dongen <info@ivovandongen.nl>2017-07-13 15:35:02 +0300
committerIvo van Dongen <info@ivovandongen.nl>2017-07-18 17:06:33 +0200
commit386556b1a4be5ed4d9864fb2870c9b7a6b0da37b (patch)
tree0f4cc6e0ad280eafff1fc757b419ce49b28ce6b2
parent2d147470a5f982afb0c1a63ff632497f85ea85bf (diff)
downloadqtlocation-mapboxgl-386556b1a4be5ed4d9864fb2870c9b7a6b0da37b.tar.gz
[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
-rw-r--r--cmake/test-files.cmake1
-rw-r--r--include/mbgl/map/backend.hpp5
-rw-r--r--include/mbgl/map/backend_scope.hpp4
-rw-r--r--src/mbgl/map/backend_scope.cpp35
-rw-r--r--test/renderer/backend_scope.test.cpp113
5 files changed, 150 insertions, 8 deletions
diff --git a/cmake/test-files.cmake b/cmake/test-files.cmake
index 6026374de6..c29bd284d7 100644
--- a/cmake/test-files.cmake
+++ b/cmake/test-files.cmake
@@ -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
diff --git a/include/mbgl/map/backend.hpp b/include/mbgl/map/backend.hpp
index 884c4b5256..69a998709b 100644
--- a/include/mbgl/map/backend.hpp
+++ b/include/mbgl/map/backend.hpp
@@ -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
diff --git a/include/mbgl/map/backend_scope.hpp b/include/mbgl/map/backend_scope.hpp
index 4985cd197f..322c17b3fc 100644
--- a/include/mbgl/map/backend_scope.hpp
+++ b/include/mbgl/map/backend_scope.hpp
@@ -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
diff --git a/src/mbgl/map/backend_scope.cpp b/src/mbgl/map/backend_scope.cpp
index 824ad4498b..dac90346d7 100644
--- a/src/mbgl/map/backend_scope.cpp
+++ b/src/mbgl/map/backend_scope.cpp
@@ -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();
}
diff --git a/test/renderer/backend_scope.test.cpp b/test/renderer/backend_scope.test.cpp
new file mode 100644
index 0000000000..6afd8f12ed
--- /dev/null
+++ b/test/renderer/backend_scope.test.cpp
@@ -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);
+}