Uniform buffer objects (#1127)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
Alex Cristici
2023-05-11 20:33:58 +03:00
committed by Bart Louwers
parent bbb8bf3c1e
commit d8ea91de98
34 changed files with 634 additions and 163 deletions

View File

@@ -1,5 +1,6 @@
#pragma once
#include <mbgl/gfx/uniform_buffer.hpp>
#include <mbgl/gfx/vertex_attribute.hpp>
#include <mbgl/tile/tile_id.hpp>
#include <mbgl/util/identity.hpp>
@@ -22,7 +23,7 @@ enum class DepthMaskType : bool;
class DrawableTweaker;
class ShaderProgramBase;
using ShaderProgramBasePtr = std::shared_ptr<ShaderProgramBase>;
using UniformBufferPtr = std::shared_ptr<UniformBuffer>;
using DrawPriority = int64_t;
using DrawableTweakerPtr = std::shared_ptr<DrawableTweaker>;
@@ -94,6 +95,10 @@ public:
/// Get the tweakers attached to this drawable
const std::vector<DrawableTweakerPtr>& getTweakers() const { return tweakers; }
/// Get the uniform buffers attached to this drawable
virtual const gfx::UniformBufferArray& getUniformBuffers() const = 0;
virtual gfx::UniformBufferArray& mutableUniformBuffers() = 0;
// Reset a single color attribute for all vertexes
virtual void resetColor(const Color&) = 0;
@@ -137,5 +142,9 @@ private:
bool desc;
};
struct alignas(16) DrawableUBO {
std::array<float, 4 * 4> matrix;
};
} // namespace gfx
} // namespace mbgl

View File

@@ -0,0 +1,94 @@
#pragma once
#include <string>
#include <memory>
#include <unordered_map>
namespace mbgl {
namespace gfx {
class UniformBuffer;
class UniformBlock {
// Can only be created by UniformBlockArray implementations
protected:
UniformBlock(int index_, std::size_t size_)
: index(index_),
size(size_) {}
UniformBlock(const UniformBlock&) = default;
UniformBlock(UniformBlock&& other)
: index(other.index),
size(other.size) {}
public:
virtual ~UniformBlock() = default;
int getIndex() const { return index; }
std::size_t getSize() const { return size; }
virtual void bindBuffer(const UniformBuffer& uniformBuffer) = 0;
virtual void unbindBuffer() = 0;
protected:
UniformBlock& operator=(const UniformBlock&) = default;
UniformBlock& operator=(UniformBlock&& other) {
index = other.index;
size = other.size;
return *this;
}
protected:
int index;
std::size_t size;
};
/// Stores a collection of uniform blocks by name
class UniformBlockArray {
public:
using UniformBlockMap = std::unordered_map<std::string, std::unique_ptr<UniformBlock>>;
UniformBlockArray(int initCapacity = 10);
UniformBlockArray(UniformBlockArray&&);
// Would need to use the virtual assignment operator
UniformBlockArray(const UniformBlockArray&) = delete;
virtual ~UniformBlockArray() = default;
/// Get map of elements.
const UniformBlockMap& getMap() const { return uniformBlockMap; }
/// Number of elements
std::size_t size() const { return uniformBlockMap.size(); }
/// Get an uniform block element.
/// Returns a pointer to the element on success, or null if the uniform block doesn't exists.
const std::unique_ptr<UniformBlock>& get(const std::string& name) const;
/// Add a new uniform block element.
/// Returns a pointer to the new element on success, or null if the uniform block already exists.
const std::unique_ptr<UniformBlock>& add(std::string name, int index, std::size_t size);
UniformBlockArray& operator=(UniformBlockArray&&);
UniformBlockArray& operator=(const UniformBlockArray&);
protected:
const std::unique_ptr<UniformBlock>& add(std::string name, std::unique_ptr<UniformBlock>&& uniformBlock) {
const auto result = uniformBlockMap.insert(std::make_pair(std::move(name), std::unique_ptr<UniformBlock>()));
if (result.second) {
result.first->second = std::move(uniformBlock);
return result.first->second;
} else {
return nullref;
}
}
virtual std::unique_ptr<UniformBlock> create(int index, std::size_t size) = 0;
virtual std::unique_ptr<UniformBlock> copy(const UniformBlock& uniformBlock) = 0;
protected:
UniformBlockMap uniformBlockMap;
static std::unique_ptr<UniformBlock> nullref;
};
} // namespace gfx
} // namespace mbgl

View File

@@ -0,0 +1,79 @@
#pragma once
#include <memory>
#include <string>
#include <unordered_map>
namespace mbgl {
namespace gfx {
class UniformBuffer {
// Can only be created by platform specific implementations
protected:
UniformBuffer(std::size_t size_)
: size(size_) {}
UniformBuffer(const UniformBuffer&) = default;
UniformBuffer(UniformBuffer&& other)
: size(other.size) {}
public:
virtual ~UniformBuffer() = default;
std::size_t getSize() const { return size; }
protected:
UniformBuffer& operator=(const UniformBuffer&) = default;
UniformBuffer& operator=(UniformBuffer&& other) {
size = other.size;
return *this;
}
protected:
std::size_t size;
};
/// Stores a collection of uniform buffers by name
class UniformBufferArray {
public:
using UniformBufferMap = std::unordered_map<std::string, std::shared_ptr<UniformBuffer>>;
UniformBufferArray(int initCapacity = 10);
UniformBufferArray(UniformBufferArray&&);
// Would need to use the virtual assignment operator
UniformBufferArray(const UniformBufferArray&) = delete;
virtual ~UniformBufferArray() = default;
/// Number of elements
std::size_t size() const { return uniformBufferMap.size(); }
/// Get an uniform buffer element.
/// Returns a pointer to the element on success, or null if the uniform buffer doesn't exists.
const std::shared_ptr<UniformBuffer>& get(const std::string& name) const;
/// Add a new uniform buffer element or replace the existing one.
const std::shared_ptr<UniformBuffer>& addOrReplace(std::string name,
const std::shared_ptr<UniformBuffer>& uniformBuffer);
UniformBufferArray& operator=(UniformBufferArray&&);
UniformBufferArray& operator=(const UniformBufferArray&);
protected:
const std::shared_ptr<UniformBuffer>& add(std::string name, std::shared_ptr<UniformBuffer>&& uniformBuffer) {
const auto result = uniformBufferMap.insert(std::make_pair(std::move(name), std::shared_ptr<UniformBuffer>()));
if (result.second) {
result.first->second = std::move(uniformBuffer);
return result.first->second;
} else {
return nullref;
}
}
virtual std::unique_ptr<UniformBuffer> copy(const UniformBuffer& uniformBuffer) = 0;
protected:
UniformBufferMap uniformBufferMap;
static std::shared_ptr<UniformBuffer> nullref;
};
} // namespace gfx
} // namespace mbgl

View File

@@ -147,30 +147,30 @@ public:
/// Add a new attribute element.
/// Returns a pointer to the new element on success, or null if the attribute already exists.
/// The result is valid only until the next non-const method call on this class.
VertexAttribute* get(const std::string& name) const;
const std::unique_ptr<VertexAttribute>& get(const std::string& name) const;
/// Add a new attribute element.
/// Returns a pointer to the new element on success, or null if the attribute already exists.
/// The result is valid only until the next non-const method call on this class.
VertexAttribute* add(std::string name,
int index = -1,
AttributeDataType = AttributeDataType::Invalid,
int size = 1,
std::size_t count = 1);
const std::unique_ptr<VertexAttribute>& add(std::string name,
int index = -1,
AttributeDataType = AttributeDataType::Invalid,
int size = 1,
std::size_t count = 1);
/// Add a new attribute element if it doesn't already exist.
/// Returns a pointer to the new element on success, or null if the type or count conflict with an existing entry.
/// The result is valid only until the next non-const method call on this class.
VertexAttribute* getOrAdd(std::string name,
int index = -1,
AttributeDataType = AttributeDataType::Invalid,
int size = 1,
std::size_t count = 1);
const std::unique_ptr<VertexAttribute>& getOrAdd(std::string name,
int index = -1,
AttributeDataType = AttributeDataType::Invalid,
int size = 1,
std::size_t count = 1);
// Set a value if the element is present
template <typename T>
bool set(const std::string& name, std::size_t i, T value) {
if (auto* item = get(name)) {
if (const auto& item = get(name)) {
return item->set(i, value);
}
return false;
@@ -182,24 +182,22 @@ public:
attrs.begin(), attrs.end(), [](const auto& kv) { return kv.second && kv.second->isDirty(); });
}
using ResolveDelegate = std::function<void(const std::string&, const VertexAttribute&, const VertexAttribute*)>;
using ResolveDelegate =
std::function<void(const std::string&, const VertexAttribute&, const std::unique_ptr<VertexAttribute>&)>;
/// Call the provided delegate with each value, providing the override if one exists.
void resolve(const VertexAttributeArray& overrides, ResolveDelegate) const;
/// Apply to the active program
virtual void applyUniforms(const ShaderProgramBase&) = 0;
VertexAttributeArray& operator=(VertexAttributeArray&&);
VertexAttributeArray& operator=(const VertexAttributeArray&);
protected:
VertexAttribute* add(std::string name, std::unique_ptr<VertexAttribute>&& attr) {
const std::unique_ptr<VertexAttribute>& add(std::string name, std::unique_ptr<VertexAttribute>&& attr) {
const auto result = attrs.insert(std::make_pair(std::move(name), std::unique_ptr<VertexAttribute>()));
if (result.second) {
result.first->second = std::move(attr);
return result.first->second.get();
return result.first->second;
} else {
return nullptr;
return nullref;
}
}
@@ -211,6 +209,7 @@ protected:
protected:
AttributeMap attrs;
static std::unique_ptr<VertexAttribute> nullref;
};
} // namespace gfx

View File

@@ -42,6 +42,9 @@ public:
const gfx::UniqueVertexBufferResource& getBuffer() const;
const gfx::IndexBuffer& getIndexBuffer() const;
const gfx::UniformBufferArray& getUniformBuffers() const override;
gfx::UniformBufferArray& mutableUniformBuffers() override;
/// Reset a single color attribute for all vertexes
void resetColor(const Color&) override;
@@ -61,6 +64,8 @@ protected:
DrawableGL(std::unique_ptr<Impl>);
private:
void bindUniformBuffers() const;
void unbindUniformBuffers() const;
};
} // namespace gl

View File

@@ -0,0 +1,57 @@
#pragma once
#include <mbgl/gfx/uniform_block.hpp>
#include <mbgl/gfx/uniform_buffer.hpp>
namespace mbgl {
namespace gl {
class UniformBlockArrayGL;
class UniformBlockGL final : public gfx::UniformBlock {
// Can only be created by UniformBlockArrayGL
private:
friend UniformBlockArrayGL;
UniformBlockGL(int index_, std::size_t size_)
: UniformBlock(index_, size_) {}
UniformBlockGL(const UniformBlockGL& other)
: UniformBlock(other) {}
UniformBlockGL(UniformBlockGL&& other)
: UniformBlock(std::move(other)) {}
public:
void bindBuffer(const gfx::UniformBuffer& uniformBuffer) override;
void unbindBuffer() override;
};
/// Stores a collection of uniform blocks by name
class UniformBlockArrayGL final : public gfx::UniformBlockArray {
public:
UniformBlockArrayGL(int initCapacity = 10)
: UniformBlockArray(initCapacity) {}
UniformBlockArrayGL(UniformBlockArrayGL&& other)
: UniformBlockArray(std::move(other)) {}
UniformBlockArrayGL(const UniformBlockArrayGL&) = delete;
UniformBlockArrayGL& operator=(UniformBlockArrayGL&& other) {
UniformBlockArray::operator=(std::move(other));
return *this;
}
UniformBlockArrayGL& operator=(const UniformBlockArrayGL& other) {
UniformBlockArray::operator=(other);
return *this;
}
private:
std::unique_ptr<gfx::UniformBlock> create(int index, std::size_t size) override {
return std::unique_ptr<gfx::UniformBlock>(new UniformBlockGL(index, size));
}
std::unique_ptr<gfx::UniformBlock> copy(const gfx::UniformBlock& uniformBlocks) override {
return std::unique_ptr<gfx::UniformBlock>(
new UniformBlockGL(static_cast<const UniformBlockGL&>(uniformBlocks)));
}
};
} // namespace gl
} // namespace mbgl

View File

@@ -0,0 +1,49 @@
#pragma once
#include <mbgl/gfx/uniform_buffer.hpp>
#include <mbgl/gl/types.hpp>
namespace mbgl {
namespace gl {
class UniformBufferGL final : public gfx::UniformBuffer {
public:
UniformBufferGL(const void* data, std::size_t size_);
UniformBufferGL(const UniformBufferGL& other)
: UniformBuffer(other) {}
UniformBufferGL(UniformBufferGL&& other)
: UniformBuffer(std::move(other)) {}
BufferID getID() const { return id; }
protected:
BufferID id = 0;
};
/// Stores a collection of uniform buffers by name
class UniformBufferArrayGL final : public gfx::UniformBufferArray {
public:
UniformBufferArrayGL(int initCapacity = 10)
: UniformBufferArray(initCapacity) {}
UniformBufferArrayGL(UniformBufferArrayGL&& other)
: UniformBufferArray(std::move(other)) {}
UniformBufferArrayGL(const UniformBufferArrayGL&) = delete;
UniformBufferArrayGL& operator=(UniformBufferArrayGL&& other) {
UniformBufferArray::operator=(std::move(other));
return *this;
}
UniformBufferArrayGL& operator=(const UniformBufferArrayGL& other) {
UniformBufferArray::operator=(other);
return *this;
}
private:
std::unique_ptr<gfx::UniformBuffer> copy(const gfx::UniformBuffer& uniformBuffers) override {
return std::unique_ptr<gfx::UniformBuffer>(
new UniformBufferGL(static_cast<const UniformBufferGL&>(uniformBuffers)));
}
};
} // namespace gl
} // namespace mbgl

View File

@@ -62,8 +62,6 @@ public:
return *this;
}
void applyUniforms(const gfx::ShaderProgramBase&) override;
private:
std::unique_ptr<gfx::VertexAttribute> create(int index,
gfx::AttributeDataType dataType,

View File

@@ -0,0 +1,43 @@
#pragma once
#include <mbgl/shaders/shader_source.hpp>
namespace mbgl {
namespace shaders {
template <>
struct ShaderSource<BuiltIn::BackgroundProgramUBO, gfx::Backend::Type::OpenGL> {
static constexpr const char* vertex = R"(#version 300 es
precision highp float;
layout (location = 0) in vec2 a_pos;
layout (std140) uniform DrawableUBO {
mat4 u_matrix;
};
void main() {
gl_Position = u_matrix * vec4(a_pos, 0, 1);
}
)";
static constexpr const char* fragment = R"(#version 300 es
precision highp float;
layout (std140) uniform BackgroundLayerUBO {
vec4 u_color;
float u_opacity;
};
out vec4 fragColor;
void main() {
fragColor = u_color * u_opacity;
#ifdef OVERDRAW_INSPECTOR
fragColor = vec4(1.0);
#endif
}
)";
};
} // namespace shaders
} // namespace mbgl

View File

@@ -1,6 +1,7 @@
#pragma once
#include <mbgl/gl/context.hpp>
#include <mbgl/gl/uniform_block_gl.hpp>
#include <mbgl/gl/vertex_attribute_gl.hpp>
#include <mbgl/shaders/shader_program_base.hpp>
@@ -10,7 +11,7 @@ namespace gl {
class ShaderProgramGL final : public gfx::ShaderProgramBase {
public:
ShaderProgramGL(UniqueProgram&& glProgram_);
ShaderProgramGL(UniqueProgram&&, VertexAttributeArrayGL&& uniforms, VertexAttributeArrayGL&& attributes);
ShaderProgramGL(UniqueProgram&&, UniformBlockArrayGL&& uniformBlocks, VertexAttributeArrayGL&& attributes);
ShaderProgramGL(ShaderProgramGL&& other);
~ShaderProgramGL() noexcept override = default;
@@ -22,21 +23,21 @@ public:
std::string_view vertexSource,
std::string_view fragmentSource) noexcept(false);
const gfx::VertexAttributeArray& getUniforms() const override { return uniforms; }
const gfx::UniformBlockArray& getUniformBlocks() const override { return uniformBlocks; }
const gfx::VertexAttributeArray& getVertexAttributes() const override { return vertexAttributes; }
ProgramID getGLProgramID() const { return glProgram; }
protected:
gfx::VertexAttributeArray& mutableUniforms() override { return uniforms; }
gfx::UniformBlockArray& mutableUniformBlocks() override { return uniformBlocks; }
gfx::VertexAttributeArray& mutableVertexAttributes() override { return vertexAttributes; }
protected:
UniqueProgram glProgram;
VertexAttributeArrayGL uniforms;
UniformBlockArrayGL uniformBlocks;
VertexAttributeArrayGL vertexAttributes;
};

View File

@@ -32,4 +32,6 @@
#include <mbgl/shaders/gl/symbol_sdf_text.hpp>
#include <mbgl/shaders/gl/symbol_sdf_icon.hpp>
#include <mbgl/shaders/gl/symbol_text_and_icon.hpp>
#include <mbgl/shaders/gl/background_ubo.hpp>
#endif

View File

@@ -1,6 +1,7 @@
#pragma once
#include <mbgl/gfx/shader.hpp>
#include <mbgl/gfx/uniform_block.hpp>
#include <mbgl/gfx/vertex_attribute.hpp>
#include <mbgl/util/identity.hpp>
@@ -17,7 +18,7 @@ protected:
template <typename T>
bool set(gfx::VertexAttributeArray& attrs, const std::string& name, std::size_t i, T value) {
auto* item = attrs.get(name);
const auto& item = attrs.get(name);
if (item && i < item->getCount()) {
item->set(i, value);
return true;
@@ -28,26 +29,19 @@ protected:
public:
const util::SimpleIdentity& getID() const { return shaderProgramID; }
/// Get the available vertex attributes and their default values
virtual const gfx::VertexAttributeArray& getUniforms() const = 0;
/// Get the available uniform blocks attached to this shader
virtual const gfx::UniformBlockArray& getUniformBlocks() const = 0;
/// Get the available vertex attributes and their default values
virtual const gfx::VertexAttributeArray& getVertexAttributes() const = 0;
// Set a value if the element is present
template <typename T>
bool setUniform(const std::string& name, std::size_t i, T value) {
return set(mutableUniforms(), name, i, value);
}
template <typename T>
bool setAttribute(const std::string& name, std::size_t i, T value) {
return set(mutableVertexAttributes(), name, i, value);
}
void updateUniforms() { mutableUniforms().applyUniforms(*this); }
protected:
virtual gfx::VertexAttributeArray& mutableUniforms() = 0;
virtual gfx::UniformBlockArray& mutableUniformBlocks() = 0;
virtual gfx::VertexAttributeArray& mutableVertexAttributes() = 0;
protected:

View File

@@ -37,7 +37,9 @@ enum class BuiltIn {
SymbolIconProgram,
SymbolSDFTextProgram,
SymbolSDFIconProgram,
SymbolTextAndIconProgram
SymbolTextAndIconProgram,
BackgroundProgramUBO
};
/// @brief Select shader source based on a program type and a desired