Correct and revise OpenGL texture pooling (#2709)

This commit is contained in:
alasram
2024-08-29 14:13:26 -07:00
committed by GitHub
parent 290bf927f5
commit b850c257a3
79 changed files with 817 additions and 247 deletions

View File

@@ -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
)

View File

@@ -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

View 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

View 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);
}