diff options
Diffstat (limited to 'src/mbgl/gl')
-rw-r--r-- | src/mbgl/gl/debugging.cpp | 2 | ||||
-rw-r--r-- | src/mbgl/gl/gl.cpp | 236 | ||||
-rw-r--r-- | src/mbgl/gl/gl_config.cpp | 24 | ||||
-rw-r--r-- | src/mbgl/gl/gl_config.hpp | 100 | ||||
-rw-r--r-- | src/mbgl/gl/gl_object_store.cpp | 120 | ||||
-rw-r--r-- | src/mbgl/gl/gl_object_store.hpp | 141 | ||||
-rw-r--r-- | src/mbgl/gl/texture_pool.cpp | 41 | ||||
-rw-r--r-- | src/mbgl/gl/texture_pool.hpp | 41 |
8 files changed, 704 insertions, 1 deletions
diff --git a/src/mbgl/gl/debugging.cpp b/src/mbgl/gl/debugging.cpp index fb9e037714..e61de42bc3 100644 --- a/src/mbgl/gl/debugging.cpp +++ b/src/mbgl/gl/debugging.cpp @@ -1,5 +1,5 @@ #include <mbgl/gl/debugging.hpp> -#include <mbgl/platform/gl.hpp> +#include <mbgl/gl/gl.hpp> #include <mbgl/platform/event.hpp> #include <mbgl/platform/log.hpp> diff --git a/src/mbgl/gl/gl.cpp b/src/mbgl/gl/gl.cpp new file mode 100644 index 0000000000..c57717aa87 --- /dev/null +++ b/src/mbgl/gl/gl.cpp @@ -0,0 +1,236 @@ +#include <mbgl/gl/gl.hpp> +#include <mbgl/util/string.hpp> +#include <mbgl/platform/log.hpp> + +#include <cassert> +#include <iostream> +#include <map> +#include <mutex> + +namespace mbgl { +namespace gl { + +std::vector<ExtensionFunctionBase*>& ExtensionFunctionBase::functions() { + static std::vector<ExtensionFunctionBase*> functions; + return functions; +} + +static std::once_flag initializeExtensionsOnce; + +void InitializeExtensions(glProc (*getProcAddress)(const char *)) { + std::call_once(initializeExtensionsOnce, [getProcAddress] { + const char * extensionsPtr = reinterpret_cast<const char *>( + MBGL_CHECK_ERROR(glGetString(GL_EXTENSIONS))); + + if (!extensionsPtr) + return; + + const std::string extensions = extensionsPtr; + for (auto fn : ExtensionFunctionBase::functions()) { + for (auto probe : fn->probes) { + if (extensions.find(probe.first) != std::string::npos) { +#ifdef GL_TRACK + fn->foundName = probe.second; +#endif + fn->ptr = getProcAddress(probe.second); + break; + } + } + } + }); +} + +void checkError(const char *cmd, const char *file, int line) { + const GLenum err = glGetError(); + if (err != GL_NO_ERROR) { + const char *error = nullptr; + switch (err) { + case GL_INVALID_ENUM: error = "INVALID_ENUM"; break; + case GL_INVALID_VALUE: error = "INVALID_VALUE"; break; + case GL_INVALID_OPERATION: error = "INVALID_OPERATION"; break; + case GL_INVALID_FRAMEBUFFER_OPERATION: error = "INVALID_FRAMEBUFFER_OPERATION"; break; + case GL_OUT_OF_MEMORY: error = "OUT_OF_MEMORY"; break; +#ifdef GL_STACK_UNDERFLOW + case GL_STACK_UNDERFLOW: error = "STACK_UNDERFLOW"; break; +#endif +#ifdef GL_STACK_OVERFLOW + case GL_STACK_OVERFLOW: error = "STACK_OVERFLOW"; break; +#endif + default: error = "(unknown)"; break; + } + + throw ::mbgl::gl::Error(err, std::string(cmd) + ": Error GL_" + error + " - " + file + ":" + util::toString(line)); + } +} +} // namespace gl +} // namespace mbgl + +#ifdef GL_TRACK +#undef glBindTexture +#undef glDeleteTextures +#undef glTexImage2D +#undef glClear +#undef glShaderSource +#undef glBufferData +#undef glBindBuffer +#undef glDeleteBuffers +#undef glBufferData +static unsigned int currentUsedBytes = 0; +static GLint currentBoundTexture = 0; +static std::map<GLint, unsigned int> bindingToSizeMap; + +static GLuint currentArrayBuffer = 0; +static GLuint currentElementArrayBuffer = 0; +static std::map<GLint, GLsizeiptr> bufferBindingToSizeMap; +static unsigned int currentUsedBufferBytes = 0; +static unsigned int largestAmountUsedSoFar = 0; + +static std::map<GLuint, GLuint> vertexArrayToArrayBufferMap; +static GLuint currentVertexArray = 0; + +static std::mutex gDebugMutex; + +namespace mbgl { + namespace gl { + void mbx_trapExtension(const char *) { } + void mbx_trapExtension(const char *, GLint, const char *) { } + void mbx_trapExtension(const char *, GLsizei, GLuint *) { } + void mbx_trapExtension(const char *, GLsizei, const GLuint *) { } + void mbx_trapExtension(const char *, GLenum, GLenum, GLenum, GLsizei, const GLuint *, GLboolean) { } + void mbx_trapExtension(const char *, GLenum, GLuint, GLsizei, const GLchar *) { } + void mbx_trapExtension(const char *, GLDEBUGPROC, const void *) { } + void mbx_trapExtension(const char *, GLuint, GLuint, GLuint, GLuint, GLint, const char *, const void*) { } + + void mbx_trapExtension(const char *name, GLuint array) { + if(strncasecmp(name, "glBindVertexArray", 17) == 0) { + currentVertexArray = array; + std::cout << name << ": " << array << std::endl; + } + } + } +} + +void mbx_glBindBuffer(GLenum target, + GLuint buffer) { + std::unique_lock<std::mutex> lock(gDebugMutex); + if (target == GL_ARRAY_BUFFER) { + currentArrayBuffer = buffer; + if (currentVertexArray != 0) { + if (vertexArrayToArrayBufferMap.find(currentVertexArray) != vertexArrayToArrayBufferMap.end()) { + if (vertexArrayToArrayBufferMap[currentVertexArray] != currentArrayBuffer) { + std::cout << "glBindBuffer: ERROR: You are re-binding a VAO to point to a new array buffer. This is almost certainly unintended." << std::endl; + } + } + std::cout << "glBindBuffer: binding VAO " << currentVertexArray << " to array buffer " << currentArrayBuffer << std::endl; + vertexArrayToArrayBufferMap[currentVertexArray] = currentArrayBuffer; + } + } else if (target == GL_ELEMENT_ARRAY_BUFFER) { + currentElementArrayBuffer = buffer; + } + lock.unlock(); + glBindBuffer(target, buffer); +} + +void mbx_glDeleteBuffers(GLsizei n, + const GLuint * buffers) { + std::unique_lock<std::mutex> lock(gDebugMutex); + for (int i = 0; i < n; ++i) { + if (bufferBindingToSizeMap.find(buffers[i]) != bufferBindingToSizeMap.end()) { + currentUsedBufferBytes -= bufferBindingToSizeMap[buffers[i]]; + std::cout << "GL glDeleteBuffers: " << buffers[i] << " freeing " << bufferBindingToSizeMap[buffers[i]] << " bytes current total " << currentUsedBufferBytes << "\n"; + bufferBindingToSizeMap.erase(buffers[i]); + } + } + lock.unlock(); + glDeleteBuffers(n, buffers); +} + +void mbx_glBufferData(GLenum target, + GLsizeiptr size, + const GLvoid * data, + GLenum usage) { + std::unique_lock<std::mutex> lock(gDebugMutex); + GLuint currentBinding = 0; + if (target == GL_ARRAY_BUFFER) { + currentBinding = currentArrayBuffer; + } else if (target == GL_ELEMENT_ARRAY_BUFFER) { + currentBinding = currentElementArrayBuffer; + } + if (bufferBindingToSizeMap.find(currentBinding) != bufferBindingToSizeMap.end()) { + currentUsedBufferBytes -= bufferBindingToSizeMap[currentBinding]; + std::cout << "GL glBufferData: " << currentBinding << " freeing " << bufferBindingToSizeMap[currentBinding] << " bytes current total " << currentUsedBufferBytes << "\n"; + } + bufferBindingToSizeMap[currentBinding] = size; + currentUsedBufferBytes += size; + if (currentUsedBufferBytes > largestAmountUsedSoFar) { + largestAmountUsedSoFar = currentUsedBufferBytes; + } + std::cout << "GL glBufferData: " << currentBinding << " using " << bufferBindingToSizeMap[currentBinding] << " bytes current total " << currentUsedBufferBytes << " high water mark " << largestAmountUsedSoFar << "\n"; + lock.unlock(); + + glBufferData(target, size, data, usage); +} + + +void mbx_glShaderSource(GLuint shader, + GLsizei count, + const GLchar * const *string, + const GLint *length) { + //std::cout << "Calling glShaderSource: " << *string << std::endl; + glShaderSource(shader, count, const_cast<const GLchar **>(string), length); +} + +void mbx_glClear(GLbitfield mask) { + //std::cout << "Calling glClear" << std::endl; + glClear(mask); +} + +void mbx_glBindTexture( GLenum target, + GLuint texture) { + std::unique_lock<std::mutex> lock(gDebugMutex); + if (target == GL_TEXTURE_2D) { + currentBoundTexture = texture; + } + lock.unlock(); + glBindTexture(target, texture); +} + +void mbx_glDeleteTextures(GLsizei n, + const GLuint * textures) { + std::unique_lock<std::mutex> lock(gDebugMutex); + for (int i = 0; i < n; ++i) { + if (bindingToSizeMap.find(textures[i]) != bindingToSizeMap.end()) { + std::cout << "GL deleteTexture:" << textures[i] << "freeing " << bindingToSizeMap[textures[i]] << " bytes current total " << currentUsedBytes << "\n"; + currentUsedBytes -= bindingToSizeMap[textures[i]]; + bindingToSizeMap.erase(textures[i]); + } + } + lock.unlock(); + glDeleteTextures(n, textures); +} + +void mbx_glTexImage2D(GLenum target, + GLint level, + GLint internalformat, + GLsizei width, + GLsizei height, + GLint border, + GLenum format, + GLenum type, + const GLvoid * data) { + std::unique_lock<std::mutex> lock(gDebugMutex); + if (internalformat == GL_RGBA && + type == GL_UNSIGNED_BYTE) { + if (bindingToSizeMap.find(currentBoundTexture) != bindingToSizeMap.end()) { + currentUsedBytes -= bindingToSizeMap[currentBoundTexture]; + std::cout << "GL glTexImage2D: " << currentBoundTexture << " freeing " << bindingToSizeMap[currentBoundTexture] << " bytes current total " << currentUsedBytes << "\n"; + } + bindingToSizeMap[currentBoundTexture] = width * height * 4; + currentUsedBytes += bindingToSizeMap[currentBoundTexture]; + std::cout << "GL glTexImage2D: " << currentBoundTexture << " freeing " << bindingToSizeMap[currentBoundTexture] << " bytes current total " << currentUsedBytes << "\n"; + } + lock.unlock(); + glTexImage2D(target, level, internalformat, width, height, border, format, type, data); +} +#endif + diff --git a/src/mbgl/gl/gl_config.cpp b/src/mbgl/gl/gl_config.cpp new file mode 100644 index 0000000000..4160ae100e --- /dev/null +++ b/src/mbgl/gl/gl_config.cpp @@ -0,0 +1,24 @@ +#include "gl_config.hpp" + +namespace mbgl { +namespace gl { + +const StencilFunc::Type StencilFunc::Default = { GL_ALWAYS, 0, ~0u }; +const StencilMask::Type StencilMask::Default = ~0u; +const StencilTest::Type StencilTest::Default = GL_FALSE; +const StencilOp::Type StencilOp::Default = { GL_KEEP, GL_KEEP, GL_REPLACE }; +const DepthRange::Type DepthRange::Default = { 0, 1 }; +const DepthMask::Type DepthMask::Default = GL_TRUE; +const DepthTest::Type DepthTest::Default = GL_FALSE; +const DepthFunc::Type DepthFunc::Default = GL_LEQUAL; +const Blend::Type Blend::Default = GL_TRUE; +const BlendFunc::Type BlendFunc::Default = { GL_ONE, GL_ONE_MINUS_SRC_ALPHA }; +const ColorMask::Type ColorMask::Default = { GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE }; +const ClearDepth::Type ClearDepth::Default = 1; +const ClearColor::Type ClearColor::Default = { 0, 0, 0, 0 }; +const ClearStencil::Type ClearStencil::Default = 0; +const Program::Type Program::Default = 0; +const LineWidth::Type LineWidth::Default = 1; + +} // namespace gl +} // namespace mbgl diff --git a/src/mbgl/gl/gl_config.hpp b/src/mbgl/gl/gl_config.hpp new file mode 100644 index 0000000000..af373fc3f8 --- /dev/null +++ b/src/mbgl/gl/gl_config.hpp @@ -0,0 +1,100 @@ +#ifndef MBGL_GL_GL_CONFIG +#define MBGL_GL_GL_CONFIG + +#include <cstdint> +#include <tuple> +#include <array> + +#include <mbgl/gl/gl_values.hpp> + +namespace mbgl { +namespace gl { + +template <typename T> +class Value { +public: + inline void operator=(const typename T::Type& value) { + if (dirty || current != value) { + dirty = false; + current = value; + T::Set(current); + } + } + + inline void reset() { + dirty = true; + current = T::Default; + T::Set(current); + } + + inline void setDirty() { + dirty = true; + } + +private: + typename T::Type current = T::Default; + bool dirty = false; +}; + +class Config { +public: + void reset() { + stencilFunc.reset(); + stencilMask.reset(); + stencilTest.reset(); + stencilOp.reset(); + depthRange.reset(); + depthMask.reset(); + depthTest.reset(); + depthFunc.reset(); + blend.reset(); + blendFunc.reset(); + colorMask.reset(); + clearDepth.reset(); + clearColor.reset(); + clearStencil.reset(); + program.reset(); + lineWidth.reset(); + } + + void setDirty() { + stencilFunc.setDirty(); + stencilMask.setDirty(); + stencilTest.setDirty(); + stencilOp.setDirty(); + depthRange.setDirty(); + depthMask.setDirty(); + depthTest.setDirty(); + depthFunc.setDirty(); + blend.setDirty(); + blendFunc.setDirty(); + colorMask.setDirty(); + clearDepth.setDirty(); + clearColor.setDirty(); + clearStencil.setDirty(); + program.setDirty(); + lineWidth.setDirty(); + } + + Value<StencilFunc> stencilFunc; + Value<StencilMask> stencilMask; + Value<StencilTest> stencilTest; + Value<StencilOp> stencilOp; + Value<DepthRange> depthRange; + Value<DepthMask> depthMask; + Value<DepthTest> depthTest; + Value<DepthFunc> depthFunc; + Value<Blend> blend; + Value<BlendFunc> blendFunc; + Value<ColorMask> colorMask; + Value<ClearDepth> clearDepth; + Value<ClearColor> clearColor; + Value<ClearStencil> clearStencil; + Value<Program> program; + Value<LineWidth> lineWidth; +}; + +} // namespace gl +} // namespace mbgl + +#endif // MBGL_RENDERER_GL_CONFIG diff --git a/src/mbgl/gl/gl_object_store.cpp b/src/mbgl/gl/gl_object_store.cpp new file mode 100644 index 0000000000..4948e20694 --- /dev/null +++ b/src/mbgl/gl/gl_object_store.cpp @@ -0,0 +1,120 @@ +#include <mbgl/gl/gl_object_store.hpp> + +#include <cassert> + +namespace mbgl { +namespace gl { + +void ProgramHolder::create(GLObjectStore& objectStore_) { + if (id) return; + objectStore = &objectStore_; + id = MBGL_CHECK_ERROR(glCreateProgram()); +} + +void ProgramHolder::reset() { + if (!id) return; + objectStore->abandonedPrograms.push_back(id); + id = 0; +} + +void ShaderHolder::create(GLObjectStore& objectStore_) { + if (id) return; + objectStore = &objectStore_; + id = MBGL_CHECK_ERROR(glCreateShader(type)); +} + +void ShaderHolder::reset() { + if (!id) return; + objectStore->abandonedShaders.push_back(id); + id = 0; +} + +void BufferHolder::create(GLObjectStore& objectStore_) { + if (id) return; + objectStore = &objectStore_; + MBGL_CHECK_ERROR(glGenBuffers(1, &id)); +} + +void BufferHolder::reset() { + if (!id) return; + objectStore->abandonedBuffers.push_back(id); + id = 0; +} + +void TextureHolder::create(GLObjectStore& objectStore_) { + if (id) return; + objectStore = &objectStore_; + MBGL_CHECK_ERROR(glGenTextures(1, &id)); +} + +void TextureHolder::reset() { + if (!id) return; + objectStore->abandonedTextures.push_back(id); + id = 0; +} + +void TexturePoolHolder::create(GLObjectStore& objectStore_) { + if (bool()) return; + objectStore = &objectStore_; + MBGL_CHECK_ERROR(glGenTextures(TextureMax, ids.data())); +} + +void TexturePoolHolder::reset() { + if (!bool()) return; + for (GLuint id : ids) { + if (id) { + objectStore->abandonedTextures.push_back(id); + } + } + ids.fill(0); +} + +void VAOHolder::create(GLObjectStore& objectStore_) { + if (id) return; + objectStore = &objectStore_; + MBGL_CHECK_ERROR(gl::GenVertexArrays(1, &id)); +} + +void VAOHolder::reset() { + if (!id) return; + objectStore->abandonedVAOs.push_back(id); + id = 0; +} + +GLObjectStore::~GLObjectStore() { + assert(abandonedPrograms.empty()); + assert(abandonedShaders.empty()); + assert(abandonedBuffers.empty()); + assert(abandonedTextures.empty()); + assert(abandonedVAOs.empty()); +} + +void GLObjectStore::performCleanup() { + for (GLuint id : abandonedPrograms) { + MBGL_CHECK_ERROR(glDeleteProgram(id)); + } + abandonedPrograms.clear(); + + for (GLuint id : abandonedShaders) { + MBGL_CHECK_ERROR(glDeleteShader(id)); + } + abandonedShaders.clear(); + + if (!abandonedBuffers.empty()) { + MBGL_CHECK_ERROR(glDeleteBuffers(int(abandonedBuffers.size()), abandonedBuffers.data())); + abandonedBuffers.clear(); + } + + if (!abandonedTextures.empty()) { + MBGL_CHECK_ERROR(glDeleteTextures(int(abandonedTextures.size()), abandonedTextures.data())); + abandonedTextures.clear(); + } + + if (!abandonedVAOs.empty()) { + MBGL_CHECK_ERROR(gl::DeleteVertexArrays(int(abandonedVAOs.size()), abandonedVAOs.data())); + abandonedVAOs.clear(); + } +} + +} // namespace gl +} // namespace mbgl diff --git a/src/mbgl/gl/gl_object_store.hpp b/src/mbgl/gl/gl_object_store.hpp new file mode 100644 index 0000000000..832f1d09b3 --- /dev/null +++ b/src/mbgl/gl/gl_object_store.hpp @@ -0,0 +1,141 @@ +#ifndef MBGL_MAP_UTIL_GL_OBJECT_STORE +#define MBGL_MAP_UTIL_GL_OBJECT_STORE + +#include <mbgl/gl/gl.hpp> +#include <mbgl/util/noncopyable.hpp> + +#include <array> +#include <algorithm> +#include <memory> +#include <vector> + +namespace mbgl { +namespace gl { + +class GLObjectStore : private util::noncopyable { +public: + ~GLObjectStore(); + + // Actually remove the objects we marked as abandoned with the above methods. + // Only call this while the OpenGL context is exclusive to this thread. + void performCleanup(); + +private: + friend class ProgramHolder; + friend class ShaderHolder; + friend class BufferHolder; + friend class TextureHolder; + friend class TexturePoolHolder; + friend class VAOHolder; + + std::vector<GLuint> abandonedPrograms; + std::vector<GLuint> abandonedShaders; + std::vector<GLuint> abandonedBuffers; + std::vector<GLuint> abandonedTextures; + std::vector<GLuint> abandonedVAOs; +}; + +class GLHolder : private util::noncopyable { +public: + GLHolder() {} + + GLHolder(GLHolder&& o) noexcept : id(o.id) { o.id = 0; } + GLHolder& operator=(GLHolder&& o) noexcept { id = o.id; o.id = 0; return *this; } + + explicit operator bool() const { return id; } + GLuint getID() const { return id; } + +protected: + GLuint id = 0; + GLObjectStore* objectStore = nullptr; +}; + +class ProgramHolder : public GLHolder { +public: + ProgramHolder() = default; + ~ProgramHolder() { reset(); } + + ProgramHolder(ProgramHolder&& o) noexcept : GLHolder(std::move(o)) {} + ProgramHolder& operator=(ProgramHolder&& o) noexcept { GLHolder::operator=(std::move(o)); return *this; } + + void create(GLObjectStore&); + void reset(); +}; + +class ShaderHolder : public GLHolder { +public: + ShaderHolder(GLenum type_) : type(type_) {} + ~ShaderHolder() { reset(); } + + ShaderHolder(ShaderHolder&& o) noexcept : GLHolder(std::move(o)), type(o.type) {} + ShaderHolder& operator=(ShaderHolder&& o) noexcept { GLHolder::operator=(std::move(o)); type = o.type; return *this; } + + void create(GLObjectStore&); + void reset(); + +private: + GLenum type = 0; +}; + +class BufferHolder : public GLHolder { +public: + BufferHolder() = default; + ~BufferHolder() { reset(); } + + BufferHolder(BufferHolder&& o) noexcept : GLHolder(std::move(o)) {} + BufferHolder& operator=(BufferHolder&& o) noexcept { GLHolder::operator=(std::move(o)); return *this; } + + void create(GLObjectStore&); + void reset(); +}; + +class TextureHolder : public GLHolder { +public: + TextureHolder() = default; + ~TextureHolder() { reset(); } + + TextureHolder(TextureHolder&& o) noexcept : GLHolder(std::move(o)) {} + TextureHolder& operator=(TextureHolder&& o) noexcept { GLHolder::operator=(std::move(o)); return *this; } + + void create(GLObjectStore&); + void reset(); +}; + +class TexturePoolHolder : private util::noncopyable { +public: + static const GLsizei TextureMax = 64; + + TexturePoolHolder() { ids.fill(0); } + ~TexturePoolHolder() { reset(); } + + TexturePoolHolder(TexturePoolHolder&& o) noexcept : ids(std::move(o.ids)) {} + TexturePoolHolder& operator=(TexturePoolHolder&& o) noexcept { ids = std::move(o.ids); return *this; } + + explicit operator bool() { return std::none_of(ids.begin(), ids.end(), [](int id) { return id == 0; }); } + const std::array<GLuint, TextureMax>& getIDs() const { return ids; } + const GLuint& operator[](size_t pos) { return ids[pos]; } + + void create(GLObjectStore&); + void reset(); + +private: + std::array<GLuint, TextureMax> ids; + GLObjectStore* objectStore = nullptr; +}; + +class VAOHolder : public GLHolder { +public: + VAOHolder() = default; + ~VAOHolder() { reset(); } + + VAOHolder(VAOHolder&& o) noexcept : GLHolder(std::move(o)) {} + VAOHolder& operator=(VAOHolder&& o) noexcept { GLHolder::operator=(std::move(o)); return *this; } + + void create(GLObjectStore&); + void reset(); +}; + +} // namespace gl +} // namespace mbgl + +#endif diff --git a/src/mbgl/gl/texture_pool.cpp b/src/mbgl/gl/texture_pool.cpp new file mode 100644 index 0000000000..a875f4d579 --- /dev/null +++ b/src/mbgl/gl/texture_pool.cpp @@ -0,0 +1,41 @@ +#include <mbgl/gl/texture_pool.hpp> +#include <mbgl/gl/gl_object_store.hpp> + +#include <vector> + +namespace mbgl { +namespace gl { + +GLuint TexturePool::getTextureID(gl::GLObjectStore& glObjectStore) { + for (auto& impl : pools) { + if (impl.ids.empty()) continue; + auto it = impl.ids.begin(); + GLuint id = *it; + impl.ids.erase(it); + return id; + } + + // All texture IDs are in use. + pools.emplace_back(Impl(glObjectStore)); + auto it = pools.back().ids.begin(); + GLuint id = *it; + pools.back().ids.erase(it); + return id; +} + +void TexturePool::releaseTextureID(GLuint id) { + for (auto it = pools.begin(); it != pools.end(); ++it) { + for (GLsizei i = 0; i < gl::TexturePoolHolder::TextureMax; ++i) { + if (it->pool[i] == id) { + it->ids.push_back(id); + if (GLsizei(it->ids.size()) == gl::TexturePoolHolder::TextureMax) { + pools.erase(it); + } + return; + } + } + } +} + +} // namespace gl +} // namespace mbgl diff --git a/src/mbgl/gl/texture_pool.hpp b/src/mbgl/gl/texture_pool.hpp new file mode 100644 index 0000000000..10f63bfac9 --- /dev/null +++ b/src/mbgl/gl/texture_pool.hpp @@ -0,0 +1,41 @@ +#ifndef MBGL_UTIL_TEXTUREPOOL +#define MBGL_UTIL_TEXTUREPOOL + +#include <mbgl/util/noncopyable.hpp> +#include <mbgl/gl/gl.hpp> +#include <mbgl/gl/gl_object_store.hpp> + +#include <algorithm> +#include <memory> +#include <vector> + +namespace mbgl { +namespace gl { + +class TexturePool : private util::noncopyable { +public: + GLuint getTextureID(gl::GLObjectStore&); + void releaseTextureID(GLuint); + +private: + class Impl : private util::noncopyable { + public: + Impl(gl::GLObjectStore& glObjectStore) : ids(gl::TexturePoolHolder::TextureMax) { + pool.create(glObjectStore); + std::copy(pool.getIDs().begin(), pool.getIDs().end(), ids.begin()); + } + + Impl(Impl&& o) : pool(std::move(o.pool)), ids(std::move(o.ids)) {} + Impl& operator=(Impl&& o) { pool = std::move(o.pool); ids = std::move(o.ids); return *this; } + + gl::TexturePoolHolder pool; + std::vector<GLuint> ids; + }; + + std::vector<Impl> pools; +}; + +} // namespace gl +} // namespace mbgl + +#endif |