diff options
Diffstat (limited to 'src/mbgl/gl')
30 files changed, 1453 insertions, 678 deletions
diff --git a/src/mbgl/gl/attribute.cpp b/src/mbgl/gl/attribute.cpp new file mode 100644 index 0000000000..7432fff590 --- /dev/null +++ b/src/mbgl/gl/attribute.cpp @@ -0,0 +1,29 @@ +#include <mbgl/gl/attribute.hpp> +#include <mbgl/gl/gl.hpp> + +namespace mbgl { +namespace gl { + +AttributeLocation bindAttributeLocation(ProgramID id, AttributeLocation location, const char* name) { + MBGL_CHECK_ERROR(glBindAttribLocation(id, location, name)); + return location; +} + +void bindAttribute(AttributeLocation location, + std::size_t count, + DataType type, + std::size_t vertexSize, + std::size_t vertexOffset, + std::size_t attributeOffset) { + MBGL_CHECK_ERROR(glEnableVertexAttribArray(location)); + MBGL_CHECK_ERROR(glVertexAttribPointer( + location, + static_cast<GLint>(count), + static_cast<GLenum>(type), + GL_FALSE, + static_cast<GLsizei>(vertexSize), + reinterpret_cast<GLvoid*>(attributeOffset + (vertexSize * vertexOffset)))); +} + +} // namespace gl +} // namespace mbgl diff --git a/src/mbgl/gl/attribute.hpp b/src/mbgl/gl/attribute.hpp index 8bc474e967..e45014127b 100644 --- a/src/mbgl/gl/attribute.hpp +++ b/src/mbgl/gl/attribute.hpp @@ -1,50 +1,171 @@ #pragma once #include <mbgl/gl/types.hpp> -#include <mbgl/gl/shader.hpp> +#include <mbgl/util/ignore.hpp> +#include <mbgl/util/indexed_tuple.hpp> #include <cstddef> -#include <limits> -#include <vector> +#include <functional> namespace mbgl { namespace gl { -template <typename T, std::size_t N> +template <class Tag, class T, std::size_t N> class Attribute { public: - Attribute(const char* name, const Shader& shader) - : location(shader.getAttributeLocation(name)) {} + using Type = T[N]; - AttributeLocation location; + class State { + public: + explicit State(AttributeLocation location_) + : location(location_) {} + + AttributeLocation location; + static constexpr std::size_t count = N; + static constexpr DataType type = DataTypeOf<T>::value; + }; }; -class AttributeBinding { +#define MBGL_DEFINE_ATTRIBUTE(type_, n_, name_) \ + struct name_ : ::mbgl::gl::Attribute<name_, type_, n_> { static constexpr auto name = #name_; } + +namespace detail { + +// Attribute binding requires member offsets. The only standard way to +// obtain an offset is the offsetof macro. The offsetof macro has defined +// behavior only for standard layout types. That rules out std::tuple and +// any other solution that relies on chained inheritance. Manually implemented +// variadic specialization looks like the only solution. Fortunately, we +// only use a maximum of five attributes. + +template <class... As> +class Vertex; + +template <class A1> +class Vertex<A1> { public: - template <class Vertex, class T, std::size_t N, std::size_t O> - AttributeBinding(const T (Vertex::*)[N], const Attribute<T, N>& attribute, std::integral_constant<std::size_t, O>) - : location(attribute.location), - type(DataTypeOf<T>::value), - count(N), - offset(O) { - static_assert(std::is_standard_layout<Vertex>::value, "vertex type must use standard layout"); - static_assert(O % 4 == 0, "vertex attribute must be optimally aligned"); - static_assert(1 <= N && N <= 4, "count must be 1, 2, 3, or 4"); - static_assert(sizeof(Vertex) <= std::numeric_limits<int32_t>::max(), "vertex type is too big"); - } + typename A1::Type a1; - AttributeLocation location; - DataType type; - uint8_t count; - std::size_t offset; + using VertexType = Vertex<A1>; + static const std::size_t attributeOffsets[1]; }; -#define MBGL_MAKE_ATTRIBUTE_BINDING(Vertex, shader, name) \ - ::mbgl::gl::AttributeBinding(&Vertex::name, \ - shader.name, \ - std::integral_constant<std::size_t, offsetof(Vertex, name)>()) +template <class A1, class A2> +class Vertex<A1, A2> { +public: + typename A1::Type a1; + typename A2::Type a2; + + using VertexType = Vertex<A1, A2>; + static const std::size_t attributeOffsets[2]; +}; + +template <class A1, class A2, class A3> +class Vertex<A1, A2, A3> { +public: + typename A1::Type a1; + typename A2::Type a2; + typename A3::Type a3; + + using VertexType = Vertex<A1, A2, A3>; + static const std::size_t attributeOffsets[3]; +}; + +template <class A1, class A2, class A3, class A4> +class Vertex<A1, A2, A3, A4> { +public: + typename A1::Type a1; + typename A2::Type a2; + typename A3::Type a3; + typename A4::Type a4; + + using VertexType = Vertex<A1, A2, A3, A4>; + static const std::size_t attributeOffsets[4]; +}; + +template <class A1, class A2, class A3, class A4, class A5> +class Vertex<A1, A2, A3, A4, A5> { +public: + typename A1::Type a1; + typename A2::Type a2; + typename A3::Type a3; + typename A4::Type a4; + typename A5::Type a5; + + using VertexType = Vertex<A1, A2, A3, A4, A5>; + static const std::size_t attributeOffsets[5]; +}; -template <class Shader, class Vertex> struct AttributeBindings; +template <class A1> +const std::size_t Vertex<A1>::attributeOffsets[1] = { + offsetof(VertexType, a1) +}; + +template <class A1, class A2> +const std::size_t Vertex<A1, A2>::attributeOffsets[2] = { + offsetof(VertexType, a1), + offsetof(VertexType, a2) +}; + +template <class A1, class A2, class A3> +const std::size_t Vertex<A1, A2, A3>::attributeOffsets[3] = { + offsetof(VertexType, a1), + offsetof(VertexType, a2), + offsetof(VertexType, a3) +}; + +template <class A1, class A2, class A3, class A4> +const std::size_t Vertex<A1, A2, A3, A4>::attributeOffsets[4] = { + offsetof(VertexType, a1), + offsetof(VertexType, a2), + offsetof(VertexType, a3), + offsetof(VertexType, a4) +}; + +template <class A1, class A2, class A3, class A4, class A5> +const std::size_t Vertex<A1, A2, A3, A4, A5>::attributeOffsets[5] = { + offsetof(VertexType, a1), + offsetof(VertexType, a2), + offsetof(VertexType, a3), + offsetof(VertexType, a4), + offsetof(VertexType, a5) +}; + +} // namespace detail + +AttributeLocation bindAttributeLocation(ProgramID, AttributeLocation, const char * name); + +void bindAttribute(AttributeLocation location, + std::size_t count, + DataType type, + std::size_t vertexSize, + std::size_t vertexOffset, + std::size_t attributeOffset); + +template <class... As> +class Attributes { +public: + using State = IndexedTuple<TypeList<As...>, TypeList<typename As::State...>>; + using Vertex = detail::Vertex<As...>; + + template <class A> + static constexpr std::size_t Index = TypeIndex<A, As...>::value; + + static State state(const ProgramID& id) { + return State { typename As::State(bindAttributeLocation(id, Index<As>, As::name))... }; + } + + static std::function<void (std::size_t)> binder(const State& state) { + return [&state] (std::size_t vertexOffset) { + util::ignore({ (bindAttribute(state.template get<As>().location, + state.template get<As>().count, + state.template get<As>().type, + sizeof(Vertex), + vertexOffset, + Vertex::attributeOffsets[Index<As>]), 0)... }); + }; + } +}; } // namespace gl } // namespace mbgl diff --git a/src/mbgl/gl/color_mode.cpp b/src/mbgl/gl/color_mode.cpp new file mode 100644 index 0000000000..e838c8e2ff --- /dev/null +++ b/src/mbgl/gl/color_mode.cpp @@ -0,0 +1,44 @@ +#include <mbgl/gl/color_mode.hpp> +#include <mbgl/gl/gl.hpp> +#include <mbgl/util/traits.hpp> + +namespace mbgl { +namespace gl { + +static_assert(underlying_type(ColorMode::BlendEquation::Add) == GL_FUNC_ADD, "OpenGL enum mismatch"); +static_assert(underlying_type(ColorMode::BlendEquation::Subtract) == GL_FUNC_SUBTRACT, "OpenGL enum mismatch"); +static_assert(underlying_type(ColorMode::BlendEquation::ReverseSubtract) == GL_FUNC_REVERSE_SUBTRACT, "OpenGL enum mismatch"); + +static_assert(underlying_type(ColorMode::Zero) == GL_ZERO, "OpenGL enum mismatch"); +static_assert(underlying_type(ColorMode::One) == GL_ONE, "OpenGL enum mismatch"); +static_assert(underlying_type(ColorMode::SrcColor) == GL_SRC_COLOR, "OpenGL enum mismatch"); +static_assert(underlying_type(ColorMode::OneMinusSrcColor) == GL_ONE_MINUS_SRC_COLOR, "OpenGL enum mismatch"); +static_assert(underlying_type(ColorMode::DstColor) == GL_DST_COLOR, "OpenGL enum mismatch"); +static_assert(underlying_type(ColorMode::OneMinusDstColor) == GL_ONE_MINUS_DST_COLOR, "OpenGL enum mismatch"); +static_assert(underlying_type(ColorMode::SrcAlpha) == GL_SRC_ALPHA, "OpenGL enum mismatch"); +static_assert(underlying_type(ColorMode::OneMinusSrcAlpha) == GL_ONE_MINUS_SRC_ALPHA, "OpenGL enum mismatch"); +static_assert(underlying_type(ColorMode::DstAlpha) == GL_DST_ALPHA, "OpenGL enum mismatch"); +static_assert(underlying_type(ColorMode::OneMinusDstAlpha) == GL_ONE_MINUS_DST_ALPHA, "OpenGL enum mismatch"); +static_assert(underlying_type(ColorMode::ConstantColor) == GL_CONSTANT_COLOR, "OpenGL enum mismatch"); +static_assert(underlying_type(ColorMode::OneMinusConstantColor) == GL_ONE_MINUS_CONSTANT_COLOR, "OpenGL enum mismatch"); +static_assert(underlying_type(ColorMode::ConstantAlpha) == GL_CONSTANT_ALPHA, "OpenGL enum mismatch"); +static_assert(underlying_type(ColorMode::OneMinusConstantAlpha) == GL_ONE_MINUS_CONSTANT_ALPHA, "OpenGL enum mismatch"); +static_assert(underlying_type(ColorMode::SrcAlphaSaturate) == GL_SRC_ALPHA_SATURATE, "OpenGL enum mismatch"); + +static_assert(underlying_type(ColorMode::Zero) == GL_ZERO, "OpenGL enum mismatch"); +static_assert(underlying_type(ColorMode::One) == GL_ONE, "OpenGL enum mismatch"); +static_assert(underlying_type(ColorMode::SrcColor) == GL_SRC_COLOR, "OpenGL enum mismatch"); +static_assert(underlying_type(ColorMode::OneMinusSrcColor) == GL_ONE_MINUS_SRC_COLOR, "OpenGL enum mismatch"); +static_assert(underlying_type(ColorMode::DstColor) == GL_DST_COLOR, "OpenGL enum mismatch"); +static_assert(underlying_type(ColorMode::OneMinusDstColor) == GL_ONE_MINUS_DST_COLOR, "OpenGL enum mismatch"); +static_assert(underlying_type(ColorMode::SrcAlpha) == GL_SRC_ALPHA, "OpenGL enum mismatch"); +static_assert(underlying_type(ColorMode::OneMinusSrcAlpha) == GL_ONE_MINUS_SRC_ALPHA, "OpenGL enum mismatch"); +static_assert(underlying_type(ColorMode::DstAlpha) == GL_DST_ALPHA, "OpenGL enum mismatch"); +static_assert(underlying_type(ColorMode::OneMinusDstAlpha) == GL_ONE_MINUS_DST_ALPHA, "OpenGL enum mismatch"); +static_assert(underlying_type(ColorMode::ConstantColor) == GL_CONSTANT_COLOR, "OpenGL enum mismatch"); +static_assert(underlying_type(ColorMode::OneMinusConstantColor) == GL_ONE_MINUS_CONSTANT_COLOR, "OpenGL enum mismatch"); +static_assert(underlying_type(ColorMode::ConstantAlpha) == GL_CONSTANT_ALPHA, "OpenGL enum mismatch"); +static_assert(underlying_type(ColorMode::OneMinusConstantAlpha) == GL_ONE_MINUS_CONSTANT_ALPHA, "OpenGL enum mismatch"); + +} // namespace gl +} // namespace mbgl diff --git a/src/mbgl/gl/color_mode.hpp b/src/mbgl/gl/color_mode.hpp new file mode 100644 index 0000000000..e73c8737eb --- /dev/null +++ b/src/mbgl/gl/color_mode.hpp @@ -0,0 +1,95 @@ +#pragma once + +#include <mbgl/util/variant.hpp> +#include <mbgl/util/color.hpp> + +namespace mbgl { +namespace gl { + +class ColorMode { +public: + enum class BlendEquation { + Add = 0x8006, + Subtract = 0x800A, + ReverseSubtract = 0x800B + }; + + enum BlendFactor { + Zero = 0x0000, + One = 0x0001, + SrcColor = 0x0300, + OneMinusSrcColor = 0x0301, + SrcAlpha = 0x0302, + OneMinusSrcAlpha = 0x0303, + DstAlpha = 0x0304, + OneMinusDstAlpha = 0x0305, + DstColor = 0x0306, + OneMinusDstColor = 0x0307, + SrcAlphaSaturate = 0x0308, + ConstantColor = 0x8001, + OneMinusConstantColor = 0x8002, + ConstantAlpha = 0x8003, + OneMinusConstantAlpha = 0x8004 + }; + + template <BlendEquation E> + struct ConstantBlend { + static constexpr BlendEquation equation = E; + static constexpr BlendFactor srcFactor = One; + static constexpr BlendFactor dstFactor = One; + }; + + template <BlendEquation E> + struct LinearBlend { + static constexpr BlendEquation equation = E; + BlendFactor srcFactor; + BlendFactor dstFactor; + }; + + struct Replace { + static constexpr BlendEquation equation = BlendEquation::Add; + static constexpr BlendFactor srcFactor = One; + static constexpr BlendFactor dstFactor = One; + }; + + using Add = LinearBlend<BlendEquation::Add>; + using Subtract = LinearBlend<BlendEquation::Subtract>; + using ReverseSubtract = LinearBlend<BlendEquation::ReverseSubtract>; + + using BlendFunction = variant< + Replace, + Add, + Subtract, + ReverseSubtract>; + + BlendFunction blendFunction; + Color blendColor; + + struct Mask { + bool r; + bool g; + bool b; + bool a; + }; + + Mask mask; + + static ColorMode disabled() { + return ColorMode { Replace(), {}, { false, false, false, false } }; + } + + static ColorMode unblended() { + return ColorMode { Replace(), {}, { true, true, true, true } }; + } + + static ColorMode alphaBlended() { + return ColorMode { Add { One, OneMinusSrcAlpha }, {}, { true, true, true, true } }; + } +}; + +constexpr bool operator!=(const ColorMode::Mask& a, const ColorMode::Mask& b) { + return a.r != b.r || a.g != b.g || a.b != b.b || a.a != b.a; +} + +} // namespace gl +} // namespace mbgl diff --git a/src/mbgl/gl/context.cpp b/src/mbgl/gl/context.cpp index 23b28a15df..5048ffcd66 100644 --- a/src/mbgl/gl/context.cpp +++ b/src/mbgl/gl/context.cpp @@ -3,10 +3,25 @@ #include <mbgl/gl/gl.hpp> #include <mbgl/gl/vertex_array.hpp> #include <mbgl/util/traits.hpp> +#include <mbgl/util/std.hpp> +#include <mbgl/util/logging.hpp> + +#include <cstring> namespace mbgl { namespace gl { +static_assert(underlying_type(ShaderType::Vertex) == GL_VERTEX_SHADER, "OpenGL type mismatch"); +static_assert(underlying_type(ShaderType::Fragment) == GL_FRAGMENT_SHADER, "OpenGL type mismatch"); + +static_assert(underlying_type(PrimitiveType::Points) == GL_POINTS, "OpenGL type mismatch"); +static_assert(underlying_type(PrimitiveType::Lines) == GL_LINES, "OpenGL type mismatch"); +static_assert(underlying_type(PrimitiveType::LineLoop) == GL_LINE_LOOP, "OpenGL type mismatch"); +static_assert(underlying_type(PrimitiveType::LineStrip) == GL_LINE_STRIP, "OpenGL type mismatch"); +static_assert(underlying_type(PrimitiveType::Triangles) == GL_TRIANGLES, "OpenGL type mismatch"); +static_assert(underlying_type(PrimitiveType::TriangleStrip) == GL_TRIANGLE_STRIP, "OpenGL type mismatch"); +static_assert(underlying_type(PrimitiveType::TriangleFan) == GL_TRIANGLE_FAN, "OpenGL type mismatch"); + static_assert(std::is_same<ProgramID, GLuint>::value, "OpenGL type mismatch"); static_assert(std::is_same<ShaderID, GLuint>::value, "OpenGL type mismatch"); static_assert(std::is_same<BufferID, GLuint>::value, "OpenGL type mismatch"); @@ -15,81 +30,66 @@ static_assert(std::is_same<VertexArrayID, GLuint>::value, "OpenGL type mismatch" static_assert(std::is_same<FramebufferID, GLuint>::value, "OpenGL type mismatch"); static_assert(std::is_same<RenderbufferID, GLuint>::value, "OpenGL type mismatch"); -static_assert(std::is_same<StencilValue, GLint>::value, "OpenGL type mismatch"); -static_assert(std::is_same<StencilMaskValue, GLuint>::value, "OpenGL type mismatch"); - -static_assert(underlying_type(StencilTestFunction::Never) == GL_NEVER, "OpenGL enum mismatch"); -static_assert(underlying_type(StencilTestFunction::Less) == GL_LESS, "OpenGL enum mismatch"); -static_assert(underlying_type(StencilTestFunction::Equal) == GL_EQUAL, "OpenGL enum mismatch"); -static_assert(underlying_type(StencilTestFunction::LessEqual) == GL_LEQUAL, "OpenGL enum mismatch"); -static_assert(underlying_type(StencilTestFunction::Greater) == GL_GREATER, "OpenGL enum mismatch"); -static_assert(underlying_type(StencilTestFunction::NotEqual) == GL_NOTEQUAL, "OpenGL enum mismatch"); -static_assert(underlying_type(StencilTestFunction::GreaterEqual) == GL_GEQUAL, "OpenGL enum mismatch"); -static_assert(underlying_type(StencilTestFunction::Always) == GL_ALWAYS, "OpenGL enum mismatch"); - -static_assert(underlying_type(StencilTestOperation::Keep) == GL_KEEP, "OpenGL enum mismatch"); -static_assert(underlying_type(StencilTestOperation::Zero) == GL_ZERO, "OpenGL enum mismatch"); -static_assert(underlying_type(StencilTestOperation::Replace) == GL_REPLACE, "OpenGL enum mismatch"); -static_assert(underlying_type(StencilTestOperation::Increment) == GL_INCR, "OpenGL enum mismatch"); -static_assert(underlying_type(StencilTestOperation::IncrementWrap) == GL_INCR_WRAP, "OpenGL enum mismatch"); -static_assert(underlying_type(StencilTestOperation::Decrement) == GL_DECR, "OpenGL enum mismatch"); -static_assert(underlying_type(StencilTestOperation::DecrementWrap) == GL_DECR_WRAP, "OpenGL enum mismatch"); -static_assert(underlying_type(StencilTestOperation::Invert) == GL_INVERT, "OpenGL enum mismatch"); - -static_assert(underlying_type(DepthTestFunction::Never) == GL_NEVER, "OpenGL enum mismatch"); -static_assert(underlying_type(DepthTestFunction::Less) == GL_LESS, "OpenGL enum mismatch"); -static_assert(underlying_type(DepthTestFunction::Equal) == GL_EQUAL, "OpenGL enum mismatch"); -static_assert(underlying_type(DepthTestFunction::LessEqual) == GL_LEQUAL, "OpenGL enum mismatch"); -static_assert(underlying_type(DepthTestFunction::Greater) == GL_GREATER, "OpenGL enum mismatch"); -static_assert(underlying_type(DepthTestFunction::NotEqual) == GL_NOTEQUAL, "OpenGL enum mismatch"); -static_assert(underlying_type(DepthTestFunction::GreaterEqual) == GL_GEQUAL, "OpenGL enum mismatch"); -static_assert(underlying_type(DepthTestFunction::Always) == GL_ALWAYS, "OpenGL enum mismatch"); - -static_assert(underlying_type(BlendSourceFactor::Zero) == GL_ZERO, "OpenGL enum mismatch"); -static_assert(underlying_type(BlendSourceFactor::One) == GL_ONE, "OpenGL enum mismatch"); -static_assert(underlying_type(BlendSourceFactor::SrcColor) == GL_SRC_COLOR, "OpenGL enum mismatch"); -static_assert(underlying_type(BlendSourceFactor::OneMinusSrcColor) == GL_ONE_MINUS_SRC_COLOR, "OpenGL enum mismatch"); -static_assert(underlying_type(BlendSourceFactor::DstColor) == GL_DST_COLOR, "OpenGL enum mismatch"); -static_assert(underlying_type(BlendSourceFactor::OneMinusDstColor) == GL_ONE_MINUS_DST_COLOR, "OpenGL enum mismatch"); -static_assert(underlying_type(BlendSourceFactor::SrcAlpha) == GL_SRC_ALPHA, "OpenGL enum mismatch"); -static_assert(underlying_type(BlendSourceFactor::OneMinusSrcAlpha) == GL_ONE_MINUS_SRC_ALPHA, "OpenGL enum mismatch"); -static_assert(underlying_type(BlendSourceFactor::DstAlpha) == GL_DST_ALPHA, "OpenGL enum mismatch"); -static_assert(underlying_type(BlendSourceFactor::OneMinusDstAlpha) == GL_ONE_MINUS_DST_ALPHA, "OpenGL enum mismatch"); -static_assert(underlying_type(BlendSourceFactor::ConstantColor) == GL_CONSTANT_COLOR, "OpenGL enum mismatch"); -static_assert(underlying_type(BlendSourceFactor::OneMinusConstantColor) == GL_ONE_MINUS_CONSTANT_COLOR, "OpenGL enum mismatch"); -static_assert(underlying_type(BlendSourceFactor::ConstantAlpha) == GL_CONSTANT_ALPHA, "OpenGL enum mismatch"); -static_assert(underlying_type(BlendSourceFactor::OneMinusConstantAlpha) == GL_ONE_MINUS_CONSTANT_ALPHA, "OpenGL enum mismatch"); -static_assert(underlying_type(BlendSourceFactor::SrcAlphaSaturate) == GL_SRC_ALPHA_SATURATE, "OpenGL enum mismatch"); - -static_assert(underlying_type(BlendDestinationFactor::Zero) == GL_ZERO, "OpenGL enum mismatch"); -static_assert(underlying_type(BlendDestinationFactor::One) == GL_ONE, "OpenGL enum mismatch"); -static_assert(underlying_type(BlendDestinationFactor::SrcColor) == GL_SRC_COLOR, "OpenGL enum mismatch"); -static_assert(underlying_type(BlendDestinationFactor::OneMinusSrcColor) == GL_ONE_MINUS_SRC_COLOR, "OpenGL enum mismatch"); -static_assert(underlying_type(BlendDestinationFactor::DstColor) == GL_DST_COLOR, "OpenGL enum mismatch"); -static_assert(underlying_type(BlendDestinationFactor::OneMinusDstColor) == GL_ONE_MINUS_DST_COLOR, "OpenGL enum mismatch"); -static_assert(underlying_type(BlendDestinationFactor::SrcAlpha) == GL_SRC_ALPHA, "OpenGL enum mismatch"); -static_assert(underlying_type(BlendDestinationFactor::OneMinusSrcAlpha) == GL_ONE_MINUS_SRC_ALPHA, "OpenGL enum mismatch"); -static_assert(underlying_type(BlendDestinationFactor::DstAlpha) == GL_DST_ALPHA, "OpenGL enum mismatch"); -static_assert(underlying_type(BlendDestinationFactor::OneMinusDstAlpha) == GL_ONE_MINUS_DST_ALPHA, "OpenGL enum mismatch"); -static_assert(underlying_type(BlendDestinationFactor::ConstantColor) == GL_CONSTANT_COLOR, "OpenGL enum mismatch"); -static_assert(underlying_type(BlendDestinationFactor::OneMinusConstantColor) == GL_ONE_MINUS_CONSTANT_COLOR, "OpenGL enum mismatch"); -static_assert(underlying_type(BlendDestinationFactor::ConstantAlpha) == GL_CONSTANT_ALPHA, "OpenGL enum mismatch"); -static_assert(underlying_type(BlendDestinationFactor::OneMinusConstantAlpha) == GL_ONE_MINUS_CONSTANT_ALPHA, "OpenGL enum mismatch"); +static_assert(std::is_same<std::underlying_type_t<TextureFormat>, GLenum>::value, "OpenGL type mismatch"); +static_assert(underlying_type(TextureFormat::RGBA) == GL_RGBA, "OpenGL type mismatch"); +static_assert(underlying_type(TextureFormat::Alpha) == GL_ALPHA, "OpenGL type mismatch"); Context::~Context() { reset(); } -UniqueProgram Context::createProgram() { - return UniqueProgram{ MBGL_CHECK_ERROR(glCreateProgram()), { this } }; +UniqueShader Context::createShader(ShaderType type, const std::string& source) { + UniqueShader result { MBGL_CHECK_ERROR(glCreateShader(static_cast<GLenum>(type))), { this } }; + + const GLchar* sources = source.data(); + const GLsizei lengths = static_cast<GLsizei>(source.length()); + MBGL_CHECK_ERROR(glShaderSource(result, 1, &sources, &lengths)); + MBGL_CHECK_ERROR(glCompileShader(result)); + + GLint status = 0; + MBGL_CHECK_ERROR(glGetShaderiv(result, GL_COMPILE_STATUS, &status)); + if (status != 0) { + return result; + } + + GLint logLength; + MBGL_CHECK_ERROR(glGetShaderiv(result, GL_INFO_LOG_LENGTH, &logLength)); + if (logLength > 0) { + const auto log = std::make_unique<GLchar[]>(logLength); + MBGL_CHECK_ERROR(glGetShaderInfoLog(result, logLength, &logLength, log.get())); + Log::Error(Event::Shader, "Shader failed to compile: %s", log.get()); + } + + throw std::runtime_error("shader failed to compile"); } -UniqueShader Context::createVertexShader() { - return UniqueShader{ MBGL_CHECK_ERROR(glCreateShader(GL_VERTEX_SHADER)), { this } }; +UniqueProgram Context::createProgram(ShaderID vertexShader, ShaderID fragmentShader) { + UniqueProgram result { MBGL_CHECK_ERROR(glCreateProgram()), { this } }; + + MBGL_CHECK_ERROR(glAttachShader(result, vertexShader)); + MBGL_CHECK_ERROR(glAttachShader(result, fragmentShader)); + + return result; } -UniqueShader Context::createFragmentShader() { - return UniqueShader{ MBGL_CHECK_ERROR(glCreateShader(GL_FRAGMENT_SHADER)), { this } }; +void Context::linkProgram(ProgramID program_) { + MBGL_CHECK_ERROR(glLinkProgram(program_)); + + GLint status; + MBGL_CHECK_ERROR(glGetProgramiv(program_, GL_LINK_STATUS, &status)); + if (status == GL_TRUE) { + return; + } + + GLint logLength; + MBGL_CHECK_ERROR(glGetProgramiv(program_, GL_INFO_LOG_LENGTH, &logLength)); + const auto log = std::make_unique<GLchar[]>(logLength); + if (logLength > 0) { + MBGL_CHECK_ERROR(glGetProgramInfoLog(program_, logLength, &logLength, log.get())); + Log::Error(Event::Shader, "Program failed to link: %s", log.get()); + } + + throw std::runtime_error("program failed to link"); } UniqueBuffer Context::createVertexBuffer(const void* data, std::size_t size) { @@ -105,21 +105,12 @@ UniqueBuffer Context::createIndexBuffer(const void* data, std::size_t size) { BufferID id = 0; MBGL_CHECK_ERROR(glGenBuffers(1, &id)); UniqueBuffer result { std::move(id), { this } }; + vertexArrayObject = 0; elementBuffer = result; MBGL_CHECK_ERROR(glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, data, GL_STATIC_DRAW)); return result; } -void Context::bindAttribute(const AttributeBinding& binding, std::size_t stride, const int8_t* offset) { - MBGL_CHECK_ERROR(glEnableVertexAttribArray(binding.location)); - MBGL_CHECK_ERROR(glVertexAttribPointer(binding.location, - binding.count, - static_cast<GLenum>(binding.type), - false, - static_cast<GLsizei>(stride), - offset + binding.offset)); -} - UniqueTexture Context::createTexture() { if (pooledTextures.empty()) { pooledTextures.resize(TextureMax); @@ -131,31 +122,60 @@ UniqueTexture Context::createTexture() { return UniqueTexture{ std::move(id), { this } }; } -UniqueVertexArray Context::createVertexArray() { - VertexArrayID id = 0; - MBGL_CHECK_ERROR(gl::GenVertexArrays(1, &id)); - return UniqueVertexArray{ std::move(id), { this } }; -} - UniqueFramebuffer Context::createFramebuffer() { FramebufferID id = 0; MBGL_CHECK_ERROR(glGenFramebuffers(1, &id)); return UniqueFramebuffer{ std::move(id), { this } }; } -UniqueRenderbuffer Context::createRenderbuffer(const RenderbufferType type, - const uint16_t width, - const uint16_t height) { +UniqueRenderbuffer Context::createRenderbuffer(const RenderbufferType type, const Size size) { RenderbufferID id = 0; MBGL_CHECK_ERROR(glGenRenderbuffers(1, &id)); UniqueRenderbuffer renderbuffer{ std::move(id), { this } }; bindRenderbuffer = renderbuffer; MBGL_CHECK_ERROR( - glRenderbufferStorage(GL_RENDERBUFFER, static_cast<GLenum>(type), width, height)); + glRenderbufferStorage(GL_RENDERBUFFER, static_cast<GLenum>(type), size.width, size.height)); return renderbuffer; } +std::unique_ptr<uint8_t[]> Context::readFramebuffer(const Size size, const TextureFormat format, const bool flip) { + const size_t stride = size.width * (format == TextureFormat::RGBA ? 4 : 1); + auto data = std::make_unique<uint8_t[]>(stride * size.height); + +#if not MBGL_USE_GLES2 + // When reading data from the framebuffer, make sure that we are storing the values + // tightly packed into the buffer to avoid buffer overruns. + pixelStorePack = { 1 }; +#endif // MBGL_USE_GLES2 + + MBGL_CHECK_ERROR(glReadPixels(0, 0, size.width, size.height, static_cast<GLenum>(format), + GL_UNSIGNED_BYTE, data.get())); + + if (flip) { + auto tmp = std::make_unique<uint8_t[]>(stride); + uint8_t* rgba = data.get(); + for (int i = 0, j = size.height - 1; i < j; i++, j--) { + std::memcpy(tmp.get(), rgba + i * stride, stride); + std::memcpy(rgba + i * stride, rgba + j * stride, stride); + std::memcpy(rgba + j * stride, tmp.get(), stride); + } + } + + return data; +} + +#if not MBGL_USE_GLES2 +void Context::drawPixels(const Size size, const void* data, TextureFormat format) { + pixelStoreUnpack = { 1 }; + if (format != TextureFormat::RGBA) { + format = static_cast<TextureFormat>(GL_LUMINANCE); + } + MBGL_CHECK_ERROR(glDrawPixels(size.width, size.height, static_cast<GLenum>(GL_LUMINANCE), + GL_UNSIGNED_BYTE, data)); +} +#endif // MBGL_USE_GLES2 + namespace { void checkFramebuffer() { @@ -251,35 +271,62 @@ Framebuffer Context::createFramebuffer(const Texture& color) { } UniqueTexture -Context::createTexture(uint16_t width, uint16_t height, const void* data, TextureUnit unit) { +Context::createTexture(const Size size, const void* data, TextureFormat format, TextureUnit unit) { auto obj = createTexture(); - activeTexture = unit; - texture[unit] = obj; + updateTexture(obj, size, data, format, unit); + // We are using clamp to edge here since OpenGL ES doesn't allow GL_REPEAT on NPOT textures. + // We use those when the pixelRatio isn't a power of two, e.g. on iPhone 6 Plus. 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)); MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)); MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)); - MBGL_CHECK_ERROR( - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data)); return obj; } +void Context::updateTexture( + TextureID id, const Size size, const void* data, TextureFormat format, TextureUnit unit) { + activeTexture = unit; + texture[unit] = id; + MBGL_CHECK_ERROR(glTexImage2D(GL_TEXTURE_2D, 0, static_cast<GLenum>(format), size.width, + size.height, 0, static_cast<GLenum>(format), GL_UNSIGNED_BYTE, + data)); +} + void Context::bindTexture(Texture& obj, TextureUnit unit, TextureFilter filter, - TextureMipMap mipmap) { - if (filter != obj.filter || mipmap != obj.mipmap) { + TextureMipMap mipmap, + TextureWrap wrapX, + TextureWrap wrapY) { + if (filter != obj.filter || mipmap != obj.mipmap || wrapX != obj.wrapX || wrapY != obj.wrapY) { activeTexture = unit; texture[unit] = obj.texture; - MBGL_CHECK_ERROR(glTexParameteri( - GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, - filter == TextureFilter::Linear - ? (mipmap == TextureMipMap::Yes ? GL_LINEAR_MIPMAP_NEAREST : GL_LINEAR) - : (mipmap == TextureMipMap::Yes ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST))); - MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, - filter == TextureFilter::Linear ? GL_LINEAR : GL_NEAREST)); - obj.filter = filter; - obj.mipmap = mipmap; + + if (filter != obj.filter || mipmap != obj.mipmap) { + MBGL_CHECK_ERROR(glTexParameteri( + GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, + filter == TextureFilter::Linear + ? (mipmap == TextureMipMap::Yes ? GL_LINEAR_MIPMAP_NEAREST : GL_LINEAR) + : (mipmap == TextureMipMap::Yes ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST))); + MBGL_CHECK_ERROR( + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, + filter == TextureFilter::Linear ? GL_LINEAR : GL_NEAREST)); + obj.filter = filter; + obj.mipmap = mipmap; + } + if (wrapX != obj.wrapX) { + + MBGL_CHECK_ERROR( + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, + wrapX == TextureWrap::Clamp ? GL_CLAMP_TO_EDGE : GL_REPEAT)); + obj.wrapX = wrapX; + } + if (wrapY != obj.wrapY) { + MBGL_CHECK_ERROR( + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, + wrapY == TextureWrap::Clamp ? GL_CLAMP_TO_EDGE : GL_REPEAT)); + obj.wrapY = wrapY; + } } else if (texture[unit] != obj.texture) { // We are checking first to avoid setting the active texture without a subsequent // texture bind. @@ -306,6 +353,7 @@ void Context::setDirtyState() { depthTest.setDirty(); depthFunc.setDirty(); blend.setDirty(); + blendEquation.setDirty(); blendFunc.setDirty(); blendColor.setDirty(); colorMask.setDirty(); @@ -316,8 +364,13 @@ void Context::setDirtyState() { lineWidth.setDirty(); activeTexture.setDirty(); #if not MBGL_USE_GLES2 + pointSize.setDirty(); pixelZoom.setDirty(); rasterPos.setDirty(); + pixelStorePack.setDirty(); + pixelStoreUnpack.setDirty(); + pixelTransferDepth.setDirty(); + pixelTransferStencil.setDirty(); #endif // MBGL_USE_GLES2 for (auto& tex : texture) { tex.setDirty(); @@ -327,6 +380,153 @@ void Context::setDirtyState() { vertexArrayObject.setDirty(); } +void Context::clear(optional<mbgl::Color> color, + optional<float> depth, + optional<int32_t> stencil) { + GLbitfield mask = 0; + + if (color) { + mask |= GL_COLOR_BUFFER_BIT; + clearColor = *color; + colorMask = { true, true, true, true }; + } + + if (depth) { + mask |= GL_DEPTH_BUFFER_BIT; + clearDepth = *depth; + depthMask = true; + } + + if (stencil) { + mask |= GL_STENCIL_BUFFER_BIT; + clearStencil = *stencil; + stencilMask = 0xFF; + } + + MBGL_CHECK_ERROR(glClear(mask)); +} + +#if not MBGL_USE_GLES2 +PrimitiveType Context::operator()(const Points& points) { + pointSize = points.pointSize; + return PrimitiveType::Points; +} +#else +PrimitiveType Context::operator()(const Points&) { + return PrimitiveType::Points; +} +#endif // MBGL_USE_GLES2 + +PrimitiveType Context::operator()(const Lines& lines) { + lineWidth = lines.lineWidth; + return PrimitiveType::Lines; +} + +PrimitiveType Context::operator()(const LineStrip& lineStrip) { + lineWidth = lineStrip.lineWidth; + return PrimitiveType::LineStrip; +} + +PrimitiveType Context::operator()(const Triangles&) { + return PrimitiveType::Triangles; +} + +PrimitiveType Context::operator()(const TriangleStrip&) { + return PrimitiveType::TriangleStrip; +} + +void Context::setDepthMode(const DepthMode& depth) { + if (depth.func == DepthMode::Always && !depth.mask) { + depthTest = false; + } else { + depthTest = true; + depthFunc = depth.func; + depthMask = depth.mask; + depthRange = depth.range; + } +} + +void Context::setStencilMode(const StencilMode& stencil) { + if (stencil.test.is<StencilMode::Always>() && !stencil.mask) { + stencilTest = false; + } else { + stencilTest = true; + stencilMask = stencil.mask; + stencilOp = { stencil.fail, stencil.depthFail, stencil.pass }; + apply_visitor([&] (const auto& test) { + stencilFunc = { test.func, stencil.ref, test.mask }; + }, stencil.test); + } +} + +void Context::setColorMode(const ColorMode& color) { + if (color.blendFunction.is<ColorMode::Replace>()) { + blend = false; + } else { + blend = true; + blendColor = color.blendColor; + apply_visitor([&] (const auto& blendFunction) { + blendEquation = ColorMode::BlendEquation(blendFunction.equation); + blendFunc = { blendFunction.srcFactor, blendFunction.dstFactor }; + }, color.blendFunction); + } + + colorMask = color.mask; +} + +void Context::draw(const Drawable& drawable) { + if (drawable.segments.empty()) { + return; + } + + PrimitiveType primitiveType = apply_visitor([&] (auto m) { return (*this)(m); }, drawable.drawMode); + + setDepthMode(drawable.depthMode); + setStencilMode(drawable.stencilMode); + setColorMode(drawable.colorMode); + + program = drawable.program; + + drawable.bindUniforms(); + + for (const auto& segment : drawable.segments) { + auto needAttributeBindings = [&] () { + if (!gl::GenVertexArrays || !gl::BindVertexArray) { + return true; + } + + if (segment.vao) { + vertexArrayObject = *segment.vao; + return false; + } + + VertexArrayID id = 0; + MBGL_CHECK_ERROR(gl::GenVertexArrays(1, &id)); + vertexArrayObject = id; + segment.vao = UniqueVertexArray(std::move(id), { this }); + + // If we are initializing a new VAO, we need to force the buffers + // to be rebound. VAOs don't inherit the existing buffer bindings. + vertexBuffer.setDirty(); + elementBuffer.setDirty(); + + return true; + }; + + if (needAttributeBindings()) { + vertexBuffer = drawable.vertexBuffer; + elementBuffer = drawable.indexBuffer; + drawable.bindAttributes(segment.vertexOffset); + } + + MBGL_CHECK_ERROR(glDrawElements( + static_cast<GLenum>(primitiveType), + static_cast<GLsizei>(segment.indexLength), + GL_UNSIGNED_SHORT, + reinterpret_cast<GLvoid*>(sizeof(uint16_t) * segment.indexOffset))); + } +} + void Context::performCleanup() { for (auto id : abandonedPrograms) { if (program == id) { diff --git a/src/mbgl/gl/context.hpp b/src/mbgl/gl/context.hpp index cf8bb2658b..093afa20ed 100644 --- a/src/mbgl/gl/context.hpp +++ b/src/mbgl/gl/context.hpp @@ -8,12 +8,21 @@ #include <mbgl/gl/framebuffer.hpp> #include <mbgl/gl/vertex_buffer.hpp> #include <mbgl/gl/index_buffer.hpp> -#include <mbgl/gl/attribute.hpp> +#include <mbgl/gl/types.hpp> +#include <mbgl/gl/draw_mode.hpp> +#include <mbgl/gl/depth_mode.hpp> +#include <mbgl/gl/stencil_mode.hpp> +#include <mbgl/gl/color_mode.hpp> +#include <mbgl/gl/segment.hpp> #include <mbgl/util/noncopyable.hpp> + +#include <functional> #include <memory> #include <vector> #include <array> +#include <string> +#include <unordered_map> namespace mbgl { @@ -27,32 +36,31 @@ class Context : private util::noncopyable { public: ~Context(); - UniqueProgram createProgram(); - UniqueShader createVertexShader(); - UniqueShader createFragmentShader(); + UniqueShader createShader(ShaderType type, const std::string& source); + UniqueProgram createProgram(ShaderID vertexShader, ShaderID fragmentShader); + void linkProgram(ProgramID); UniqueTexture createTexture(); - UniqueVertexArray createVertexArray(); - template <class V> - VertexBuffer<V> createVertexBuffer(std::vector<V>&& v) { - return VertexBuffer<V> { - v.size(), - createVertexBuffer(v.data(), v.size() * sizeof(V)) + template <class Vertex, class DrawMode> + VertexBuffer<Vertex, DrawMode> createVertexBuffer(VertexVector<Vertex, DrawMode>&& v) { + return VertexBuffer<Vertex, DrawMode> { + v.vertexSize(), + createVertexBuffer(v.data(), v.byteSize()) }; } - template <class P> - IndexBuffer<P> createIndexBuffer(std::vector<P>&& v) { - return IndexBuffer<P> { - createIndexBuffer(v.data(), v.size() * sizeof(P)) + template <class DrawMode> + IndexBuffer<DrawMode> createIndexBuffer(IndexVector<DrawMode>&& v) { + return IndexBuffer<DrawMode> { + createIndexBuffer(v.data(), v.byteSize()) }; } template <RenderbufferType type> - Renderbuffer<type> createRenderbuffer(const std::array<uint16_t, 2>& size) { + Renderbuffer<type> createRenderbuffer(const Size size) { static_assert(type == RenderbufferType::RGBA || type == RenderbufferType::DepthStencil, "invalid renderbuffer type"); - return { size, createRenderbuffer(type, size[0], size[1]) }; + return { size, createRenderbuffer(type, size) }; } Framebuffer createFramebuffer(const Renderbuffer<RenderbufferType::RGBA>&, @@ -62,30 +70,73 @@ public: const Renderbuffer<RenderbufferType::DepthStencil>&); Framebuffer createFramebuffer(const Texture&); + template <typename Image, + TextureFormat format = Image::channels == 4 ? TextureFormat::RGBA + : TextureFormat::Alpha> + Image readFramebuffer(const Size size, bool flip = true) { + static_assert(Image::channels == (format == TextureFormat::RGBA ? 4 : 1), + "image format mismatch"); + return { size, readFramebuffer(size, format, flip) }; + } + +#if not MBGL_USE_GLES2 + template <typename Image> + void drawPixels(const Image& image) { + auto format = image.channels == 4 ? TextureFormat::RGBA : TextureFormat::Alpha; + drawPixels(image.size, image.data.get(), format); + } +#endif // MBGL_USE_GLES2 + // Create a texture from an image with data. template <typename Image> Texture createTexture(const Image& image, TextureUnit unit = 0) { - return { {{ image.width, image.height }}, - createTexture(image.width, image.height, image.data.get(), unit) }; + auto format = image.channels == 4 ? TextureFormat::RGBA : TextureFormat::Alpha; + return { image.size, createTexture(image.size, image.data.get(), format, unit) }; + } + + template <typename Image> + void updateTexture(Texture& obj, const Image& image, TextureUnit unit = 0) { + auto format = image.channels == 4 ? TextureFormat::RGBA : TextureFormat::Alpha; + updateTexture(obj.texture.get(), image.size, image.data.get(), format, unit); + obj.size = image.size; } // Creates an empty texture with the specified dimensions. - Texture createTexture(const std::array<uint16_t, 2>& size, TextureUnit unit = 0) { - return { size, createTexture(size[0], size[1], nullptr, unit) }; + Texture createTexture(const Size size, + TextureFormat format = TextureFormat::RGBA, + TextureUnit unit = 0) { + return { size, createTexture(size, nullptr, format, unit) }; } void bindTexture(Texture&, TextureUnit = 0, TextureFilter = TextureFilter::Nearest, - TextureMipMap = TextureMipMap::No); - - template <class Shader, class Vertex> - void bindAttributes(const Shader& shader, const VertexBuffer<Vertex>&, const int8_t* offset) { - static_assert(std::is_same<typename Shader::VertexType, Vertex>::value, "vertex type mismatch"); - for (const auto& binding : AttributeBindings<Shader, Vertex>()(shader)) { - bindAttribute(binding, sizeof(Vertex), offset); - } - } + TextureMipMap = TextureMipMap::No, + TextureWrap wrapX = TextureWrap::Clamp, + TextureWrap wrapY = TextureWrap::Clamp); + + void clear(optional<mbgl::Color> color, + optional<float> depth, + optional<int32_t> stencil); + + struct Drawable { + DrawMode drawMode; + DepthMode depthMode; + StencilMode stencilMode; + ColorMode colorMode; + gl::ProgramID program; + gl::BufferID vertexBuffer; + gl::BufferID indexBuffer; + const std::vector<Segment>& segments; + std::function<void ()> bindUniforms; + std::function<void (std::size_t)> bindAttributes; + }; + + void draw(const Drawable&); + + void setDepthMode(const DepthMode&); + void setStencilMode(const StencilMode&); + void setColorMode(const ColorMode&); // Actually remove the objects we marked as abandoned with the above methods. // Only call this while the OpenGL context is exclusive to this thread. @@ -107,6 +158,23 @@ public: void setDirtyState(); + State<value::ActiveTexture> activeTexture; + State<value::BindFramebuffer> bindFramebuffer; + State<value::Viewport> viewport; + std::array<State<value::BindTexture>, 2> texture; + State<value::BindVertexArray> vertexArrayObject; + State<value::Program> program; + +#if not MBGL_USE_GLES2 + State<value::PixelZoom> pixelZoom; + State<value::RasterPos> rasterPos; + State<value::PixelStorePack> pixelStorePack; + State<value::PixelStoreUnpack> pixelStoreUnpack; + State<value::PixelTransferDepth> pixelTransferDepth; + State<value::PixelTransferStencil> pixelTransferStencil; +#endif // MBGL_USE_GLES2 + +private: State<value::StencilFunc> stencilFunc; State<value::StencilMask> stencilMask; State<value::StencilTest> stencilTest; @@ -116,34 +184,37 @@ public: State<value::DepthTest> depthTest; State<value::DepthFunc> depthFunc; State<value::Blend> blend; + State<value::BlendEquation> blendEquation; State<value::BlendFunc> blendFunc; State<value::BlendColor> blendColor; State<value::ColorMask> colorMask; State<value::ClearDepth> clearDepth; State<value::ClearColor> clearColor; State<value::ClearStencil> clearStencil; - State<value::Program> program; State<value::LineWidth> lineWidth; - State<value::ActiveTexture> activeTexture; - State<value::BindFramebuffer> bindFramebuffer; - State<value::Viewport> viewport; State<value::BindRenderbuffer> bindRenderbuffer; #if not MBGL_USE_GLES2 - State<value::PixelZoom> pixelZoom; - State<value::RasterPos> rasterPos; + State<value::PointSize> pointSize; #endif // MBGL_USE_GLES2 - std::array<State<value::BindTexture>, 2> texture; State<value::BindVertexBuffer> vertexBuffer; State<value::BindElementBuffer> elementBuffer; - State<value::BindVertexArray> vertexArrayObject; -private: UniqueBuffer createVertexBuffer(const void* data, std::size_t size); UniqueBuffer createIndexBuffer(const void* data, std::size_t size); - UniqueTexture createTexture(uint16_t width, uint16_t height, const void* data, TextureUnit); + UniqueTexture createTexture(Size size, const void* data, TextureFormat, TextureUnit); + void updateTexture(TextureID, Size size, const void* data, TextureFormat, TextureUnit); UniqueFramebuffer createFramebuffer(); - UniqueRenderbuffer createRenderbuffer(RenderbufferType, uint16_t width, uint16_t height); - void bindAttribute(const AttributeBinding&, std::size_t stride, const int8_t* offset); + UniqueRenderbuffer createRenderbuffer(RenderbufferType, Size size); + std::unique_ptr<uint8_t[]> readFramebuffer(Size, TextureFormat, bool flip); +#if not MBGL_USE_GLES2 + void drawPixels(Size size, const void* data, TextureFormat); +#endif // MBGL_USE_GLES2 + + PrimitiveType operator()(const Points&); + PrimitiveType operator()(const Lines&); + PrimitiveType operator()(const LineStrip&); + PrimitiveType operator()(const Triangles&); + PrimitiveType operator()(const TriangleStrip&); friend detail::ProgramDeleter; friend detail::ShaderDeleter; diff --git a/src/mbgl/gl/debugging.cpp b/src/mbgl/gl/debugging.cpp index 1d82b6afb0..8037fc5ef5 100644 --- a/src/mbgl/gl/debugging.cpp +++ b/src/mbgl/gl/debugging.cpp @@ -2,8 +2,8 @@ #include <mbgl/gl/debugging.hpp> #include <mbgl/gl/gl.hpp> #include <mbgl/gl/extension.hpp> -#include <mbgl/platform/event.hpp> -#include <mbgl/platform/log.hpp> +#include <mbgl/util/event.hpp> +#include <mbgl/util/logging.hpp> #define GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242 #define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH 0x8243 diff --git a/src/mbgl/gl/depth_mode.cpp b/src/mbgl/gl/depth_mode.cpp new file mode 100644 index 0000000000..21af75a391 --- /dev/null +++ b/src/mbgl/gl/depth_mode.cpp @@ -0,0 +1,18 @@ +#include <mbgl/gl/depth_mode.hpp> +#include <mbgl/gl/gl.hpp> +#include <mbgl/util/traits.hpp> + +namespace mbgl { +namespace gl { + +static_assert(underlying_type(DepthMode::Never) == GL_NEVER, "OpenGL enum mismatch"); +static_assert(underlying_type(DepthMode::Less) == GL_LESS, "OpenGL enum mismatch"); +static_assert(underlying_type(DepthMode::Equal) == GL_EQUAL, "OpenGL enum mismatch"); +static_assert(underlying_type(DepthMode::LessEqual) == GL_LEQUAL, "OpenGL enum mismatch"); +static_assert(underlying_type(DepthMode::Greater) == GL_GREATER, "OpenGL enum mismatch"); +static_assert(underlying_type(DepthMode::NotEqual) == GL_NOTEQUAL, "OpenGL enum mismatch"); +static_assert(underlying_type(DepthMode::GreaterEqual) == GL_GEQUAL, "OpenGL enum mismatch"); +static_assert(underlying_type(DepthMode::Always) == GL_ALWAYS, "OpenGL enum mismatch"); + +} // namespace gl +} // namespace mbgl diff --git a/src/mbgl/gl/depth_mode.hpp b/src/mbgl/gl/depth_mode.hpp new file mode 100644 index 0000000000..37617e3c34 --- /dev/null +++ b/src/mbgl/gl/depth_mode.hpp @@ -0,0 +1,36 @@ +#pragma once + +#include <mbgl/util/range.hpp> + +namespace mbgl { +namespace gl { + +class DepthMode { +public: + enum Function { + Never = 0x0200, + Less = 0x0201, + Equal = 0x0202, + LessEqual = 0x0203, + Greater = 0x0204, + NotEqual = 0x0205, + GreaterEqual = 0x0206, + Always = 0x0207 + }; + + enum Mask : bool { + ReadOnly = false, + ReadWrite = true + }; + + Function func; + Mask mask; + Range<float> range; + + static DepthMode disabled() { + return DepthMode { Always, ReadOnly, { 0.0, 1.0 } }; + } +}; + +} // namespace gl +} // namespace mbgl diff --git a/src/mbgl/gl/draw_mode.hpp b/src/mbgl/gl/draw_mode.hpp new file mode 100644 index 0000000000..ab86d5e469 --- /dev/null +++ b/src/mbgl/gl/draw_mode.hpp @@ -0,0 +1,76 @@ +#pragma once + +#include <mbgl/gl/primitives.hpp> +#include <mbgl/util/variant.hpp> + +#include <cassert> + +namespace mbgl { +namespace gl { + +class Points { +public: + using Primitive = Point; + static constexpr std::size_t bufferGroupSize = 1; + + explicit Points(float pointSize_) : pointSize(pointSize_) {} + + float pointSize; +}; + +class Lines { +public: + using Primitive = Line; + static constexpr std::size_t bufferGroupSize = 2; + + explicit Lines(float lineWidth_) : lineWidth(lineWidth_) { + assert(lineWidth > 0); + } + + float lineWidth; +}; + +class LineStrip { +public: + // LineStrip is a form of "Line" rendering, but the element buffer + // cannot be grouped into logical elements beyond a single Point. + using Primitive = Line; + static constexpr std::size_t bufferGroupSize = 1; + + explicit LineStrip(float lineWidth_) : lineWidth(lineWidth_) { + assert(lineWidth > 0); + } + + float lineWidth; +}; + +class Triangles { +public: + using Primitive = Triangle; + static constexpr std::size_t bufferGroupSize = 3; +}; + +class TriangleStrip { +public: + // TriangleStrip is a form of "Triangle" rendering, but the element buffer + // cannot be grouped into logical elements beyond a single Point. + using Primitive = Triangle; + static constexpr std::size_t bufferGroupSize = 1; +}; + +// Special draw mode for use with VertexVector<Indexed, Vertex>, in which +// case the true draw mode is denoted by the IndexVector type. +class Indexed { +public: + static constexpr std::size_t bufferGroupSize = 1; +}; + +using DrawMode = variant< + Points, + Lines, + LineStrip, + Triangles, + TriangleStrip>; + +} // namespace gl +} // namespace mbgl diff --git a/src/mbgl/gl/extension.cpp b/src/mbgl/gl/extension.cpp index ee94e8ecfd..e6b4d9156e 100644 --- a/src/mbgl/gl/extension.cpp +++ b/src/mbgl/gl/extension.cpp @@ -4,6 +4,7 @@ #include <mutex> #include <string> #include <vector> +#include <cstring> namespace mbgl { namespace gl { @@ -26,18 +27,14 @@ 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 : detail::extensionFunctions()) { - for (auto probe : fn.second) { - if (extensions.find(probe.first) != std::string::npos) { - *fn.first = getProcAddress(probe.second); - break; + if (const char* extensions = + reinterpret_cast<const char*>(MBGL_CHECK_ERROR(glGetString(GL_EXTENSIONS)))) { + for (auto fn : detail::extensionFunctions()) { + for (auto probe : fn.second) { + if (strstr(extensions, probe.first) != nullptr) { + *fn.first = getProcAddress(probe.second); + break; + } } } } diff --git a/src/mbgl/gl/framebuffer.hpp b/src/mbgl/gl/framebuffer.hpp index 880fed159e..91ed467b40 100644 --- a/src/mbgl/gl/framebuffer.hpp +++ b/src/mbgl/gl/framebuffer.hpp @@ -1,15 +1,14 @@ #pragma once #include <mbgl/gl/object.hpp> - -#include <array> +#include <mbgl/util/size.hpp> namespace mbgl { namespace gl { class Framebuffer { public: - std::array<uint16_t, 2> size; + Size size; gl::UniqueFramebuffer framebuffer; }; diff --git a/src/mbgl/gl/index_buffer.hpp b/src/mbgl/gl/index_buffer.hpp index f38d7fd4f5..b3610f4154 100644 --- a/src/mbgl/gl/index_buffer.hpp +++ b/src/mbgl/gl/index_buffer.hpp @@ -1,39 +1,38 @@ #pragma once #include <mbgl/gl/object.hpp> +#include <mbgl/gl/draw_mode.hpp> +#include <mbgl/util/ignore.hpp> + +#include <vector> namespace mbgl { namespace gl { -class Line { +template <class DrawMode> +class IndexVector { public: - Line(uint16_t a_, uint16_t b_) - : a(a_), b(b_) {} - - uint16_t a; - uint16_t b; + static constexpr std::size_t groupSize = DrawMode::bufferGroupSize; - static constexpr std::size_t IndexCount = 2; -}; + template <class... Args> + void emplace_back(Args&&... args) { + static_assert(sizeof...(args) == groupSize, "wrong buffer element count"); + util::ignore({(v.emplace_back(std::forward<Args>(args)), 0)...}); + } -class Triangle { -public: - Triangle(uint16_t a_, uint16_t b_, uint16_t c_) - : a(a_), b(b_), c(c_) {} + std::size_t indexSize() const { return v.size(); } + std::size_t byteSize() const { return v.size() * sizeof(uint16_t); } - uint16_t a; - uint16_t b; - uint16_t c; + bool empty() const { return v.empty(); } + const uint16_t* data() const { return v.data(); } - static constexpr std::size_t IndexCount = 3; +private: + std::vector<uint16_t> v; }; -template <class Primitive> +template <class DrawMode> class IndexBuffer { public: - static_assert(std::is_same<Primitive, Line>::value || std::is_same<Primitive, Triangle>::value, - "primitive must be Line or Triangle"); - static constexpr std::size_t primitiveSize = sizeof(Primitive); UniqueBuffer buffer; }; diff --git a/src/mbgl/gl/primitives.hpp b/src/mbgl/gl/primitives.hpp new file mode 100644 index 0000000000..fe6b1b2e5b --- /dev/null +++ b/src/mbgl/gl/primitives.hpp @@ -0,0 +1,22 @@ +#pragma once + +namespace mbgl { +namespace gl { + +class Point { +public: + static constexpr std::size_t vertexCount = 1; +}; + +class Line { +public: + static constexpr std::size_t vertexCount = 2; +}; + +class Triangle { +public: + static constexpr std::size_t vertexCount = 3; +}; + +} // namespace gl +} // namespace mbgl diff --git a/src/mbgl/gl/program.hpp b/src/mbgl/gl/program.hpp new file mode 100644 index 0000000000..33387e9d4e --- /dev/null +++ b/src/mbgl/gl/program.hpp @@ -0,0 +1,70 @@ +#pragma once + +#include <mbgl/gl/types.hpp> +#include <mbgl/gl/object.hpp> +#include <mbgl/gl/context.hpp> +#include <mbgl/gl/vertex_buffer.hpp> +#include <mbgl/gl/index_buffer.hpp> +#include <mbgl/gl/attribute.hpp> +#include <mbgl/gl/uniform.hpp> + +#include <string> + +namespace mbgl { +namespace gl { + +template <class P, class As, class Us> +class Program { +public: + using Primitive = P; + using Attributes = As; + using Uniforms = Us; + + using Vertex = typename Attributes::Vertex; + using UniformValues = typename Uniforms::Values; + + static_assert(std::is_standard_layout<Vertex>::value, "vertex type must use standard layout"); + + Program(Context& context, const std::string& vertexSource, const std::string& fragmentSource) + : vertexShader(context.createShader(ShaderType::Vertex, vertexSource)), + fragmentShader(context.createShader(ShaderType::Fragment, fragmentSource)), + program(context.createProgram(vertexShader, fragmentShader)), + attributesState(Attributes::state(program)), + uniformsState((context.linkProgram(program), Uniforms::state(program))) {} + + template <class DrawMode> + void draw(Context& context, + DrawMode drawMode, + DepthMode depthMode, + StencilMode stencilMode, + ColorMode colorMode, + UniformValues&& uniformValues, + const VertexBuffer<Vertex>& vertexBuffer, + const IndexBuffer<DrawMode>& indexBuffer, + const SegmentVector<Attributes>& segments) { + static_assert(std::is_same<Primitive, typename DrawMode::Primitive>::value, "incompatible draw mode"); + context.draw({ + std::move(drawMode), + std::move(depthMode), + std::move(stencilMode), + std::move(colorMode), + program, + vertexBuffer.buffer, + indexBuffer.buffer, + segments, + Uniforms::binder(uniformsState, std::move(uniformValues)), + Attributes::binder(attributesState) + }); + } + +private: + UniqueShader vertexShader; + UniqueShader fragmentShader; + UniqueProgram program; + + typename Attributes::State attributesState; + typename Uniforms::State uniformsState; +}; + +} // namespace gl +} // namespace mbgl diff --git a/src/mbgl/gl/renderbuffer.hpp b/src/mbgl/gl/renderbuffer.hpp index 9e8993bb77..cc8ff13268 100644 --- a/src/mbgl/gl/renderbuffer.hpp +++ b/src/mbgl/gl/renderbuffer.hpp @@ -1,8 +1,7 @@ #pragma once #include <mbgl/gl/object.hpp> - -#include <array> +#include <mbgl/util/size.hpp> namespace mbgl { namespace gl { @@ -11,7 +10,7 @@ template <RenderbufferType renderbufferType> class Renderbuffer { public: using type = std::integral_constant<RenderbufferType, renderbufferType>; - std::array<uint16_t, 2> size; + Size size; gl::UniqueRenderbuffer renderbuffer; }; diff --git a/src/mbgl/gl/segment.hpp b/src/mbgl/gl/segment.hpp new file mode 100644 index 0000000000..8f74afd237 --- /dev/null +++ b/src/mbgl/gl/segment.hpp @@ -0,0 +1,39 @@ +#pragma once + +#include <mbgl/util/optional.hpp> + +#include <cstddef> + +namespace mbgl { +namespace gl { + +class Segment { +public: + Segment(std::size_t vertexOffset_, + std::size_t indexOffset_, + std::size_t vertexLength_ = 0, + std::size_t indexLength_ = 0) + : vertexOffset(vertexOffset_), + indexOffset(indexOffset_), + vertexLength(vertexLength_), + indexLength(indexLength_) {} + + const std::size_t vertexOffset; + const std::size_t indexOffset; + + std::size_t vertexLength; + std::size_t indexLength; + +private: + friend class Context; + mutable optional<UniqueVertexArray> vao; +}; + +template <class Attributes> +class SegmentVector : public std::vector<Segment> { +public: + SegmentVector() = default; +}; + +} // namespace gl +} // namespace mbgl diff --git a/src/mbgl/gl/shader.cpp b/src/mbgl/gl/shader.cpp deleted file mode 100644 index d8ee734567..0000000000 --- a/src/mbgl/gl/shader.cpp +++ /dev/null @@ -1,113 +0,0 @@ -#include <mbgl/gl/shader.hpp> -#include <mbgl/gl/gl.hpp> -#include <mbgl/gl/context.hpp> -#include <mbgl/util/stopwatch.hpp> -#include <mbgl/util/exception.hpp> -#include <mbgl/platform/log.hpp> -#include <mbgl/platform/platform.hpp> - -#include <cstring> -#include <cassert> -#include <iostream> -#include <string> -#include <fstream> -#include <cstdio> -#include <cassert> - -namespace mbgl { -namespace gl { - -Shader::Shader(const char* name_, - const char* vertexSource, - const char* fragmentSource, - Context& context, - Defines defines) - : name(name_), - program(context.createProgram()), - vertexShader(context.createVertexShader()), - fragmentShader(context.createFragmentShader()) { - util::stopwatch stopwatch("shader compilation", Event::Shader); - - if (!compileShader(vertexShader, vertexSource)) { - Log::Error(Event::Shader, "Vertex shader %s failed to compile: %s", name, vertexSource); - throw util::ShaderException(std::string { "Vertex shader " } + name + " failed to compile"); - } - - std::string fragment(fragmentSource); - if (defines & Defines::Overdraw) { - assert(fragment.find("#ifdef OVERDRAW_INSPECTOR") != std::string::npos); - fragment.replace(fragment.find_first_of('\n'), 1, "\n#define OVERDRAW_INSPECTOR\n"); - } - - if (!compileShader(fragmentShader, fragment.c_str())) { - Log::Error(Event::Shader, "Fragment shader %s failed to compile: %s", name, fragmentSource); - throw util::ShaderException(std::string { "Fragment shader " } + name + " failed to compile"); - } - - // Attach shaders - 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.get())); - - MBGL_CHECK_ERROR(glGetProgramiv(program.get(), GL_LINK_STATUS, &status)); - if (status == 0) { - GLint 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.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()); - } -} - -bool Shader::compileShader(UniqueShader& shader, const GLchar *source) { - GLint status = 0; - - const GLsizei lengths = static_cast<GLsizei>(std::strlen(source)); - MBGL_CHECK_ERROR(glShaderSource(shader.get(), 1, &source, &lengths)); - - MBGL_CHECK_ERROR(glCompileShader(shader.get())); - - MBGL_CHECK_ERROR(glGetShaderiv(shader.get(), GL_COMPILE_STATUS, &status)); - if (status == 0) { - GLint 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.get(), logLength, &logLength, log.get())); - Log::Error(Event::Shader, "Shader failed to compile: %s", log.get()); - } - return false; - } - - 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; - } - - return true; -} - -Shader::~Shader() { - if (program.get()) { - MBGL_CHECK_ERROR(glDetachShader(program.get(), vertexShader.get())); - MBGL_CHECK_ERROR(glDetachShader(program.get(), fragmentShader.get())); - } -} - -UniformLocation Shader::getUniformLocation(const char* uniform) const { - return MBGL_CHECK_ERROR(glGetUniformLocation(program.get(), uniform)); -} - -AttributeLocation Shader::getAttributeLocation(const char* attribute) const { - return MBGL_CHECK_ERROR(glGetAttribLocation(program.get(), attribute)); -} - -} // namespace gl -} // namespace mbgl diff --git a/src/mbgl/gl/shader.hpp b/src/mbgl/gl/shader.hpp deleted file mode 100644 index f88bd4f867..0000000000 --- a/src/mbgl/gl/shader.hpp +++ /dev/null @@ -1,45 +0,0 @@ -#pragma once - -#include <mbgl/gl/types.hpp> -#include <mbgl/gl/object.hpp> -#include <mbgl/util/noncopyable.hpp> - -namespace mbgl { -namespace gl { - -class Context; - -class Shader : private util::noncopyable { -public: - ~Shader(); - const char* name; - - ProgramID getID() const { - return program.get(); - } - - AttributeLocation getAttributeLocation(const char* uniform) const; - UniformLocation getUniformLocation(const char* uniform) const; - - enum Defines : bool { - None = false, - Overdraw = true, - }; - -protected: - Shader(const char* name_, - const char* vertex, - const char* fragment, - Context&, - Defines defines = Defines::None); - -private: - bool compileShader(UniqueShader&, const char *source); - - UniqueProgram program; - UniqueShader vertexShader; - UniqueShader fragmentShader; -}; - -} // namespace gl -} // namespace mbgl diff --git a/src/mbgl/gl/stencil_mode.cpp b/src/mbgl/gl/stencil_mode.cpp new file mode 100644 index 0000000000..6858d6d106 --- /dev/null +++ b/src/mbgl/gl/stencil_mode.cpp @@ -0,0 +1,27 @@ +#include <mbgl/gl/stencil_mode.hpp> +#include <mbgl/gl/gl.hpp> +#include <mbgl/util/traits.hpp> + +namespace mbgl { +namespace gl { + +static_assert(StencilMode::Never::func == GL_NEVER, "OpenGL enum mismatch"); +static_assert(StencilMode::Less::func == GL_LESS, "OpenGL enum mismatch"); +static_assert(StencilMode::Equal::func == GL_EQUAL, "OpenGL enum mismatch"); +static_assert(StencilMode::LessEqual::func == GL_LEQUAL, "OpenGL enum mismatch"); +static_assert(StencilMode::Greater::func == GL_GREATER, "OpenGL enum mismatch"); +static_assert(StencilMode::NotEqual::func == GL_NOTEQUAL, "OpenGL enum mismatch"); +static_assert(StencilMode::GreaterEqual::func == GL_GEQUAL, "OpenGL enum mismatch"); +static_assert(StencilMode::Always::func == GL_ALWAYS, "OpenGL enum mismatch"); + +static_assert(underlying_type(StencilMode::Keep) == GL_KEEP, "OpenGL enum mismatch"); +static_assert(underlying_type(StencilMode::Zero) == GL_ZERO, "OpenGL enum mismatch"); +static_assert(underlying_type(StencilMode::Replace) == GL_REPLACE, "OpenGL enum mismatch"); +static_assert(underlying_type(StencilMode::Increment) == GL_INCR, "OpenGL enum mismatch"); +static_assert(underlying_type(StencilMode::IncrementWrap) == GL_INCR_WRAP, "OpenGL enum mismatch"); +static_assert(underlying_type(StencilMode::Decrement) == GL_DECR, "OpenGL enum mismatch"); +static_assert(underlying_type(StencilMode::DecrementWrap) == GL_DECR_WRAP, "OpenGL enum mismatch"); +static_assert(underlying_type(StencilMode::Invert) == GL_INVERT, "OpenGL enum mismatch"); + +} // namespace gl +} // namespace mbgl diff --git a/src/mbgl/gl/stencil_mode.hpp b/src/mbgl/gl/stencil_mode.hpp new file mode 100644 index 0000000000..bc959c9a73 --- /dev/null +++ b/src/mbgl/gl/stencil_mode.hpp @@ -0,0 +1,66 @@ +#pragma once + +#include <mbgl/util/variant.hpp> + +namespace mbgl { +namespace gl { + +class StencilMode { +public: + template <uint32_t F> + struct SimpleTest { + static constexpr uint32_t func = F; + static constexpr uint32_t mask = 0; + }; + + template <uint32_t F> + struct MaskedTest { + static constexpr uint32_t func = F; + uint32_t mask; + }; + + using Never = SimpleTest<0x0200>; + using Less = MaskedTest<0x0201>; + using Equal = MaskedTest<0x0202>; + using LessEqual = MaskedTest<0x0203>; + using Greater = MaskedTest<0x0204>; + using NotEqual = MaskedTest<0x0205>; + using GreaterEqual = MaskedTest<0x0206>; + using Always = SimpleTest<0x0207>; + + using Test = variant< + Never, + Less, + Equal, + LessEqual, + Greater, + NotEqual, + GreaterEqual, + Always>; + + enum Op { + Zero = 0x0000, + Keep = 0x1E00, + Replace = 0x1E01, + Increment = 0x1E02, + Decrement = 0x1E03, + Invert = 0x150A, + IncrementWrap = 0x8507, + DecrementWrap = 0x8508 + }; + + Test test; + int32_t ref; + uint32_t mask; + + Op fail; + Op depthFail; + Op pass; + + static StencilMode disabled() { + return StencilMode { Always(), 0, 0, Keep, Keep, Keep }; + } +}; + +} // namespace gl +} // namespace mbgl diff --git a/src/mbgl/gl/texture.hpp b/src/mbgl/gl/texture.hpp index 49e1323095..5330689ac2 100644 --- a/src/mbgl/gl/texture.hpp +++ b/src/mbgl/gl/texture.hpp @@ -1,18 +1,19 @@ #pragma once #include <mbgl/gl/object.hpp> - -#include <array> +#include <mbgl/util/size.hpp> namespace mbgl { namespace gl { class Texture { public: - std::array<uint16_t, 2> size; + Size size; UniqueTexture texture; TextureFilter filter = TextureFilter::Nearest; TextureMipMap mipmap = TextureMipMap::No; + TextureWrap wrapX = TextureWrap::Clamp; + TextureWrap wrapY = TextureWrap::Clamp; }; } // namespace gl diff --git a/src/mbgl/gl/types.hpp b/src/mbgl/gl/types.hpp index dccc61b03a..577629d5d3 100644 --- a/src/mbgl/gl/types.hpp +++ b/src/mbgl/gl/types.hpp @@ -19,9 +19,10 @@ using AttributeLocation = int32_t; using UniformLocation = int32_t; using TextureUnit = uint8_t; -using DepthValue = double; -using StencilValue = int32_t; -using StencilMaskValue = uint32_t; +enum class ShaderType : uint32_t { + Vertex = 0x8B31, + Fragment = 0x8B30 +}; enum class DataType : uint32_t { Byte = 0x1400, @@ -43,11 +44,6 @@ template <> struct DataTypeOf<int32_t> : std::integral_constant<DataType, DataT template <> struct DataTypeOf<uint32_t> : std::integral_constant<DataType, DataType::UnsignedInteger> {}; template <> struct DataTypeOf<float> : std::integral_constant<DataType, DataType::Float> {}; -enum class BufferType : uint32_t { - Vertex = 0x8892, - Element = 0x8893 -}; - enum class RenderbufferType : uint32_t { RGBA = 0x8058, DepthStencil = 0x88F0, @@ -55,74 +51,37 @@ enum class RenderbufferType : uint32_t { enum class TextureMipMap : bool { No = false, Yes = true }; enum class TextureFilter : bool { Nearest = false, Linear = true }; - -enum class StencilTestFunction : uint32_t { - Never = 0x0200, - Less = 0x0201, - Equal = 0x0202, - LessEqual = 0x0203, - Greater = 0x0204, - NotEqual = 0x0205, - GreaterEqual = 0x0206, - Always = 0x0207, +enum class TextureWrap : bool { Clamp, Repeat }; +enum class TextureFormat : uint32_t { + RGBA = 0x1908, + Alpha = 0x1906, +#if not MBGL_USE_GLES2 + Stencil = 0x1901, + Depth = 0x1902, +#endif // MBGL_USE_GLES2 }; -enum class StencilTestOperation : uint32_t { - Keep = 0x1E00, - Zero = 0x0000, - Replace = 0x1E01, - Increment = 0x1E02, - IncrementWrap = 0x8507, - Decrement = 0x1E03, - DecrementWrap = 0x8508, - Invert = 0x150A, +enum class PrimitiveType { + Points = 0x0000, + Lines = 0x0001, + LineLoop = 0x0002, + LineStrip = 0x0003, + Triangles = 0x0004, + TriangleStrip = 0x0005, + TriangleFan = 0x0006 }; -enum class DepthTestFunction : uint32_t { - Never = 0x0200, - Less = 0x0201, - Equal = 0x0202, - LessEqual = 0x0203, - Greater = 0x0204, - NotEqual = 0x0205, - GreaterEqual = 0x0206, - Always = 0x0207, -}; +#if not MBGL_USE_GLES2 -enum class BlendSourceFactor : uint32_t { - Zero = 0x0000, - One = 0x0001, - SrcColor = 0x0300, - OneMinusSrcColor = 0x0301, - DstColor = 0x0306, - OneMinusDstColor = 0x0307, - SrcAlpha = 0x0302, - OneMinusSrcAlpha = 0x0303, - DstAlpha = 0x0304, - OneMinusDstAlpha = 0x0305, - ConstantColor = 0x8001, - OneMinusConstantColor = 0x8002, - ConstantAlpha = 0x8003, - OneMinusConstantAlpha = 0x8004, - SrcAlphaSaturate = 0x0308, +struct PixelStorageType { + int32_t alignment; }; -enum class BlendDestinationFactor : uint32_t { - Zero = 0x0000, - One = 0x0001, - SrcColor = 0x0300, - OneMinusSrcColor = 0x0301, - DstColor = 0x0306, - OneMinusDstColor = 0x0307, - SrcAlpha = 0x0302, - OneMinusSrcAlpha = 0x0303, - DstAlpha = 0x0304, - OneMinusDstAlpha = 0x0305, - ConstantColor = 0x8001, - OneMinusConstantColor = 0x8002, - ConstantAlpha = 0x8003, - OneMinusConstantAlpha = 0x8004, -}; +constexpr bool operator!=(const PixelStorageType& a, const PixelStorageType& b) { + return a.alignment != b.alignment; +} + +#endif // MBGL_USE_GLES2 } // namespace gl } // namespace mbgl diff --git a/src/mbgl/gl/uniform.cpp b/src/mbgl/gl/uniform.cpp index 07a27963d9..7b674f2cde 100644 --- a/src/mbgl/gl/uniform.cpp +++ b/src/mbgl/gl/uniform.cpp @@ -1,54 +1,80 @@ #include <mbgl/gl/uniform.hpp> #include <mbgl/gl/gl.hpp> #include <mbgl/util/color.hpp> +#include <mbgl/util/size.hpp> +#include <mbgl/util/convert.hpp> namespace mbgl { namespace gl { +UniformLocation uniformLocation(ProgramID id, const char* name) { + return MBGL_CHECK_ERROR(glGetUniformLocation(id, name)); +} + template <> -void Uniform<float>::bind(const float& t) { +void bindUniform<float>(UniformLocation location, const float& t) { MBGL_CHECK_ERROR(glUniform1f(location, t)); } template <> -void Uniform<int32_t>::bind(const int32_t& t) { +void bindUniform<int32_t>(UniformLocation location, const int32_t& t) { MBGL_CHECK_ERROR(glUniform1i(location, t)); } template <> -void Uniform<std::array<float, 2>>::bind(const std::array<float, 2>& t) { +void bindUniform<std::array<float, 2>>(UniformLocation location, const std::array<float, 2>& t) { MBGL_CHECK_ERROR(glUniform2fv(location, 1, t.data())); } template <> -void Uniform<std::array<float, 3>>::bind(const std::array<float, 3>& t) { +void bindUniform<std::array<float, 3>>(UniformLocation location, const std::array<float, 3>& t) { MBGL_CHECK_ERROR(glUniform3fv(location, 1, t.data())); } template <> -void Uniform<std::array<float, 4>>::bind(const std::array<float, 4>& t) { +void bindUniform<std::array<float, 4>>(UniformLocation location, const std::array<float, 4>& t) { MBGL_CHECK_ERROR(glUniform4fv(location, 1, t.data())); } template <> -void Uniform<Color>::bind(const Color& t) { - std::array<float, 4> a = {{ t.r, t.g, t.b, t.a }}; - MBGL_CHECK_ERROR(glUniform4fv(location, 1, a.data())); +void bindUniform<std::array<double, 4>>(UniformLocation location, const std::array<double, 4>& t) { + MBGL_CHECK_ERROR(glUniformMatrix2fv(location, 1, GL_FALSE, util::convert<float>(t).data())); +} + +template <> +void bindUniform<std::array<double, 9>>(UniformLocation location, const std::array<double, 9>& t) { + MBGL_CHECK_ERROR(glUniformMatrix3fv(location, 1, GL_FALSE, util::convert<float>(t).data())); +} + +template <> +void bindUniform<std::array<double, 16>>(UniformLocation location, const std::array<double, 16>& t) { + MBGL_CHECK_ERROR(glUniformMatrix4fv(location, 1, GL_FALSE, util::convert<float>(t).data())); +} + + +template <> +void bindUniform<bool>(UniformLocation location, const bool& t) { + return bindUniform(location, int32_t(t)); +} + +template <> +void bindUniform<uint8_t>(UniformLocation location, const uint8_t& t) { + bindUniform(location, int32_t(t)); } template <> -void UniformMatrix<2>::bind(const std::array<float, 4>& t) { - MBGL_CHECK_ERROR(glUniformMatrix2fv(location, 1, GL_FALSE, t.data())); +void bindUniform<Color>(UniformLocation location, const Color& t) { + bindUniform(location, std::array<float, 4> {{ t.r, t.g, t.b, t.a }}); } template <> -void UniformMatrix<3>::bind(const std::array<float, 9>& t) { - MBGL_CHECK_ERROR(glUniformMatrix3fv(location, 1, GL_FALSE, t.data())); +void bindUniform<Size>(UniformLocation location, const Size& t) { + bindUniform(location, util::convert<float>(std::array<uint32_t, 2> {{ t.width, t.height }})); } template <> -void UniformMatrix<4>::bind(const std::array<float, 16>& t) { - MBGL_CHECK_ERROR(glUniformMatrix4fv(location, 1, GL_FALSE, t.data())); +void bindUniform<std::array<uint16_t, 2>>(UniformLocation location, const std::array<uint16_t, 2>& t) { + bindUniform(location, util::convert<float>(t)); } // Add more as needed. diff --git a/src/mbgl/gl/uniform.hpp b/src/mbgl/gl/uniform.hpp index 5af781043d..726cd4fe10 100644 --- a/src/mbgl/gl/uniform.hpp +++ b/src/mbgl/gl/uniform.hpp @@ -1,60 +1,80 @@ #pragma once -#include <mbgl/gl/shader.hpp> +#include <mbgl/gl/types.hpp> +#include <mbgl/util/optional.hpp> +#include <mbgl/util/ignore.hpp> +#include <mbgl/util/indexed_tuple.hpp> #include <array> +#include <functional> namespace mbgl { namespace gl { -template <typename T> +template <class T> +void bindUniform(UniformLocation, const T&); + +template <class Tag, class T> +class UniformValue { +public: + explicit UniformValue(T t_) : t(std::move(t_)) {} + T t; +}; + +template <class Tag, class T> class Uniform { public: - Uniform(const char* name, const Shader& shader) - : current(), location(shader.getUniformLocation(name)) { - } + using Value = UniformValue<Tag, T>; - void operator=(const T& t) { - if (current != t) { - current = t; - bind(t); + class State { + public: + void operator=(const Value& value) { + if (!current || *current != value.t) { + current = value.t; + bindUniform(location, value.t); + } } - } - -private: - void bind(const T&); - T current; - UniformLocation location; + UniformLocation location; + optional<T> current = {}; + }; }; -template <size_t C, size_t R = C> -class UniformMatrix { +template <class Tag, class T> +using UniformScalar = Uniform<Tag, T>; + +template <class Tag, class T, size_t N> +using UniformVector = Uniform<Tag, std::array<T, N>>; + +template <class Tag, class T, size_t N> +using UniformMatrix = Uniform<Tag, std::array<T, N*N>>; + +#define MBGL_DEFINE_UNIFORM_SCALAR(type_, name_) \ + struct name_ : ::mbgl::gl::UniformScalar<name_, type_> { static constexpr auto name = #name_; } + +#define MBGL_DEFINE_UNIFORM_VECTOR(type_, n_, name_) \ + struct name_ : ::mbgl::gl::UniformVector<name_, type_, n_> { static constexpr auto name = #name_; } + +#define MBGL_DEFINE_UNIFORM_MATRIX(type_, n_, name_) \ + struct name_ : ::mbgl::gl::UniformMatrix<name_, type_, n_> { static constexpr auto name = #name_; } + +UniformLocation uniformLocation(ProgramID, const char * name); + +template <class... Us> +class Uniforms { public: - typedef std::array<float, C*R> T; + using State = IndexedTuple<TypeList<Us...>, TypeList<typename Us::State...>>; + using Values = IndexedTuple<TypeList<Us...>, TypeList<typename Us::Value...>>; - UniformMatrix(const char* name, const Shader& shader) - : current(), location(shader.getUniformLocation(name)) { + static State state(const ProgramID& id) { + return State { { uniformLocation(id, Us::name) }... }; } - void operator=(const std::array<double, C*R>& t) { - bool dirty = false; - for (unsigned int i = 0; i < C*R; i++) { - if (current[i] != t[i]) { - current[i] = t[i]; - dirty = true; - } - } - if (dirty) { - bind(current); - } + static std::function<void ()> binder(State& state, Values&& values_) { + return [&state, values = std::move(values_)] () mutable { + util::ignore({ (state.template get<Us>() = values.template get<Us>(), 0)... }); + }; } - -private: - void bind(const T&); - - T current; - UniformLocation location; }; } // namespace gl diff --git a/src/mbgl/gl/value.cpp b/src/mbgl/gl/value.cpp index 14cd03efc4..86218f3d9a 100644 --- a/src/mbgl/gl/value.cpp +++ b/src/mbgl/gl/value.cpp @@ -94,7 +94,7 @@ StencilFunc::Type StencilFunc::Get() { MBGL_CHECK_ERROR(glGetIntegerv(GL_STENCIL_FUNC, &func)); MBGL_CHECK_ERROR(glGetIntegerv(GL_STENCIL_REF, &ref)); MBGL_CHECK_ERROR(glGetIntegerv(GL_STENCIL_VALUE_MASK, &mask)); - return { static_cast<StencilTestFunction>(func), ref, static_cast<StencilMaskValue>(mask) }; + return { static_cast<uint32_t>(func), ref, static_cast<uint32_t>(mask) }; } const constexpr StencilTest::Type StencilTest::Default; @@ -122,17 +122,17 @@ StencilOp::Type StencilOp::Get() { MBGL_CHECK_ERROR(glGetIntegerv(GL_STENCIL_FAIL, &sfail)); MBGL_CHECK_ERROR(glGetIntegerv(GL_STENCIL_PASS_DEPTH_FAIL, &dpfail)); MBGL_CHECK_ERROR(glGetIntegerv(GL_STENCIL_PASS_DEPTH_PASS, &dppass)); - return { static_cast<StencilTestOperation>(sfail), static_cast<StencilTestOperation>(dpfail), - static_cast<StencilTestOperation>(dppass) }; + return { static_cast<StencilMode::Op>(sfail), static_cast<StencilMode::Op>(dpfail), + static_cast<StencilMode::Op>(dppass) }; } const constexpr DepthRange::Type DepthRange::Default; void DepthRange::Set(const Type& value) { #if MBGL_USE_GLES2 - MBGL_CHECK_ERROR(glDepthRangef(value.near, value.far)); + MBGL_CHECK_ERROR(glDepthRangef(value.min, value.max)); #else - MBGL_CHECK_ERROR(glDepthRange(value.near, value.far)); + MBGL_CHECK_ERROR(glDepthRange(value.min, value.max)); #endif } @@ -178,6 +178,18 @@ Blend::Type Blend::Get() { return blend; } +const constexpr BlendEquation::Type BlendEquation::Default; + +void BlendEquation::Set(const Type& value) { + MBGL_CHECK_ERROR(glBlendEquation(static_cast<GLenum>(value))); +} + +BlendEquation::Type BlendEquation::Get() { + GLint blend; + MBGL_CHECK_ERROR(glGetIntegerv(GL_BLEND_EQUATION_RGB, &blend)); + return static_cast<Type>(blend); +} + const constexpr BlendFunc::Type BlendFunc::Default; void BlendFunc::Set(const Type& value) { @@ -189,8 +201,8 @@ BlendFunc::Type BlendFunc::Get() { GLint sfactor, dfactor; MBGL_CHECK_ERROR(glGetIntegerv(GL_BLEND_SRC_ALPHA, &sfactor)); MBGL_CHECK_ERROR(glGetIntegerv(GL_BLEND_DST_ALPHA, &dfactor)); - return { static_cast<BlendSourceFactor>(sfactor), - static_cast<BlendDestinationFactor>(dfactor) }; + return { static_cast<ColorMode::BlendFactor>(sfactor), + static_cast<ColorMode::BlendFactor>(dfactor) }; } const constexpr BlendColor::Type BlendColor::Default; @@ -244,14 +256,14 @@ ActiveTexture::Type ActiveTexture::Get() { const constexpr Viewport::Type Viewport::Default; void Viewport::Set(const Type& value) { - MBGL_CHECK_ERROR(glViewport(value.x, value.y, value.width, value.height)); + MBGL_CHECK_ERROR(glViewport(value.x, value.y, value.size.width, value.size.height)); } Viewport::Type Viewport::Get() { GLint viewport[4]; MBGL_CHECK_ERROR(glGetIntegerv(GL_VIEWPORT, viewport)); return { static_cast<int32_t>(viewport[0]), static_cast<int32_t>(viewport[1]), - static_cast<uint16_t>(viewport[2]), static_cast<uint16_t>(viewport[3]) }; + { static_cast<uint32_t>(viewport[2]), static_cast<uint32_t>(viewport[3]) } }; } const constexpr BindFramebuffer::Type BindFramebuffer::Default; @@ -340,6 +352,18 @@ BindVertexArray::Type BindVertexArray::Get() { #if not MBGL_USE_GLES2 +const constexpr PointSize::Type PointSize::Default; + +void PointSize::Set(const Type& value) { + MBGL_CHECK_ERROR(glPointSize(value)); +} + +PointSize::Type PointSize::Get() { + GLfloat pointSize; + MBGL_CHECK_ERROR(glGetFloatv(GL_POINT_SIZE, &pointSize)); + return pointSize; +} + const constexpr PixelZoom::Type PixelZoom::Default; void PixelZoom::Set(const Type& value) { @@ -365,8 +389,63 @@ RasterPos::Type RasterPos::Get() { return { pos[0], pos[1], pos[2], pos[3] }; } -#endif // MBGL_USE_GLES2 +const constexpr PixelStorePack::Type PixelStorePack::Default; + +void PixelStorePack::Set(const Type& value) { + assert(value.alignment == 1 || value.alignment == 2 || value.alignment == 4 || + value.alignment == 8); + MBGL_CHECK_ERROR(glPixelStorei(GL_PACK_ALIGNMENT, value.alignment)); +} + +PixelStorePack::Type PixelStorePack::Get() { + Type value; + MBGL_CHECK_ERROR(glGetIntegerv(GL_PACK_ALIGNMENT, &value.alignment)); + return value; +} + +const constexpr PixelStoreUnpack::Type PixelStoreUnpack::Default; +void PixelStoreUnpack::Set(const Type& value) { + assert(value.alignment == 1 || value.alignment == 2 || value.alignment == 4 || + value.alignment == 8); + MBGL_CHECK_ERROR(glPixelStorei(GL_UNPACK_ALIGNMENT, value.alignment)); +} + +PixelStoreUnpack::Type PixelStoreUnpack::Get() { + Type value; + MBGL_CHECK_ERROR(glGetIntegerv(GL_UNPACK_ALIGNMENT, &value.alignment)); + return value; +} + +const constexpr PixelTransferDepth::Type PixelTransferDepth::Default; + +void PixelTransferDepth::Set(const Type& value) { + MBGL_CHECK_ERROR(glPixelTransferf(GL_DEPTH_SCALE, value.scale)); + MBGL_CHECK_ERROR(glPixelTransferf(GL_DEPTH_BIAS, value.bias)); +} + +PixelTransferDepth::Type PixelTransferDepth::Get() { + Type value; + MBGL_CHECK_ERROR(glGetFloatv(GL_DEPTH_SCALE, &value.scale)); + MBGL_CHECK_ERROR(glGetFloatv(GL_DEPTH_BIAS, &value.bias)); + return value; +} + +const constexpr PixelTransferStencil::Type PixelTransferStencil::Default; + +void PixelTransferStencil::Set(const Type& value) { + MBGL_CHECK_ERROR(glPixelTransferf(GL_INDEX_SHIFT, value.shift)); + MBGL_CHECK_ERROR(glPixelTransferf(GL_INDEX_OFFSET, value.offset)); +} + +PixelTransferStencil::Type PixelTransferStencil::Get() { + Type value; + MBGL_CHECK_ERROR(glGetIntegerv(GL_INDEX_SHIFT, &value.shift)); + MBGL_CHECK_ERROR(glGetIntegerv(GL_INDEX_OFFSET, &value.offset)); + return value; +} + +#endif // MBGL_USE_GLES2 } // namespace value } // namespace gl diff --git a/src/mbgl/gl/value.hpp b/src/mbgl/gl/value.hpp index 866ce389a4..3586c26bda 100644 --- a/src/mbgl/gl/value.hpp +++ b/src/mbgl/gl/value.hpp @@ -1,7 +1,12 @@ #pragma once #include <mbgl/gl/types.hpp> +#include <mbgl/gl/depth_mode.hpp> +#include <mbgl/gl/stencil_mode.hpp> +#include <mbgl/gl/color_mode.hpp> #include <mbgl/util/color.hpp> +#include <mbgl/util/size.hpp> +#include <mbgl/util/range.hpp> namespace mbgl { namespace gl { @@ -22,14 +27,14 @@ struct ClearColor { }; struct ClearStencil { - using Type = StencilValue; + using Type = int32_t; static const constexpr Type Default = 0; static void Set(const Type&); static Type Get(); }; struct StencilMask { - using Type = StencilMaskValue; + using Type = uint32_t; static const constexpr Type Default = ~0u; static void Set(const Type&); static Type Get(); @@ -43,28 +48,19 @@ struct DepthMask { }; struct ColorMask { - struct Type { - bool r; - bool g; - bool b; - bool a; - }; + using Type = ColorMode::Mask; static const constexpr Type Default = { true, true, true, true }; static void Set(const Type&); static Type Get(); }; -constexpr bool operator!=(const ColorMask::Type& a, const ColorMask::Type& b) { - return a.r != b.r || a.g != b.g || a.b != b.b || a.a != b.a; -} - struct StencilFunc { struct Type { - StencilTestFunction func; - StencilValue ref; - StencilMaskValue mask; + uint32_t func; + int32_t ref; + uint32_t mask; }; - static const constexpr Type Default = { StencilTestFunction::Always, 0, ~0u }; + static const constexpr Type Default = { StencilMode::Always::func, 0, ~0u }; static void Set(const Type&); static Type Get(); }; @@ -82,12 +78,11 @@ struct StencilTest { struct StencilOp { struct Type { - StencilTestOperation sfail; - StencilTestOperation dpfail; - StencilTestOperation dppass; + StencilMode::Op sfail; + StencilMode::Op dpfail; + StencilMode::Op dppass; }; - static const constexpr Type Default = { StencilTestOperation::Keep, StencilTestOperation::Keep, - StencilTestOperation::Keep }; + static const constexpr Type Default = { StencilMode::Keep, StencilMode::Keep, StencilMode::Keep }; static void Set(const Type&); static Type Get(); }; @@ -97,19 +92,12 @@ constexpr bool operator!=(const StencilOp::Type& a, const StencilOp::Type& b) { } struct DepthRange { - struct Type { - float near; - float far; - }; + using Type = Range<float>; static const constexpr Type Default = { 0, 1 }; static void Set(const Type&); static Type Get(); }; -constexpr bool operator!=(const DepthRange::Type& a, const DepthRange::Type& b) { - return a.near != b.near || a.far != b.far; -} - struct DepthTest { using Type = bool; static const constexpr Type Default = false; @@ -118,8 +106,8 @@ struct DepthTest { }; struct DepthFunc { - using Type = DepthTestFunction; - static const constexpr Type Default = DepthTestFunction::Less; + using Type = DepthMode::Function; + static const constexpr Type Default = DepthMode::Less; static void Set(const Type&); static Type Get(); }; @@ -131,12 +119,19 @@ struct Blend { static Type Get(); }; +struct BlendEquation { + using Type = ColorMode::BlendEquation; + static const constexpr Type Default = ColorMode::BlendEquation::Add; + static void Set(const Type&); + static Type Get(); +}; + struct BlendFunc { struct Type { - BlendSourceFactor sfactor; - BlendDestinationFactor dfactor; + ColorMode::BlendFactor sfactor; + ColorMode::BlendFactor dfactor; }; - static const constexpr Type Default = { BlendSourceFactor::One, BlendDestinationFactor::Zero }; + static const constexpr Type Default = { ColorMode::One, ColorMode::Zero }; static void Set(const Type&); static Type Get(); }; @@ -177,16 +172,19 @@ struct Viewport { struct Type { int32_t x; int32_t y; - uint16_t width; - uint16_t height; + Size size; }; - static const constexpr Type Default = { 0, 0, 0, 0 }; + static const constexpr Type Default = { 0, 0, { 0, 0 } }; static void Set(const Type&); static Type Get(); }; constexpr bool operator!=(const Viewport::Type& a, const Viewport::Type& b) { - return a.x != b.x || a.y != b.y || a.width != b.width || a.height != b.height; + return a.x != b.x || a.y != b.y || a.size != b.size; +} + +constexpr bool operator==(const Viewport::Type& a, const Viewport::Type& b) { + return !(a != b); } struct BindFramebuffer { @@ -233,6 +231,13 @@ struct BindVertexArray { #if not MBGL_USE_GLES2 +struct PointSize { + using Type = float; + static const constexpr Type Default = 1; + static void Set(const Type&); + static Type Get(); +}; + struct PixelZoom { struct Type { float xfactor; @@ -254,7 +259,7 @@ struct RasterPos { double z; double w; }; - static const constexpr Type Default = { 0, 0, 0, 0 }; + static const constexpr Type Default = { 0, 0, 0, 1 }; static void Set(const Type&); static Type Get(); }; @@ -263,6 +268,48 @@ constexpr bool operator!=(const RasterPos::Type& a, const RasterPos::Type& b) { return a.x != b.x || a.y != b.y || a.z != b.z || a.w != b.w; } +struct PixelStorePack { + using Type = PixelStorageType; + static const constexpr Type Default = { 4 }; + static void Set(const Type&); + static Type Get(); +}; + +struct PixelStoreUnpack { + using Type = PixelStorageType; + static const constexpr Type Default = { 4 }; + static void Set(const Type&); + static Type Get(); +}; + +struct PixelTransferDepth { + struct Type { + float scale; + float bias; + }; + static const constexpr Type Default = { 1, 0 }; + static void Set(const Type&); + static Type Get(); +}; + +constexpr bool operator!=(const PixelTransferDepth::Type& a, const PixelTransferDepth::Type& b) { + return a.scale != b.scale || a.bias != b.bias; +} + +struct PixelTransferStencil { + struct Type { + int32_t shift; + int32_t offset; + }; + static const constexpr Type Default = { 0, 0 }; + static void Set(const Type&); + static Type Get(); +}; + +constexpr bool operator!=(const PixelTransferStencil::Type& a, const PixelTransferStencil::Type& b) { + return a.shift != b.shift || a.offset != b.offset; +} + #endif // MBGL_USE_GLES2 } // namespace value diff --git a/src/mbgl/gl/vao.cpp b/src/mbgl/gl/vao.cpp deleted file mode 100644 index b235b0e63b..0000000000 --- a/src/mbgl/gl/vao.cpp +++ /dev/null @@ -1,58 +0,0 @@ -#include <mbgl/gl/vao.hpp> -#include <mbgl/gl/vertex_array.hpp> -#include <mbgl/platform/log.hpp> -#include <mbgl/util/string.hpp> -#include <mbgl/gl/gl.hpp> - -namespace mbgl { -namespace gl { - -void VertexArrayObject::bindVertexArrayObject(Context& context) { - if (!GenVertexArrays || !BindVertexArray) { - static bool reported = false; - if (!reported) { - Log::Warning(Event::OpenGL, "Not using Vertex Array Objects"); - reported = true; - } - return; - } - - if (!vertexArray) { - vertexArray = context.createVertexArray(); - context.vertexBuffer.setDirty(); - context.elementBuffer.setDirty(); - } - - context.vertexArrayObject = *vertexArray; -} - -void VertexArrayObject::verifyBinding(Shader& shader, - BufferID vertexBuffer, - BufferID elementsBuffer, - int8_t* offset) { - if (bound_shader != shader.getID()) { - throw std::runtime_error(std::string("trying to rebind VAO to another shader from " + - util::toString(bound_shader) + "(" + bound_shader_name + ") to " + - util::toString(shader.getID()) + "(" + shader.name + ")" )); - } else if (bound_offset != offset) { - throw std::runtime_error("trying to bind VAO to another offset"); - } else if (bound_vertex_buffer != vertexBuffer) { - throw std::runtime_error("trying to bind VAO to another vertex buffer"); - } else if (bound_elements_buffer != elementsBuffer) { - throw std::runtime_error("trying to bind VAO to another elements buffer"); - } -} - -void VertexArrayObject::storeBinding(Shader& shader, - BufferID vertexBuffer, - BufferID elementsBuffer, - int8_t* offset) { - bound_shader = shader.getID(); - bound_shader_name = shader.name; - bound_offset = offset; - bound_vertex_buffer = vertexBuffer; - bound_elements_buffer = elementsBuffer; -} - -} // namespace gl -} // namespace mbgl diff --git a/src/mbgl/gl/vao.hpp b/src/mbgl/gl/vao.hpp deleted file mode 100644 index 826c028d32..0000000000 --- a/src/mbgl/gl/vao.hpp +++ /dev/null @@ -1,78 +0,0 @@ -#pragma once - -#include <mbgl/gl/shader.hpp> -#include <mbgl/gl/context.hpp> -#include <mbgl/gl/vertex_buffer.hpp> -#include <mbgl/util/optional.hpp> - -#include <stdexcept> - -namespace mbgl { -namespace gl { - -class VertexArrayObject { -public: - template <typename Shader, typename T> - void bind(Shader& shader, - const VertexBuffer<T>& vertexBuffer, - int8_t* offset, - Context& context) { - bindVertexArrayObject(context); - if (bound_shader == 0) { - context.vertexBuffer = vertexBuffer.buffer; - context.bindAttributes(shader, vertexBuffer, offset); - if (vertexArray) { - storeBinding(shader, vertexBuffer.buffer, 0, offset); - } - } else { - verifyBinding(shader, vertexBuffer.buffer, 0, offset); - } - } - - template <typename Shader, typename T, typename P> - void bind(Shader& shader, - const VertexBuffer<T>& vertexBuffer, - const IndexBuffer<P>& indexBuffer, - int8_t* offset, - Context& context) { - bindVertexArrayObject(context); - if (bound_shader == 0) { - context.vertexBuffer = vertexBuffer.buffer; - context.elementBuffer = indexBuffer.buffer; - context.bindAttributes(shader, vertexBuffer, offset); - if (vertexArray) { - storeBinding(shader, vertexBuffer.buffer, indexBuffer.buffer, offset); - } - } else { - verifyBinding(shader, vertexBuffer.buffer, indexBuffer.buffer, offset); - } - } - - VertexArrayID getID() const { - return *vertexArray; - } - -private: - void bindVertexArrayObject(Context&); - void storeBinding(Shader& shader, - BufferID vertexBuffer, - BufferID elementsBuffer, - int8_t* offset); - void verifyBinding(Shader& shader, - BufferID vertexBuffer, - BufferID elementsBuffer, - int8_t* offset); - - optional<UniqueVertexArray> vertexArray; - - // For debug reasons, we're storing the bind information so that we can - // detect errors and report - ProgramID bound_shader = 0; - const char* bound_shader_name = ""; - BufferID bound_vertex_buffer = 0; - BufferID bound_elements_buffer = 0; - int8_t *bound_offset = nullptr; -}; - -} // namespace gl -} // namespace mbgl diff --git a/src/mbgl/gl/vertex_buffer.hpp b/src/mbgl/gl/vertex_buffer.hpp index c77a9a4213..c9bc01f3e8 100644 --- a/src/mbgl/gl/vertex_buffer.hpp +++ b/src/mbgl/gl/vertex_buffer.hpp @@ -1,14 +1,43 @@ #pragma once #include <mbgl/gl/object.hpp> +#include <mbgl/gl/primitives.hpp> +#include <mbgl/gl/draw_mode.hpp> +#include <mbgl/util/ignore.hpp> + +#include <vector> namespace mbgl { namespace gl { -template <class Vertex> +template <class V, class DrawMode = Indexed> +class VertexVector { +public: + using Vertex = V; + static constexpr std::size_t groupSize = DrawMode::bufferGroupSize; + + template <class... Args> + void emplace_back(Args&&... args) { + static_assert(sizeof...(args) == groupSize, "wrong buffer element count"); + util::ignore({(v.emplace_back(std::forward<Args>(args)), 0)...}); + } + + std::size_t vertexSize() const { return v.size(); } + std::size_t byteSize() const { return v.size() * sizeof(Vertex); } + + bool empty() const { return v.empty(); } + const Vertex* data() const { return v.data(); } + +private: + std::vector<Vertex> v; +}; + +template <class V, class DrawMode = Indexed> class VertexBuffer { public: + using Vertex = V; static constexpr std::size_t vertexSize = sizeof(Vertex); + std::size_t vertexCount; UniqueBuffer buffer; }; |