[core] Use unique_resource for GL objects
Source: https://github.com/okdshin/unique_resource These replace the complexity of manually handling moveable-RAII objects with a type specific for that purpose. As suggested in https://github.com/mapbox/mapbox-gl-native/pull/5141#issuecomment-221719872.
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
#include <mbgl/gl/object_store.hpp>
|
||||
#include <mbgl/platform/log.hpp>
|
||||
#include <mbgl/util/noncopyable.hpp>
|
||||
#include <mbgl/util/optional.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <cstdlib>
|
||||
@@ -36,11 +37,11 @@ public:
|
||||
|
||||
// Transfers this buffer to the GPU and binds the buffer to the GL context.
|
||||
void bind(gl::ObjectStore& store) {
|
||||
if (buffer.created()) {
|
||||
MBGL_CHECK_ERROR(glBindBuffer(bufferType, getID()));
|
||||
if (buffer) {
|
||||
MBGL_CHECK_ERROR(glBindBuffer(bufferType, *buffer));
|
||||
} else {
|
||||
buffer.create(store);
|
||||
MBGL_CHECK_ERROR(glBindBuffer(bufferType, getID()));
|
||||
buffer = store.createBuffer();
|
||||
MBGL_CHECK_ERROR(glBindBuffer(bufferType, *buffer));
|
||||
if (array == nullptr) {
|
||||
Log::Debug(Event::OpenGL, "Buffer doesn't contain elements");
|
||||
pos = 0;
|
||||
@@ -60,12 +61,12 @@ public:
|
||||
}
|
||||
|
||||
GLuint getID() const {
|
||||
return buffer.getID();
|
||||
return buffer ? *buffer : 0;
|
||||
}
|
||||
|
||||
// Uploads the buffer to the GPU to be available when we need it.
|
||||
inline void upload(gl::ObjectStore& store) {
|
||||
if (!buffer.created()) {
|
||||
if (!buffer) {
|
||||
bind(store);
|
||||
}
|
||||
}
|
||||
@@ -73,7 +74,7 @@ public:
|
||||
protected:
|
||||
// increase the buffer size by at least /required/ bytes.
|
||||
inline void *addElement() {
|
||||
if (buffer.created()) {
|
||||
if (buffer) {
|
||||
throw std::runtime_error("Can't add elements after buffer was bound to GPU");
|
||||
}
|
||||
if (length < pos + itemSize) {
|
||||
@@ -114,7 +115,7 @@ private:
|
||||
size_t length = 0;
|
||||
|
||||
// GL buffer object handle.
|
||||
gl::BufferHolder buffer;
|
||||
mbgl::optional<gl::UniqueBuffer> buffer;
|
||||
};
|
||||
|
||||
} // namespace mbgl
|
||||
|
||||
@@ -144,7 +144,7 @@ void GlyphAtlas::removeGlyphs(uintptr_t tileUID) {
|
||||
|
||||
void GlyphAtlas::upload(gl::ObjectStore& store) {
|
||||
if (dirty) {
|
||||
const bool first = !texture.created();
|
||||
const bool first = !texture;
|
||||
bind(store);
|
||||
|
||||
std::lock_guard<std::mutex> lock(mtx);
|
||||
@@ -184,9 +184,9 @@ void GlyphAtlas::upload(gl::ObjectStore& store) {
|
||||
}
|
||||
|
||||
void GlyphAtlas::bind(gl::ObjectStore& store) {
|
||||
if (!texture.created()) {
|
||||
texture.create(store);
|
||||
MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, texture.getID()));
|
||||
if (!texture) {
|
||||
texture = store.createTexture();
|
||||
MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, *texture));
|
||||
#ifndef GL_ES_VERSION_2_0
|
||||
MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0));
|
||||
#endif
|
||||
@@ -195,6 +195,6 @@ void GlyphAtlas::bind(gl::ObjectStore& store) {
|
||||
MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
|
||||
MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
|
||||
} else {
|
||||
MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, texture.getID()));
|
||||
MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, *texture));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <mbgl/geometry/binpack.hpp>
|
||||
#include <mbgl/text/glyph_store.hpp>
|
||||
#include <mbgl/util/noncopyable.hpp>
|
||||
#include <mbgl/util/optional.hpp>
|
||||
#include <mbgl/gl/gl.hpp>
|
||||
#include <mbgl/gl/object_store.hpp>
|
||||
|
||||
@@ -53,7 +54,7 @@ private:
|
||||
std::unordered_map<FontStack, std::map<uint32_t, GlyphValue>, FontStackHash> index;
|
||||
const std::unique_ptr<uint8_t[]> data;
|
||||
std::atomic<bool> dirty;
|
||||
gl::TextureHolder texture;
|
||||
mbgl::optional<gl::UniqueTexture> texture;
|
||||
};
|
||||
|
||||
} // namespace mbgl
|
||||
|
||||
@@ -129,16 +129,16 @@ void LineAtlas::upload(gl::ObjectStore& store) {
|
||||
|
||||
void LineAtlas::bind(gl::ObjectStore& store) {
|
||||
bool first = false;
|
||||
if (!texture.created()) {
|
||||
texture.create(store);
|
||||
MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, texture.getID()));
|
||||
if (!texture) {
|
||||
texture = store.createTexture();
|
||||
MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, *texture));
|
||||
MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
|
||||
MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
|
||||
MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT));
|
||||
MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
|
||||
first = true;
|
||||
} else {
|
||||
MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, texture.getID()));
|
||||
MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, *texture));
|
||||
}
|
||||
|
||||
if (dirty) {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <mbgl/gl/gl.hpp>
|
||||
#include <mbgl/gl/object_store.hpp>
|
||||
#include <mbgl/util/optional.hpp>
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
@@ -35,7 +36,7 @@ public:
|
||||
private:
|
||||
const std::unique_ptr<GLbyte[]> data;
|
||||
bool dirty;
|
||||
gl::TextureHolder texture;
|
||||
mbgl::optional<gl::UniqueTexture> texture;
|
||||
int nextRow = 0;
|
||||
std::map<size_t, LinePatternPos> positions;
|
||||
};
|
||||
|
||||
@@ -26,10 +26,10 @@ void VertexArrayObject::bindVertexArrayObject(gl::ObjectStore& store) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!vao.created()) {
|
||||
vao.create(store);
|
||||
if (!vao) {
|
||||
vao = store.createVAO();
|
||||
}
|
||||
MBGL_CHECK_ERROR(gl::BindVertexArray(vao.getID()));
|
||||
MBGL_CHECK_ERROR(gl::BindVertexArray(*vao));
|
||||
}
|
||||
|
||||
void VertexArrayObject::verifyBinding(Shader &shader, GLuint vertexBuffer, GLuint elementsBuffer,
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <mbgl/gl/gl.hpp>
|
||||
#include <mbgl/gl/object_store.hpp>
|
||||
#include <mbgl/util/noncopyable.hpp>
|
||||
#include <mbgl/util/optional.hpp>
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
@@ -24,7 +25,7 @@ public:
|
||||
if (bound_shader == 0) {
|
||||
vertexBuffer.bind(store);
|
||||
shader.bind(offset);
|
||||
if (vao.created()) {
|
||||
if (vao) {
|
||||
storeBinding(shader, vertexBuffer.getID(), 0, offset);
|
||||
}
|
||||
} else {
|
||||
@@ -39,7 +40,7 @@ public:
|
||||
vertexBuffer.bind(store);
|
||||
elementsBuffer.bind(store);
|
||||
shader.bind(offset);
|
||||
if (vao.created()) {
|
||||
if (vao) {
|
||||
storeBinding(shader, vertexBuffer.getID(), elementsBuffer.getID(), offset);
|
||||
}
|
||||
} else {
|
||||
@@ -48,7 +49,7 @@ public:
|
||||
}
|
||||
|
||||
GLuint getID() const {
|
||||
return vao.getID();
|
||||
return *vao;
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -56,7 +57,7 @@ private:
|
||||
void storeBinding(Shader &shader, GLuint vertexBuffer, GLuint elementsBuffer, GLbyte *offset);
|
||||
void verifyBinding(Shader &shader, GLuint vertexBuffer, GLuint elementsBuffer, GLbyte *offset);
|
||||
|
||||
gl::VAOHolder vao;
|
||||
mbgl::optional<gl::UniqueVAO> vao;
|
||||
|
||||
// For debug reasons, we're storing the bind information so that we can
|
||||
// detect errors and report
|
||||
|
||||
@@ -5,79 +5,39 @@
|
||||
namespace mbgl {
|
||||
namespace gl {
|
||||
|
||||
void ProgramHolder::create(ObjectStore& objectStore_) {
|
||||
if (created()) return;
|
||||
objectStore = &objectStore_;
|
||||
id = MBGL_CHECK_ERROR(glCreateProgram());
|
||||
void ProgramDeleter::operator()(GLuint id) const {
|
||||
assert(store);
|
||||
store->abandonedPrograms.push_back(id);
|
||||
}
|
||||
|
||||
void ProgramHolder::reset() {
|
||||
if (!created()) return;
|
||||
objectStore->abandonedPrograms.push_back(id);
|
||||
id = 0;
|
||||
void ShaderDeleter::operator()(GLuint id) const {
|
||||
assert(store);
|
||||
store->abandonedShaders.push_back(id);
|
||||
}
|
||||
|
||||
void ShaderHolder::create(ObjectStore& objectStore_) {
|
||||
if (created()) return;
|
||||
objectStore = &objectStore_;
|
||||
id = MBGL_CHECK_ERROR(glCreateShader(type));
|
||||
void BufferDeleter::operator()(GLuint id) const {
|
||||
assert(store);
|
||||
store->abandonedBuffers.push_back(id);
|
||||
}
|
||||
|
||||
void ShaderHolder::reset() {
|
||||
if (!created()) return;
|
||||
objectStore->abandonedShaders.push_back(id);
|
||||
id = 0;
|
||||
void TextureDeleter::operator()(GLuint id) const {
|
||||
assert(store);
|
||||
store->abandonedTextures.push_back(id);
|
||||
}
|
||||
|
||||
void BufferHolder::create(ObjectStore& objectStore_) {
|
||||
if (created()) return;
|
||||
objectStore = &objectStore_;
|
||||
MBGL_CHECK_ERROR(glGenBuffers(1, &id));
|
||||
void VAODeleter::operator()(GLuint id) const {
|
||||
assert(store);
|
||||
store->abandonedVAOs.push_back(id);
|
||||
}
|
||||
|
||||
void BufferHolder::reset() {
|
||||
if (!created()) return;
|
||||
objectStore->abandonedBuffers.push_back(id);
|
||||
id = 0;
|
||||
}
|
||||
|
||||
void TextureHolder::create(ObjectStore& objectStore_) {
|
||||
if (created()) return;
|
||||
objectStore = &objectStore_;
|
||||
MBGL_CHECK_ERROR(glGenTextures(1, &id));
|
||||
}
|
||||
|
||||
void TextureHolder::reset() {
|
||||
if (!created()) return;
|
||||
objectStore->abandonedTextures.push_back(id);
|
||||
id = 0;
|
||||
}
|
||||
|
||||
void TexturePoolHolder::create(ObjectStore& objectStore_) {
|
||||
if (created()) return;
|
||||
objectStore = &objectStore_;
|
||||
MBGL_CHECK_ERROR(glGenTextures(TextureMax, ids.data()));
|
||||
}
|
||||
|
||||
void TexturePoolHolder::reset() {
|
||||
if (!created()) return;
|
||||
void TexturePoolDeleter::operator()(ObjectPool ids) const {
|
||||
assert(store);
|
||||
for (GLuint& id : ids) {
|
||||
if (id == 0) continue;
|
||||
objectStore->abandonedTextures.push_back(id);
|
||||
id = 0;
|
||||
};
|
||||
}
|
||||
|
||||
void VAOHolder::create(ObjectStore& objectStore_) {
|
||||
if (created()) return;
|
||||
objectStore = &objectStore_;
|
||||
MBGL_CHECK_ERROR(gl::GenVertexArrays(1, &id));
|
||||
}
|
||||
|
||||
void VAOHolder::reset() {
|
||||
if (!created()) return;
|
||||
objectStore->abandonedVAOs.push_back(id);
|
||||
id = 0;
|
||||
if (id) {
|
||||
store->abandonedTextures.push_back(id);
|
||||
id = 0;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
ObjectStore::~ObjectStore() {
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
#include <mbgl/gl/gl.hpp>
|
||||
#include <mbgl/util/noncopyable.hpp>
|
||||
|
||||
#include <unique_resource.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
@@ -11,21 +13,96 @@
|
||||
namespace mbgl {
|
||||
namespace gl {
|
||||
|
||||
constexpr GLsizei TextureMax = 64;
|
||||
|
||||
class ObjectStore;
|
||||
|
||||
struct ProgramDeleter {
|
||||
ObjectStore* store;
|
||||
void operator()(GLuint id) const;
|
||||
};
|
||||
|
||||
struct ShaderDeleter {
|
||||
ObjectStore* store;
|
||||
void operator()(GLuint id) const;
|
||||
};
|
||||
|
||||
struct BufferDeleter {
|
||||
ObjectStore* store;
|
||||
void operator()(GLuint id) const;
|
||||
};
|
||||
|
||||
struct TextureDeleter {
|
||||
ObjectStore* store;
|
||||
void operator()(GLuint id) const;
|
||||
};
|
||||
|
||||
struct VAODeleter {
|
||||
ObjectStore* store;
|
||||
void operator()(GLuint id) const;
|
||||
};
|
||||
|
||||
using ObjectPool = std::array<GLuint, TextureMax>;
|
||||
|
||||
struct TexturePoolDeleter {
|
||||
ObjectStore* store;
|
||||
void operator()(ObjectPool ids) const;
|
||||
};
|
||||
|
||||
using UniqueProgram = std_experimental::unique_resource<GLuint, ProgramDeleter>;
|
||||
using UniqueShader = std_experimental::unique_resource<GLuint, ShaderDeleter>;
|
||||
using UniqueBuffer = std_experimental::unique_resource<GLuint, BufferDeleter>;
|
||||
using UniqueTexture = std_experimental::unique_resource<GLuint, TextureDeleter>;
|
||||
using UniqueVAO = std_experimental::unique_resource<GLuint, VAODeleter>;
|
||||
using UniqueTexturePool = std_experimental::unique_resource<ObjectPool, TexturePoolDeleter>;
|
||||
|
||||
class ObjectStore : private util::noncopyable {
|
||||
public:
|
||||
~ObjectStore();
|
||||
|
||||
UniqueProgram createProgram() {
|
||||
return UniqueProgram(MBGL_CHECK_ERROR(glCreateProgram()), { this });
|
||||
}
|
||||
|
||||
UniqueShader createShader(GLenum type) {
|
||||
return UniqueShader(MBGL_CHECK_ERROR(glCreateShader(type)), { this });
|
||||
}
|
||||
|
||||
UniqueBuffer createBuffer() {
|
||||
GLuint id = 0;
|
||||
MBGL_CHECK_ERROR(glGenBuffers(1, &id));
|
||||
return UniqueBuffer(std::move(id), { this });
|
||||
}
|
||||
|
||||
UniqueTexture createTexture() {
|
||||
GLuint id = 0;
|
||||
MBGL_CHECK_ERROR(glGenTextures(1, &id));
|
||||
return UniqueTexture(std::move(id), { this });
|
||||
}
|
||||
|
||||
UniqueVAO createVAO() {
|
||||
GLuint id = 0;
|
||||
MBGL_CHECK_ERROR(gl::GenVertexArrays(1, &id));
|
||||
return UniqueVAO(std::move(id), { this });
|
||||
}
|
||||
|
||||
UniqueTexturePool createTexturePool() {
|
||||
ObjectPool ids;
|
||||
MBGL_CHECK_ERROR(glGenTextures(TextureMax, ids.data()));
|
||||
return UniqueTexturePool(std::move(ids), { this });
|
||||
}
|
||||
|
||||
// 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;
|
||||
friend ProgramDeleter;
|
||||
friend ShaderDeleter;
|
||||
friend BufferDeleter;
|
||||
friend TextureDeleter;
|
||||
friend VAODeleter;
|
||||
friend TexturePoolDeleter;
|
||||
|
||||
std::vector<GLuint> abandonedPrograms;
|
||||
std::vector<GLuint> abandonedShaders;
|
||||
@@ -34,105 +111,5 @@ private:
|
||||
std::vector<GLuint> abandonedVAOs;
|
||||
};
|
||||
|
||||
class GLHolder : private util::noncopyable {
|
||||
public:
|
||||
GLHolder() {}
|
||||
|
||||
GLHolder(GLHolder&& o) noexcept : id(o.id), objectStore(o.objectStore) { o.id = 0; }
|
||||
GLHolder& operator=(GLHolder&& o) noexcept { id = o.id; objectStore = o.objectStore; o.id = 0; return *this; }
|
||||
|
||||
bool created() const { return id; }
|
||||
GLuint getID() const { return id; }
|
||||
|
||||
protected:
|
||||
GLuint id = 0;
|
||||
ObjectStore* 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(ObjectStore&);
|
||||
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(ObjectStore&);
|
||||
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(ObjectStore&);
|
||||
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(ObjectStore&);
|
||||
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)), objectStore(o.objectStore) { o.ids.fill(0); }
|
||||
TexturePoolHolder& operator=(TexturePoolHolder&& o) noexcept { ids = std::move(o.ids); objectStore = o.objectStore; o.ids.fill(0); return *this; }
|
||||
|
||||
bool created() const { return std::any_of(ids.begin(), ids.end(), [](int id) { return id; }); }
|
||||
const std::array<GLuint, TextureMax>& getIDs() const { return ids; }
|
||||
const GLuint& operator[](size_t pos) { return ids[pos]; }
|
||||
|
||||
void create(ObjectStore&);
|
||||
void reset();
|
||||
|
||||
private:
|
||||
std::array<GLuint, TextureMax> ids;
|
||||
ObjectStore* 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(ObjectStore&);
|
||||
void reset();
|
||||
};
|
||||
|
||||
} // namespace gl
|
||||
} // namespace mbgl
|
||||
|
||||
@@ -25,10 +25,10 @@ GLuint TexturePool::getTextureID(gl::ObjectStore& store) {
|
||||
|
||||
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) {
|
||||
for (GLsizei i = 0; i < gl::TextureMax; ++i) {
|
||||
if (it->pool.get()[i] == id) {
|
||||
it->ids.push_back(id);
|
||||
if (GLsizei(it->ids.size()) == gl::TexturePoolHolder::TextureMax) {
|
||||
if (GLsizei(it->ids.size()) == gl::TextureMax) {
|
||||
pools.erase(it);
|
||||
}
|
||||
return;
|
||||
|
||||
@@ -19,15 +19,14 @@ public:
|
||||
private:
|
||||
class Impl : private util::noncopyable {
|
||||
public:
|
||||
Impl(gl::ObjectStore& store) : ids(gl::TexturePoolHolder::TextureMax) {
|
||||
pool.create(store);
|
||||
std::copy(pool.getIDs().begin(), pool.getIDs().end(), ids.begin());
|
||||
Impl(gl::ObjectStore& store) : pool(store.createTexturePool()), ids(gl::TextureMax) {
|
||||
std::copy(pool.get().begin(), pool.get().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;
|
||||
gl::UniqueTexturePool pool;
|
||||
std::vector<GLuint> ids;
|
||||
};
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ bool FrameHistory::needsAnimation(const Duration& duration) const {
|
||||
void FrameHistory::upload(gl::ObjectStore& store) {
|
||||
|
||||
if (changed) {
|
||||
const bool first = !texture.created();
|
||||
const bool first = !texture;
|
||||
bind(store);
|
||||
|
||||
if (first) {
|
||||
@@ -95,9 +95,9 @@ void FrameHistory::upload(gl::ObjectStore& store) {
|
||||
}
|
||||
|
||||
void FrameHistory::bind(gl::ObjectStore& store) {
|
||||
if (!texture.created()) {
|
||||
texture.create(store);
|
||||
MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, texture.getID()));
|
||||
if (!texture) {
|
||||
texture = store.createTexture();
|
||||
MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, *texture));
|
||||
#ifndef GL_ES_VERSION_2_0
|
||||
MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0));
|
||||
#endif
|
||||
@@ -106,7 +106,7 @@ void FrameHistory::bind(gl::ObjectStore& store) {
|
||||
MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
|
||||
MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
|
||||
} else {
|
||||
MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, texture.getID()));
|
||||
MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, *texture));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <mbgl/platform/platform.hpp>
|
||||
#include <mbgl/gl/object_store.hpp>
|
||||
#include <mbgl/util/chrono.hpp>
|
||||
#include <mbgl/util/optional.hpp>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
@@ -31,7 +32,7 @@ private:
|
||||
bool firstFrame = true;
|
||||
bool changed = true;
|
||||
|
||||
gl::TextureHolder texture;
|
||||
mbgl::optional<gl::UniqueTexture> texture;
|
||||
};
|
||||
|
||||
} // namespace mbgl
|
||||
|
||||
@@ -15,68 +15,68 @@ namespace mbgl {
|
||||
|
||||
Shader::Shader(const char *name_, const GLchar *vertSource, const GLchar *fragSource, gl::ObjectStore& store)
|
||||
: name(name_)
|
||||
, program(store.createProgram())
|
||||
, vertexShader(store.createShader(GL_VERTEX_SHADER))
|
||||
, fragmentShader(store.createShader(GL_FRAGMENT_SHADER))
|
||||
{
|
||||
util::stopwatch stopwatch("shader compilation", Event::Shader);
|
||||
|
||||
program.create(store);
|
||||
vertexShader.create(store);
|
||||
if (!compileShader(vertexShader, &vertSource)) {
|
||||
Log::Error(Event::Shader, "Vertex shader %s failed to compile: %s", name, vertSource);
|
||||
throw util::ShaderException(std::string { "Vertex shader " } + name + " failed to compile");
|
||||
}
|
||||
|
||||
fragmentShader.create(store);
|
||||
if (!compileShader(fragmentShader, &fragSource)) {
|
||||
Log::Error(Event::Shader, "Fragment shader %s failed to compile: %s", name, fragSource);
|
||||
throw util::ShaderException(std::string { "Fragment shader " } + name + " failed to compile");
|
||||
}
|
||||
|
||||
// Attach shaders
|
||||
MBGL_CHECK_ERROR(glAttachShader(program.getID(), vertexShader.getID()));
|
||||
MBGL_CHECK_ERROR(glAttachShader(program.getID(), fragmentShader.getID()));
|
||||
MBGL_CHECK_ERROR(glAttachShader(program.get(), vertexShader.get()));
|
||||
MBGL_CHECK_ERROR(glAttachShader(program.get(), fragmentShader.get()));
|
||||
|
||||
{
|
||||
// Link program
|
||||
GLint status;
|
||||
MBGL_CHECK_ERROR(glLinkProgram(program.getID()));
|
||||
MBGL_CHECK_ERROR(glLinkProgram(program.get()));
|
||||
|
||||
MBGL_CHECK_ERROR(glGetProgramiv(program.getID(), GL_LINK_STATUS, &status));
|
||||
MBGL_CHECK_ERROR(glGetProgramiv(program.get(), GL_LINK_STATUS, &status));
|
||||
if (status == 0) {
|
||||
GLint logLength;
|
||||
MBGL_CHECK_ERROR(glGetProgramiv(program.getID(), GL_INFO_LOG_LENGTH, &logLength));
|
||||
MBGL_CHECK_ERROR(glGetProgramiv(program.get(), GL_INFO_LOG_LENGTH, &logLength));
|
||||
const auto log = std::make_unique<GLchar[]>(logLength);
|
||||
if (logLength > 0) {
|
||||
MBGL_CHECK_ERROR(glGetProgramInfoLog(program.getID(), logLength, &logLength, log.get()));
|
||||
MBGL_CHECK_ERROR(glGetProgramInfoLog(program.get(), logLength, &logLength, log.get()));
|
||||
Log::Error(Event::Shader, "Program failed to link: %s", log.get());
|
||||
}
|
||||
throw util::ShaderException(std::string { "Program " } + name + " failed to link: " + log.get());
|
||||
}
|
||||
}
|
||||
|
||||
a_pos = MBGL_CHECK_ERROR(glGetAttribLocation(program.getID(), "a_pos"));
|
||||
a_pos = MBGL_CHECK_ERROR(glGetAttribLocation(program.get(), "a_pos"));
|
||||
}
|
||||
|
||||
bool Shader::compileShader(gl::ShaderHolder& shader, const GLchar *source[]) {
|
||||
bool Shader::compileShader(gl::UniqueShader& shader, const GLchar *source[]) {
|
||||
GLint status = 0;
|
||||
|
||||
const GLsizei lengths = static_cast<GLsizei>(std::strlen(*source));
|
||||
MBGL_CHECK_ERROR(glShaderSource(shader.getID(), 1, source, &lengths));
|
||||
MBGL_CHECK_ERROR(glShaderSource(shader.get(), 1, source, &lengths));
|
||||
|
||||
MBGL_CHECK_ERROR(glCompileShader(shader.getID()));
|
||||
MBGL_CHECK_ERROR(glCompileShader(shader.get()));
|
||||
|
||||
MBGL_CHECK_ERROR(glGetShaderiv(shader.getID(), GL_COMPILE_STATUS, &status));
|
||||
MBGL_CHECK_ERROR(glGetShaderiv(shader.get(), GL_COMPILE_STATUS, &status));
|
||||
if (status == 0) {
|
||||
GLint logLength;
|
||||
MBGL_CHECK_ERROR(glGetShaderiv(shader.getID(), GL_INFO_LOG_LENGTH, &logLength));
|
||||
MBGL_CHECK_ERROR(glGetShaderiv(shader.get(), GL_INFO_LOG_LENGTH, &logLength));
|
||||
if (logLength > 0) {
|
||||
const auto log = std::make_unique<GLchar[]>(logLength);
|
||||
MBGL_CHECK_ERROR(glGetShaderInfoLog(shader.getID(), logLength, &logLength, log.get()));
|
||||
MBGL_CHECK_ERROR(glGetShaderInfoLog(shader.get(), logLength, &logLength, log.get()));
|
||||
Log::Error(Event::Shader, "Shader failed to compile: %s", log.get());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
MBGL_CHECK_ERROR(glGetShaderiv(shader.getID(), GL_COMPILE_STATUS, &status));
|
||||
MBGL_CHECK_ERROR(glGetShaderiv(shader.get(), GL_COMPILE_STATUS, &status));
|
||||
if (status == GL_FALSE) {
|
||||
Log::Error(Event::Shader, "Shader %s failed to compile.", name);
|
||||
return false;
|
||||
@@ -86,9 +86,9 @@ bool Shader::compileShader(gl::ShaderHolder& shader, const GLchar *source[]) {
|
||||
}
|
||||
|
||||
Shader::~Shader() {
|
||||
if (program.created()) {
|
||||
MBGL_CHECK_ERROR(glDetachShader(program.getID(), vertexShader.getID()));
|
||||
MBGL_CHECK_ERROR(glDetachShader(program.getID(), fragmentShader.getID()));
|
||||
if (program.get()) {
|
||||
MBGL_CHECK_ERROR(glDetachShader(program.get(), vertexShader.get()));
|
||||
MBGL_CHECK_ERROR(glDetachShader(program.get(), fragmentShader.get()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ public:
|
||||
const GLchar *name;
|
||||
|
||||
GLuint getID() const {
|
||||
return program.getID();
|
||||
return program.get();
|
||||
}
|
||||
|
||||
virtual void bind(GLbyte *offset) = 0;
|
||||
@@ -23,11 +23,11 @@ protected:
|
||||
GLint a_pos = -1;
|
||||
|
||||
private:
|
||||
bool compileShader(gl::ShaderHolder&, const GLchar *source[]);
|
||||
bool compileShader(gl::UniqueShader&, const GLchar *source[]);
|
||||
|
||||
gl::ProgramHolder program;
|
||||
gl::ShaderHolder vertexShader = { GL_VERTEX_SHADER };
|
||||
gl::ShaderHolder fragmentShader = { GL_FRAGMENT_SHADER };
|
||||
gl::UniqueProgram program;
|
||||
gl::UniqueShader vertexShader;
|
||||
gl::UniqueShader fragmentShader;
|
||||
};
|
||||
|
||||
} // namespace mbgl
|
||||
|
||||
@@ -142,9 +142,9 @@ void SpriteAtlas::copy(const Holder& holder, const bool wrap) {
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
void SpriteAtlas::upload(gl::ObjectStore& store) {
|
||||
void SpriteAtlas::upload(gl::ObjectStore& objectStore) {
|
||||
if (dirty) {
|
||||
bind(false, store);
|
||||
bind(false, objectStore);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -179,14 +179,14 @@ void SpriteAtlas::updateDirty() {
|
||||
}
|
||||
}
|
||||
|
||||
void SpriteAtlas::bind(bool linear, gl::ObjectStore& store) {
|
||||
void SpriteAtlas::bind(bool linear, gl::ObjectStore& objectStore) {
|
||||
if (!data) {
|
||||
return; // Empty atlas
|
||||
}
|
||||
|
||||
if (!texture.created()) {
|
||||
texture.create(store);
|
||||
MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, texture.getID()));
|
||||
if (!texture) {
|
||||
texture = objectStore.createTexture();
|
||||
MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, *texture));
|
||||
#ifndef GL_ES_VERSION_2_0
|
||||
MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0));
|
||||
#endif
|
||||
@@ -196,7 +196,7 @@ void SpriteAtlas::bind(bool linear, gl::ObjectStore& store) {
|
||||
MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
|
||||
fullUploadRequired = true;
|
||||
} else {
|
||||
MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, texture.getID()));
|
||||
MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, *texture));
|
||||
}
|
||||
|
||||
GLuint filter_val = linear ? GL_LINEAR : GL_NEAREST;
|
||||
|
||||
@@ -94,7 +94,7 @@ private:
|
||||
std::unique_ptr<uint32_t[]> data;
|
||||
std::atomic<bool> dirty;
|
||||
bool fullUploadRequired = true;
|
||||
gl::TextureHolder texture;
|
||||
mbgl::optional<gl::UniqueTexture> texture;
|
||||
uint32_t filter = 0;
|
||||
static const int buffer = 1;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user