Correct and revise OpenGL texture pooling (#2709)
This commit is contained in:
@@ -111,6 +111,7 @@ add_library(
|
||||
${PROJECT_SOURCE_DIR}/test/util/token.test.cpp
|
||||
${PROJECT_SOURCE_DIR}/test/util/url.test.cpp
|
||||
${PROJECT_SOURCE_DIR}/test/util/tile_server_options.test.cpp
|
||||
${PROJECT_SOURCE_DIR}/test/util/lru_cache.test.cpp
|
||||
)
|
||||
|
||||
# MapSnapshotter uses headless backend that is rendering image on a background thread. QT / macOS adaptation for headless backend creates
|
||||
@@ -135,6 +136,7 @@ if(MLN_WITH_OPENGL)
|
||||
${PROJECT_SOURCE_DIR}/test/gl/context.test.cpp
|
||||
${PROJECT_SOURCE_DIR}/test/gl/gl_functions.test.cpp
|
||||
${PROJECT_SOURCE_DIR}/test/gl/object.test.cpp
|
||||
${PROJECT_SOURCE_DIR}/test/gl/resource_pool.test.cpp
|
||||
${PROJECT_SOURCE_DIR}/test/renderer/backend_scope.test.cpp
|
||||
${PROJECT_SOURCE_DIR}/test/util/offscreen_texture.test.cpp
|
||||
)
|
||||
|
||||
@@ -55,17 +55,22 @@ TEST(GLObject, Store) {
|
||||
gl::Context context{backend};
|
||||
EXPECT_TRUE(context.empty());
|
||||
|
||||
gl::UniqueTexture texture = context.createUniqueTexture();
|
||||
gl::UniqueTexture texture = context.createUniqueTexture(
|
||||
{8, 8}, gfx::TexturePixelType::RGBA, gfx::TextureChannelDataType::UnsignedByte);
|
||||
EXPECT_NE(texture.get(), 0u);
|
||||
texture.reset();
|
||||
EXPECT_FALSE(context.empty());
|
||||
EXPECT_FALSE(context.empty(false));
|
||||
EXPECT_FALSE(context.empty(true));
|
||||
context.performCleanup();
|
||||
EXPECT_FALSE(context.empty());
|
||||
EXPECT_TRUE(context.empty(false));
|
||||
EXPECT_FALSE(context.empty(true));
|
||||
context.reset();
|
||||
EXPECT_TRUE(context.empty());
|
||||
EXPECT_TRUE(context.empty(false));
|
||||
EXPECT_TRUE(context.empty(true));
|
||||
|
||||
context.reset();
|
||||
EXPECT_TRUE(context.empty());
|
||||
EXPECT_TRUE(context.empty(false));
|
||||
EXPECT_TRUE(context.empty(true));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
123
test/gl/resource_pool.test.cpp
Normal file
123
test/gl/resource_pool.test.cpp
Normal file
@@ -0,0 +1,123 @@
|
||||
#if MLN_RENDER_BACKEND_OPENGL
|
||||
#include <mbgl/test/util.hpp>
|
||||
|
||||
#include <unordered_set>
|
||||
|
||||
#include <mbgl/gfx/backend_scope.hpp>
|
||||
#include <mbgl/gfx/types.hpp>
|
||||
#include <mbgl/gl/headless_backend.hpp>
|
||||
#include <mbgl/gl/context.hpp>
|
||||
|
||||
using namespace mbgl;
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr auto oneMB = 1024 * 1024;
|
||||
|
||||
constexpr gl::Texture2DDesc makeDescOneMB() {
|
||||
return {{1024, 1024}, gfx::TexturePixelType::Luminance, gfx::TextureChannelDataType::UnsignedByte};
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(ResourcePool, TexturePool) {
|
||||
gl::HeadlessBackend backend{{32, 32}};
|
||||
gfx::BackendScope scope{backend};
|
||||
|
||||
gl::Context context{backend};
|
||||
EXPECT_TRUE(context.empty(true));
|
||||
|
||||
auto& pool = context.getTexturePool();
|
||||
EXPECT_LE(oneMB, pool.maxStorage());
|
||||
|
||||
EXPECT_EQ(pool.usedStorage(), 0);
|
||||
EXPECT_EQ(pool.unusedStorage(), 0);
|
||||
EXPECT_EQ(pool.storage(), 0);
|
||||
EXPECT_FALSE(pool.isUsed(3));
|
||||
EXPECT_FALSE(pool.isUnused(3));
|
||||
EXPECT_FALSE(pool.isPooled(3));
|
||||
|
||||
auto id = pool.alloc(makeDescOneMB());
|
||||
EXPECT_EQ(pool.usedStorage(), oneMB);
|
||||
EXPECT_EQ(pool.unusedStorage(), 0);
|
||||
EXPECT_EQ(pool.storage(), oneMB);
|
||||
EXPECT_TRUE(pool.isUsed(id));
|
||||
EXPECT_FALSE(pool.isUnused(id));
|
||||
EXPECT_TRUE(pool.isPooled(id));
|
||||
|
||||
pool.release(id);
|
||||
EXPECT_EQ(pool.usedStorage(), 0u);
|
||||
EXPECT_EQ(pool.unusedStorage(), oneMB);
|
||||
EXPECT_EQ(pool.storage(), oneMB);
|
||||
EXPECT_FALSE(pool.isUsed(id));
|
||||
EXPECT_TRUE(pool.isUnused(id));
|
||||
EXPECT_TRUE(pool.isPooled(id));
|
||||
|
||||
auto reused_id = pool.alloc(makeDescOneMB());
|
||||
EXPECT_EQ(reused_id, id);
|
||||
EXPECT_EQ(pool.usedStorage(), oneMB);
|
||||
EXPECT_EQ(pool.unusedStorage(), 0);
|
||||
EXPECT_EQ(pool.storage(), oneMB);
|
||||
EXPECT_TRUE(pool.isUsed(id));
|
||||
EXPECT_FALSE(pool.isUnused(id));
|
||||
EXPECT_TRUE(pool.isPooled(id));
|
||||
|
||||
std::unordered_set<gl::TextureID> ids = {id};
|
||||
while (pool.storage() <= pool.maxStorage()) {
|
||||
auto new_id = pool.alloc(makeDescOneMB());
|
||||
EXPECT_TRUE(ids.find(new_id) == ids.end());
|
||||
ids.insert(new_id);
|
||||
EXPECT_EQ(pool.usedStorage(), oneMB * ids.size());
|
||||
EXPECT_EQ(pool.unusedStorage(), 0);
|
||||
EXPECT_EQ(pool.storage(), pool.usedStorage());
|
||||
EXPECT_TRUE(pool.isUsed(new_id));
|
||||
EXPECT_FALSE(pool.isUnused(new_id));
|
||||
EXPECT_TRUE(pool.isPooled(new_id));
|
||||
}
|
||||
|
||||
EXPECT_LE(pool.maxStorage(), pool.usedStorage());
|
||||
EXPECT_EQ(pool.usedStorage(), oneMB * ids.size());
|
||||
EXPECT_EQ(pool.unusedStorage(), 0);
|
||||
EXPECT_EQ(pool.storage(), pool.usedStorage());
|
||||
EXPECT_TRUE(pool.isUsed(id));
|
||||
EXPECT_FALSE(pool.isUnused(id));
|
||||
EXPECT_TRUE(pool.isPooled(id));
|
||||
|
||||
pool.release(id);
|
||||
ids.erase(id);
|
||||
EXPECT_GE(pool.maxStorage(), pool.usedStorage());
|
||||
EXPECT_EQ(pool.usedStorage(), oneMB * ids.size());
|
||||
EXPECT_EQ(pool.unusedStorage(), 0);
|
||||
EXPECT_EQ(pool.storage(), pool.usedStorage());
|
||||
EXPECT_FALSE(pool.isUsed(id));
|
||||
EXPECT_FALSE(pool.isUnused(id));
|
||||
EXPECT_FALSE(pool.isPooled(id));
|
||||
|
||||
size_t used = pool.usedStorage();
|
||||
size_t unused = 0;
|
||||
while (!ids.empty()) {
|
||||
auto i = *ids.begin();
|
||||
pool.release(i);
|
||||
ids.erase(i);
|
||||
used -= oneMB;
|
||||
unused += oneMB;
|
||||
EXPECT_EQ(pool.usedStorage(), used);
|
||||
EXPECT_EQ(pool.unusedStorage(), unused);
|
||||
EXPECT_EQ(pool.storage(), used + unused);
|
||||
EXPECT_FALSE(pool.isUsed(i));
|
||||
EXPECT_TRUE(pool.isUnused(i));
|
||||
EXPECT_TRUE(pool.isPooled(i));
|
||||
}
|
||||
|
||||
context.reduceMemoryUsage();
|
||||
context.renderingStats().numActiveTextures = 0;
|
||||
EXPECT_EQ(pool.usedStorage(), 0);
|
||||
EXPECT_EQ(pool.unusedStorage(), 0);
|
||||
EXPECT_EQ(pool.storage(), 0);
|
||||
EXPECT_FALSE(pool.isUsed(id));
|
||||
EXPECT_FALSE(pool.isUnused(id));
|
||||
EXPECT_FALSE(pool.isPooled(id));
|
||||
EXPECT_TRUE(context.empty(true));
|
||||
}
|
||||
|
||||
#endif
|
||||
38
test/util/lru_cache.test.cpp
Normal file
38
test/util/lru_cache.test.cpp
Normal file
@@ -0,0 +1,38 @@
|
||||
#include <mbgl/util/lru_cache.hpp>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
using namespace mbgl;
|
||||
|
||||
TEST(LRU, LRU) {
|
||||
LRU<int> lru;
|
||||
EXPECT_TRUE(lru.empty());
|
||||
|
||||
lru.touch(1);
|
||||
lru.touch(2);
|
||||
lru.touch(3);
|
||||
EXPECT_FALSE(lru.empty());
|
||||
EXPECT_EQ(lru.size(), 3);
|
||||
|
||||
lru.remove(2);
|
||||
lru.remove(77);
|
||||
EXPECT_EQ(lru.evict(), 1);
|
||||
EXPECT_FALSE(lru.empty());
|
||||
EXPECT_EQ(lru.size(), 1);
|
||||
|
||||
lru.touch(4);
|
||||
EXPECT_EQ(lru.evict(), 3);
|
||||
EXPECT_FALSE(lru.empty());
|
||||
EXPECT_EQ(lru.size(), 1);
|
||||
|
||||
EXPECT_FALSE(lru.isHit(3));
|
||||
EXPECT_FALSE(lru.isHit(33));
|
||||
EXPECT_TRUE(lru.isHit(4));
|
||||
|
||||
EXPECT_EQ(lru.evict(), 4);
|
||||
EXPECT_TRUE(lru.empty());
|
||||
EXPECT_FALSE(lru.isHit(4));
|
||||
EXPECT_THROW(lru.evict(), std::runtime_error);
|
||||
}
|
||||
Reference in New Issue
Block a user