diff options
author | John Firebaugh <john.firebaugh@gmail.com> | 2016-10-28 18:17:33 -0700 |
---|---|---|
committer | John Firebaugh <john.firebaugh@gmail.com> | 2016-11-08 08:09:29 -0800 |
commit | 66bdbc3b969083b9d647abdf72784be64a125949 (patch) | |
tree | 9f2f1c6eb3d0569926420459c2c9afda50c66fd0 /src/mbgl/gl | |
parent | 36210fe4e9c68a52dedc90548d90e77cf39a2228 (diff) | |
download | qtlocation-mapboxgl-66bdbc3b969083b9d647abdf72784be64a125949.tar.gz |
[core] Introduce gl::Program template
Diffstat (limited to 'src/mbgl/gl')
-rw-r--r-- | src/mbgl/gl/attribute.cpp | 4 | ||||
-rw-r--r-- | src/mbgl/gl/attribute.hpp | 10 | ||||
-rw-r--r-- | src/mbgl/gl/context.cpp | 55 | ||||
-rw-r--r-- | src/mbgl/gl/context.hpp | 6 | ||||
-rw-r--r-- | src/mbgl/gl/drawable.hpp | 16 | ||||
-rw-r--r-- | src/mbgl/gl/program.hpp | 37 | ||||
-rw-r--r-- | src/mbgl/gl/shader.cpp | 113 | ||||
-rw-r--r-- | src/mbgl/gl/shader.hpp | 45 | ||||
-rw-r--r-- | src/mbgl/gl/types.hpp | 5 | ||||
-rw-r--r-- | src/mbgl/gl/uniform.cpp | 4 | ||||
-rw-r--r-- | src/mbgl/gl/uniform.hpp | 14 |
11 files changed, 119 insertions, 190 deletions
diff --git a/src/mbgl/gl/attribute.cpp b/src/mbgl/gl/attribute.cpp index 81ab6ac2a5..51fdd1dd12 100644 --- a/src/mbgl/gl/attribute.cpp +++ b/src/mbgl/gl/attribute.cpp @@ -4,6 +4,10 @@ namespace mbgl { namespace gl { +AttributeLocation attributeLocation(ProgramID id, const char* name) { + return MBGL_CHECK_ERROR(glGetAttribLocation(id, name)); +} + void bindAttribute(AttributeLocation location, std::size_t count, DataType type, diff --git a/src/mbgl/gl/attribute.hpp b/src/mbgl/gl/attribute.hpp index e6ef5c7f89..126da38de5 100644 --- a/src/mbgl/gl/attribute.hpp +++ b/src/mbgl/gl/attribute.hpp @@ -1,7 +1,6 @@ #pragma once #include <mbgl/gl/types.hpp> -#include <mbgl/gl/shader.hpp> #include <cstddef> #include <functional> @@ -18,9 +17,6 @@ public: class State { public: - State(const char* name, const Shader& shader) - : location(shader.getAttributeLocation(name)) {} - AttributeLocation location; static constexpr std::size_t count = N; static constexpr DataType type = DataTypeOf<T>::value; @@ -134,6 +130,8 @@ const std::size_t Vertex<A1, A2, A3, A4, A5>::attributeOffsets[5] = { } // namespace detail +AttributeLocation attributeLocation(ProgramID, const char * name); + void bindAttribute(AttributeLocation location, std::size_t count, DataType type, @@ -147,8 +145,8 @@ public: using State = std::tuple<typename As::State...>; using Vertex = detail::Vertex<As...>; - static State state(const Shader& shader) { - return State { { As::name, shader }... }; + static State state(const ProgramID& id) { + return State { { attributeLocation(id, As::name) }... }; } static std::function<void (std::size_t)> binder(const State& state) { diff --git a/src/mbgl/gl/context.cpp b/src/mbgl/gl/context.cpp index f23dfe3dbe..b12c77c1a1 100644 --- a/src/mbgl/gl/context.cpp +++ b/src/mbgl/gl/context.cpp @@ -4,12 +4,16 @@ #include <mbgl/gl/vertex_array.hpp> #include <mbgl/util/traits.hpp> #include <mbgl/util/std.hpp> +#include <mbgl/platform/log.hpp> #include <boost/functional/hash.hpp> 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"); @@ -34,16 +38,53 @@ 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()); + } -UniqueShader Context::createVertexShader() { - return UniqueShader{ MBGL_CHECK_ERROR(glCreateShader(GL_VERTEX_SHADER)), { this } }; + throw std::runtime_error("shader failed to compile"); } -UniqueShader Context::createFragmentShader() { - return UniqueShader{ MBGL_CHECK_ERROR(glCreateShader(GL_FRAGMENT_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)); + MBGL_CHECK_ERROR(glLinkProgram(result)); + + GLint status; + MBGL_CHECK_ERROR(glGetProgramiv(result, GL_LINK_STATUS, &status)); + if (status != 0) { + return result; + } + + GLint logLength; + MBGL_CHECK_ERROR(glGetProgramiv(result, GL_INFO_LOG_LENGTH, &logLength)); + const auto log = std::make_unique<GLchar[]>(logLength); + if (logLength > 0) { + MBGL_CHECK_ERROR(glGetProgramInfoLog(result, 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) { diff --git a/src/mbgl/gl/context.hpp b/src/mbgl/gl/context.hpp index 438450fe14..2a3fbea33d 100644 --- a/src/mbgl/gl/context.hpp +++ b/src/mbgl/gl/context.hpp @@ -14,6 +14,7 @@ #include <memory> #include <vector> #include <array> +#include <string> #include <unordered_map> namespace mbgl { @@ -28,9 +29,8 @@ 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); UniqueTexture createTexture(); template <class V> diff --git a/src/mbgl/gl/drawable.hpp b/src/mbgl/gl/drawable.hpp index be6b27bb83..747d8facf0 100644 --- a/src/mbgl/gl/drawable.hpp +++ b/src/mbgl/gl/drawable.hpp @@ -82,28 +82,28 @@ auto Segmented(const VertexBuffer<Vertex>& vertexBuffer, class Drawable { public: - template <class Shader, class Subject> + template <class Program, class Subject> Drawable(DepthMode depthMode_, StencilMode stencilMode_, ColorMode colorMode_, - Shader& shader, - typename Shader::UniformsType::Values&& uniformValues, + Program& program_, + typename Program::UniformValues&& uniformValues, const Subject& subject) : drawMode(subject.drawMode), depthMode(std::move(depthMode_)), stencilMode(std::move(stencilMode_)), colorMode(std::move(colorMode_)), - program(shader.getID()), + program(program_.program), vertexBuffer(subject.vertexBuffer), vertexSize(subject.vertexSize), indexBuffer(subject.indexBuffer), primitiveSize(subject.primitiveSize), segments(subject.segments), - bindUniforms(Shader::UniformsType::binder(shader.uniformsState, std::move(uniformValues))), - bindAttributes(Shader::AttributesType::binder(shader.attributesState)) + bindUniforms(Program::Uniforms::binder(program_.uniformsState, std::move(uniformValues))), + bindAttributes(Program::Attributes::binder(program_.attributesState)) { - static_assert(std::is_standard_layout<typename Subject::VertexType>::value, "vertex type must use standard layout"); - static_assert(std::is_same<typename Shader::AttributesType::Vertex, typename Subject::VertexType>::value, "vertex type mismatch"); + static_assert(std::is_standard_layout<typename Program::Vertex>::value, "vertex type must use standard layout"); + static_assert(std::is_same<typename Program::Vertex, typename Subject::VertexType>::value, "vertex type mismatch"); } DrawMode drawMode; diff --git a/src/mbgl/gl/program.hpp b/src/mbgl/gl/program.hpp new file mode 100644 index 0000000000..ea4dbcc1df --- /dev/null +++ b/src/mbgl/gl/program.hpp @@ -0,0 +1,37 @@ +#pragma once + +#include <mbgl/gl/types.hpp> +#include <mbgl/gl/object.hpp> +#include <mbgl/gl/context.hpp> + +#include <string> + +namespace mbgl { +namespace gl { + +template <class As, class Us> +class Program { +public: + using Attributes = As; + using Vertex = typename Attributes::Vertex; + + using Uniforms = Us; + using UniformValues = typename Uniforms::Values; + + 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(Uniforms::state(program)) {} + + UniqueShader vertexShader; + UniqueShader fragmentShader; + UniqueProgram program; + + typename Attributes::State attributesState; + typename Uniforms::State uniformsState; +}; + +} // 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/types.hpp b/src/mbgl/gl/types.hpp index 1697656469..577629d5d3 100644 --- a/src/mbgl/gl/types.hpp +++ b/src/mbgl/gl/types.hpp @@ -19,6 +19,11 @@ using AttributeLocation = int32_t; using UniformLocation = int32_t; using TextureUnit = uint8_t; +enum class ShaderType : uint32_t { + Vertex = 0x8B31, + Fragment = 0x8B30 +}; + enum class DataType : uint32_t { Byte = 0x1400, UnsignedByte = 0x1401, diff --git a/src/mbgl/gl/uniform.cpp b/src/mbgl/gl/uniform.cpp index 8018953fb5..7b674f2cde 100644 --- a/src/mbgl/gl/uniform.cpp +++ b/src/mbgl/gl/uniform.cpp @@ -7,6 +7,10 @@ namespace mbgl { namespace gl { +UniformLocation uniformLocation(ProgramID id, const char* name) { + return MBGL_CHECK_ERROR(glGetUniformLocation(id, name)); +} + template <> void bindUniform<float>(UniformLocation location, const float& t) { MBGL_CHECK_ERROR(glUniform1f(location, t)); diff --git a/src/mbgl/gl/uniform.hpp b/src/mbgl/gl/uniform.hpp index 40a48d3af3..90ca16e46f 100644 --- a/src/mbgl/gl/uniform.hpp +++ b/src/mbgl/gl/uniform.hpp @@ -1,6 +1,6 @@ #pragma once -#include <mbgl/gl/shader.hpp> +#include <mbgl/gl/types.hpp> #include <mbgl/util/optional.hpp> #include <array> @@ -27,9 +27,6 @@ public: class State { public: - State(const char* name, const Shader& shader) - : location(shader.getUniformLocation(name)) {} - void operator=(const Value& value) { if (!current || *current != value.t) { current = value.t; @@ -37,9 +34,8 @@ public: } } - private: - optional<T> current; UniformLocation location; + optional<T> current = {}; }; }; @@ -61,14 +57,16 @@ using UniformMatrix = Uniform<Tag, std::array<T, N*N>>; #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: using State = std::tuple<typename Us::State...>; using Values = std::tuple<typename Us::Value...>; - static State state(const Shader& shader) { - return State { { Us::name, shader }... }; + static State state(const ProgramID& id) { + return State { { uniformLocation(id, Us::name) }... }; } static std::function<void ()> binder(State& state, Values&& values_) { |