diff options
Diffstat (limited to 'platform/gfx/gl')
74 files changed, 9973 insertions, 0 deletions
diff --git a/platform/gfx/gl/include/mbgl/gl/renderable_resource.hpp b/platform/gfx/gl/include/mbgl/gl/renderable_resource.hpp new file mode 100644 index 0000000000..9585269270 --- /dev/null +++ b/platform/gfx/gl/include/mbgl/gl/renderable_resource.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include <mbgl/gfx/renderable.hpp> + +#include <cstdlib> + +namespace mbgl { +namespace gl { + +class RenderableResource : public gfx::RenderableResource { +protected: + explicit RenderableResource() = default; + +public: + virtual void bind() = 0; + + virtual void swap() { + // Renderable resources that require a swap function to be called explicitly + // can override this method. + } +}; + +} // namespace gl +} // namespace mbgl diff --git a/platform/gfx/gl/include/mbgl/gl/renderer_backend.hpp b/platform/gfx/gl/include/mbgl/gl/renderer_backend.hpp new file mode 100644 index 0000000000..cfa28ddaeb --- /dev/null +++ b/platform/gfx/gl/include/mbgl/gl/renderer_backend.hpp @@ -0,0 +1,56 @@ +#pragma once + +#include <mbgl/gfx/renderer_backend.hpp> +#include <mbgl/util/image.hpp> +#include <mbgl/util/size.hpp> +#include <mbgl/util/util.hpp> + +namespace mbgl { +namespace gl { + +class Context; +using ProcAddress = void (*)(); +using FramebufferID = uint32_t; + +class RendererBackend : public gfx::RendererBackend { +public: + RendererBackend(gfx::ContextMode); + ~RendererBackend() override; + + // Called prior to rendering to update the internally assumed OpenGL state. + virtual void updateAssumedState() = 0; + +protected: + std::unique_ptr<gfx::Context> createContext() override; + + // Called with the name of an OpenGL extension that should be loaded. RendererBackend implementations + // must call the API-specific version that obtains the function pointer for this function, + // or a null pointer if unsupported/unavailable. + virtual ProcAddress getExtensionFunctionPointer(const char*) = 0; + + // Reads the color pixel data from the currently bound framebuffer. + PremultipliedImage readFramebuffer(const Size&); + + // A constant to signal that a framebuffer is bound, but with an unknown ID. + static constexpr const FramebufferID ImplicitFramebufferBinding = + std::numeric_limits<FramebufferID>::max(); + + // Tells the renderer that OpenGL state has already been set by the windowing toolkit. + // It sets the internal assumed state to the supplied values. + void assumeFramebufferBinding(FramebufferID fbo); + void assumeViewport(int32_t x, int32_t y, const Size&); + void assumeScissorTest(bool); + + // Returns true when assumed framebuffer binding hasn't changed from the implicit binding. + bool implicitFramebufferBound(); + +public: + // Triggers an OpenGL state update if the internal assumed state doesn't match the + // supplied values. + void setFramebufferBinding(FramebufferID fbo); + void setViewport(int32_t x, int32_t y, const Size&); + void setScissorTest(bool); +}; + +} // namespace gl +} // namespace mbgl diff --git a/platform/gfx/gl/include/mbgl/platform/gl_functions.hpp b/platform/gfx/gl/include/mbgl/platform/gl_functions.hpp new file mode 100644 index 0000000000..fab3e3aa36 --- /dev/null +++ b/platform/gfx/gl/include/mbgl/platform/gl_functions.hpp @@ -0,0 +1,337 @@ +#pragma once + +#include <cstddef> + +// Pointers to OpenGL ES 2.0 functions. They must be +// initialized by the platform at linking time. + +#ifndef NDEBUG +#define MBGL_CHECK_ERROR(cmd) ([&]() { struct __MBGL_CHECK_ERROR { ~__MBGL_CHECK_ERROR() noexcept(false) { mbgl::platform::glCheckError(#cmd, __FILE__, __LINE__); } } __MBGL_CHECK_ERROR; return cmd; }()) +#else +#define MBGL_CHECK_ERROR(cmd) (cmd) +#endif + +namespace mbgl { +namespace platform { + +using GLbitfield = unsigned int; +using GLboolean = unsigned char; +using GLchar = char; +using GLdouble = double; +using GLenum = unsigned int; +using GLfloat = float; +using GLint = int; +using GLsizei = int; +using GLubyte = unsigned char; +using GLuint = unsigned int; +using GLvoid = void; + +#if defined(_WIN32) +using GLintptr = long long; +using GLsizeiptr = long long; +#else +using GLintptr = long; +using GLsizeiptr = long; +#endif + +/// Pointer to glActiveTexture OpenGL function. +extern void (* const glActiveTexture)(GLenum); +/// Pointer to glAttachShader OpenGL function. +extern void (* const glAttachShader)(GLuint, GLuint); +/// Pointer to glBindAttribLocation OpenGL function. +extern void (* const glBindAttribLocation)(GLuint, GLuint, const GLchar *); +/// Pointer to glBindBuffer OpenGL function. +extern void (* const glBindBuffer)(GLenum, GLuint); +/// Pointer to glBindFramebuffer OpenGL function. +extern void (* const glBindFramebuffer)(GLenum, GLuint); +/// Pointer to glBindRenderbuffer OpenGL function. +extern void (* const glBindRenderbuffer)(GLenum, GLuint); +/// Pointer to glBindTexture OpenGL function. +extern void (* const glBindTexture)(GLenum, GLuint); +/// Pointer to glBlendColor OpenGL function. +extern void (* const glBlendColor)(GLfloat, GLfloat, GLfloat, GLfloat); +/// Pointer to glBlendEquation OpenGL function. +extern void (* const glBlendEquation)(GLenum); +/// Pointer to glBlendEquationSeparate OpenGL function. +extern void (* const glBlendEquationSeparate)(GLenum, GLenum); +/// Pointer to glBlendFunc OpenGL function. +extern void (* const glBlendFunc)(GLenum, GLenum); +/// Pointer to glBlendFuncSeparate OpenGL function. +extern void (* const glBlendFuncSeparate)(GLenum, GLenum, GLenum, GLenum); +/// Pointer to glBufferData OpenGL function. +extern void (* const glBufferData)(GLenum, GLsizeiptr, const void *, GLenum); +/// Pointer to glBufferSubData OpenGL function. +extern void (* const glBufferSubData)(GLenum, GLintptr, GLsizeiptr, const void *); +/// Pointer to glCheckFramebufferStatus OpenGL function. +extern GLenum (* const glCheckFramebufferStatus)(GLenum); +/// Pointer to glClear OpenGL function. +extern void (* const glClear)(GLbitfield); +/// Pointer to glClearColor OpenGL function. +extern void (* const glClearColor)(GLfloat, GLfloat, GLfloat, GLfloat); +/// Pointer to glClearDepthf OpenGL function. +extern void (* const glClearDepthf)(GLfloat); +/// Pointer to glClearStencil OpenGL function. +extern void (* const glClearStencil)(GLint); +/// Pointer to glColorMask OpenGL function. +extern void (* const glColorMask)(GLboolean, GLboolean, GLboolean, GLboolean); +/// Pointer to glCompileShader OpenGL function. +extern void (* const glCompileShader)(GLuint); +/// Pointer to glCompressedTexImage2D OpenGL function. +extern void (* const glCompressedTexImage2D)(GLenum, GLint, GLenum, GLsizei, GLsizei, GLint, GLsizei, const void *); +/// Pointer to glCompressedTexSubImage2D OpenGL function. +extern void (* const glCompressedTexSubImage2D)(GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLsizei, const void *); +/// Pointer to glCopyTexImage2D OpenGL function. +extern void (* const glCopyTexImage2D)(GLenum, GLint, GLenum, GLint, GLint, GLsizei, GLsizei, GLint); +/// Pointer to glCopyTexSubImage2D OpenGL function. +extern void (* const glCopyTexSubImage2D)(GLenum, GLint, GLint, GLint, GLint, GLint, GLsizei, GLsizei); +/// Pointer to glCreateProgram OpenGL function. +extern GLuint (* const glCreateProgram)(); +/// Pointer to glCreateShader OpenGL function. +extern GLuint (* const glCreateShader)(GLenum); +/// Pointer to glCullFace OpenGL function. +extern void (* const glCullFace)(GLenum); +/// Pointer to glDeleteBuffers OpenGL function. +extern void (* const glDeleteBuffers)(GLsizei, const GLuint *); +/// Pointer to glDeleteFramebuffers OpenGL function. +extern void (* const glDeleteFramebuffers)(GLsizei, const GLuint *); +/// Pointer to glDeleteProgram OpenGL function. +extern void (* const glDeleteProgram)(GLuint); +/// Pointer to glDeleteRenderbuffers OpenGL function. +extern void (* const glDeleteRenderbuffers)(GLsizei, const GLuint *); +/// Pointer to glDeleteShader OpenGL function. +extern void (* const glDeleteShader)(GLuint); +/// Pointer to glDeleteTextures OpenGL function. +extern void (* const glDeleteTextures)(GLsizei, const GLuint *); +/// Pointer to glDepthFunc OpenGL function. +extern void (* const glDepthFunc)(GLenum); +/// Pointer to glDepthMask OpenGL function. +extern void (* const glDepthMask)(GLboolean); +/// Pointer to glDepthRangef OpenGL function. +extern void (* const glDepthRangef)(GLfloat, GLfloat); +/// Pointer to glDetachShader OpenGL function. +extern void (* const glDetachShader)(GLuint, GLuint); +/// Pointer to glDisable OpenGL function. +extern void (* const glDisable)(GLenum); +/// Pointer to glDisableVertexAttribArray OpenGL function. +extern void (* const glDisableVertexAttribArray)(GLuint); +/// Pointer to glDrawArrays OpenGL function. +extern void (* const glDrawArrays)(GLenum, GLint, GLsizei); +/// Pointer to glDrawElements OpenGL function. +extern void (* const glDrawElements)(GLenum, GLsizei, GLenum, const void *); +/// Pointer to glEnable OpenGL function. +extern void (* const glEnable)(GLenum); +/// Pointer to glEnableVertexAttribArray OpenGL function. +extern void (* const glEnableVertexAttribArray)(GLuint); +/// Pointer to glFinish OpenGL function. +extern void (* const glFinish)(); +/// Pointer to glFlush OpenGL function. +extern void (* const glFlush)(); +/// Pointer to glFramebufferRenderbuffer OpenGL function. +extern void (* const glFramebufferRenderbuffer)(GLenum, GLenum, GLenum, GLuint); +/// Pointer to glFramebufferTexture2D OpenGL function. +extern void (* const glFramebufferTexture2D)(GLenum, GLenum, GLenum, GLuint, GLint); +/// Pointer to glFrontFace OpenGL function. +extern void (* const glFrontFace)(GLenum); +/// Pointer to glGenBuffers OpenGL function. +extern void (* const glGenBuffers)(GLsizei, GLuint *); +/// Pointer to glGenerateMipmap OpenGL function. +extern void (* const glGenerateMipmap)(GLenum); +/// Pointer to glGenFramebuffers OpenGL function. +extern void (* const glGenFramebuffers)(GLsizei, GLuint *); +/// Pointer to glGenRenderbuffers OpenGL function. +extern void (* const glGenRenderbuffers)(GLsizei, GLuint *); +/// Pointer to glGenTextures OpenGL function. +extern void (* const glGenTextures)(GLsizei, GLuint *); +/// Pointer to glGetActiveAttrib OpenGL function. +extern void (* const glGetActiveAttrib)(GLuint, GLuint, GLsizei, GLsizei *, GLint *, GLenum *, GLchar *); +/// Pointer to glGetActiveUniform OpenGL function. +extern void (* const glGetActiveUniform)(GLuint, GLuint, GLsizei, GLsizei *, GLint *, GLenum *, GLchar *); +/// Pointer to glGetAttachedShaders OpenGL function. +extern void (* const glGetAttachedShaders)(GLuint, GLsizei, GLsizei *, GLuint *); +/// Pointer to glGetAttribLocation OpenGL function. +extern GLint (* const glGetAttribLocation)(GLuint, const GLchar *); +/// Pointer to glGetBooleanv OpenGL function. +extern void (* const glGetBooleanv)(GLenum, GLboolean *); +/// Pointer to glGetBufferParameteriv OpenGL function. +extern void (* const glGetBufferParameteriv)(GLenum, GLenum, GLint *); +/// Pointer to glGetError OpenGL function. +extern GLenum (* const glGetError)(); +/// Pointer to glGetFloatv OpenGL function. +extern void (* const glGetFloatv)(GLenum, GLfloat *); +/// Pointer to glGetFramebufferAttachmentParameteriv OpenGL function. +extern void (* const glGetFramebufferAttachmentParameteriv)(GLenum, GLenum, GLenum, GLint *); +/// Pointer to glGetIntegerv OpenGL function. +extern void (* const glGetIntegerv)(GLenum, GLint *); +/// Pointer to glGetProgramInfoLog OpenGL function. +extern void (* const glGetProgramInfoLog)(GLuint, GLsizei, GLsizei *, GLchar *); +/// Pointer to glGetProgramiv OpenGL function. +extern void (* const glGetProgramiv)(GLuint, GLenum, GLint *); +/// Pointer to glGetRenderbufferParameteriv OpenGL function. +extern void (* const glGetRenderbufferParameteriv)(GLenum, GLenum, GLint *); +/// Pointer to glGetShaderInfoLog OpenGL function. +extern void (* const glGetShaderInfoLog)(GLuint, GLsizei, GLsizei *, GLchar *); +/// Pointer to glGetShaderiv OpenGL function. +extern void (* const glGetShaderiv)(GLuint, GLenum, GLint *); +/// Pointer to glGetShaderSource OpenGL function. +extern void (* const glGetShaderSource)(GLuint, GLsizei, GLsizei *, GLchar *); +/// Pointer to glGetString OpenGL function. +extern const GLubyte *(*glGetString)(GLenum); +/// Pointer to glGetTexParameterfv OpenGL function. +extern void (* const glGetTexParameterfv)(GLenum, GLenum, GLfloat *); +/// Pointer to glGetTexParameteriv OpenGL function. +extern void (* const glGetTexParameteriv)(GLenum, GLenum, GLint *); +/// Pointer to glGetUniformfv OpenGL function. +extern void (* const glGetUniformfv)(GLuint, GLint, GLfloat *); +/// Pointer to glGetUniformiv OpenGL function. +extern void (* const glGetUniformiv)(GLuint, GLint, GLint *); +/// Pointer to glGetUniformLocation OpenGL function. +extern GLint (* const glGetUniformLocation)(GLuint, const GLchar *); +/// Pointer to glGetVertexAttribfv OpenGL function. +extern void (* const glGetVertexAttribfv)(GLuint, GLenum, GLfloat *); +/// Pointer to glGetVertexAttribiv OpenGL function. +extern void (* const glGetVertexAttribiv)(GLuint, GLenum, GLint *); +/// Pointer to glGetVertexAttribPointerv OpenGL function. +extern void (* const glGetVertexAttribPointerv)(GLuint, GLenum, void **); +/// Pointer to glHint OpenGL function. +extern void (* const glHint)(GLenum, GLenum); +/// Pointer to glIsBuffer OpenGL function. +extern GLboolean (* const glIsBuffer)(GLuint); +/// Pointer to glIsEnabled OpenGL function. +extern GLboolean (* const glIsEnabled)(GLenum); +/// Pointer to glIsFramebuffer OpenGL function. +extern GLboolean (* const glIsFramebuffer)(GLuint); +/// Pointer to glIsProgram OpenGL function. +extern GLboolean (* const glIsProgram)(GLuint); +/// Pointer to glIsRenderbuffer OpenGL function. +extern GLboolean (* const glIsRenderbuffer)(GLuint); +/// Pointer to glIsShader OpenGL function. +extern GLboolean (* const glIsShader)(GLuint); +/// Pointer to glIsTexture OpenGL function. +extern GLboolean (* const glIsTexture)(GLuint); +/// Pointer to glLineWidth OpenGL function. +extern void (* const glLineWidth)(GLfloat); +/// Pointer to glLinkProgram OpenGL function. +extern void (* const glLinkProgram)(GLuint); +/// Pointer to glPixelStorei OpenGL function. +extern void (* const glPixelStorei)(GLenum, GLint); +/// Pointer to glPolygonOffset OpenGL function. +extern void (* const glPolygonOffset)(GLfloat, GLfloat); +/// Pointer to glReadPixels OpenGL function. +extern void (* const glReadPixels)(GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, void *); +/// Pointer to glRenderbufferStorage OpenGL function. +extern void (* const glRenderbufferStorage)(GLenum, GLenum, GLsizei, GLsizei); +/// Pointer to glSampleCoverage OpenGL function. +extern void (* const glSampleCoverage)(GLfloat, GLboolean); +/// Pointer to glScissor OpenGL function. +extern void (* const glScissor)(GLint, GLint, GLsizei, GLsizei); +/// Pointer to glShaderSource OpenGL function. +extern void (* const glShaderSource)(GLuint, GLsizei, const GLchar * const*, const GLint *); +/// Pointer to glStencilFunc OpenGL function. +extern void (* const glStencilFunc)(GLenum, GLint, GLuint); +/// Pointer to glStencilFuncSeparate OpenGL function. +extern void (* const glStencilFuncSeparate)(GLenum, GLenum, GLint, GLuint); +/// Pointer to glStencilMask OpenGL function. +extern void (* const glStencilMask)(GLuint); +/// Pointer to glStencilMaskSeparate OpenGL function. +extern void (* const glStencilMaskSeparate)(GLenum, GLuint); +/// Pointer to glStencilOp OpenGL function. +extern void (* const glStencilOp)(GLenum, GLenum, GLenum); +/// Pointer to glStencilOpSeparate OpenGL function. +extern void (* const glStencilOpSeparate)(GLenum, GLenum, GLenum, GLenum); +/// Pointer to glTexImage2D OpenGL function. +extern void (* const glTexImage2D)(GLenum, GLint, GLint, GLsizei, GLsizei, GLint, GLenum, GLenum, const void *); +/// Pointer to glTexParameterf OpenGL function. +extern void (* const glTexParameterf)(GLenum, GLenum, GLfloat); +/// Pointer to glTexParameterfv OpenGL function. +extern void (* const glTexParameterfv)(GLenum, GLenum, const GLfloat *); +/// Pointer to glTexParameteri OpenGL function. +extern void (* const glTexParameteri)(GLenum, GLenum, GLint); +/// Pointer to glTexParameteriv OpenGL function. +extern void (* const glTexParameteriv)(GLenum, GLenum, const GLint *); +/// Pointer to glTexSubImage2D OpenGL function. +extern void (* const glTexSubImage2D)(GLenum, GLint, GLint, GLint, GLsizei, GLsizei, GLenum, GLenum, const void *); +/// Pointer to glUniform1f OpenGL function. +extern void (* const glUniform1f)(GLint, GLfloat); +/// Pointer to glUniform1fv OpenGL function. +extern void (* const glUniform1fv)(GLint, GLsizei, const GLfloat *); +/// Pointer to glUniform1i OpenGL function. +extern void (* const glUniform1i)(GLint, GLint); +/// Pointer to glUniform1iv OpenGL function. +extern void (* const glUniform1iv)(GLint, GLsizei, const GLint *); +/// Pointer to glUniform2f OpenGL function. +extern void (* const glUniform2f)(GLint, GLfloat, GLfloat); +/// Pointer to glUniform2fv OpenGL function. +extern void (* const glUniform2fv)(GLint, GLsizei, const GLfloat *); +/// Pointer to glUniform2i OpenGL function. +extern void (* const glUniform2i)(GLint, GLint, GLint); +/// Pointer to glUniform2iv OpenGL function. +extern void (* const glUniform2iv)(GLint, GLsizei, const GLint *); +/// Pointer to glUniform3f OpenGL function. +extern void (* const glUniform3f)(GLint, GLfloat, GLfloat, GLfloat); +/// Pointer to glUniform3fv OpenGL function. +extern void (* const glUniform3fv)(GLint, GLsizei, const GLfloat *); +/// Pointer to glUniform3i OpenGL function. +extern void (* const glUniform3i)(GLint, GLint, GLint, GLint); +/// Pointer to glUniform3iv OpenGL function. +extern void (* const glUniform3iv)(GLint, GLsizei, const GLint *); +/// Pointer to glUniform4f OpenGL function. +extern void (* const glUniform4f)(GLint, GLfloat, GLfloat, GLfloat, GLfloat); +/// Pointer to glUniform4fv OpenGL function. +extern void (* const glUniform4fv)(GLint, GLsizei, const GLfloat *); +/// Pointer to glUniform4i OpenGL function. +extern void (* const glUniform4i)(GLint, GLint, GLint, GLint, GLint); +/// Pointer to glUniform4iv OpenGL function. +extern void (* const glUniform4iv)(GLint, GLsizei, const GLint *); +/// Pointer to glUniformMatrix2fv OpenGL function. +extern void (* const glUniformMatrix2fv)(GLint, GLsizei, GLboolean, const GLfloat *); +/// Pointer to glUniformMatrix3fv OpenGL function. +extern void (* const glUniformMatrix3fv)(GLint, GLsizei, GLboolean, const GLfloat *); +/// Pointer to glUniformMatrix4fv OpenGL function. +extern void (* const glUniformMatrix4fv)(GLint, GLsizei, GLboolean, const GLfloat *); +/// Pointer to glUseProgram OpenGL function. +extern void (* const glUseProgram)(GLuint); +/// Pointer to glValidateProgram OpenGL function. +extern void (* const glValidateProgram)(GLuint); +/// Pointer to glVertexAttrib1f OpenGL function. +extern void (* const glVertexAttrib1f)(GLuint, GLfloat); +/// Pointer to glVertexAttrib1fv OpenGL function. +extern void (* const glVertexAttrib1fv)(GLuint, const GLfloat *); +/// Pointer to glVertexAttrib2f OpenGL function. +extern void (* const glVertexAttrib2f)(GLuint, GLfloat, GLfloat); +/// Pointer to glVertexAttrib2fv OpenGL function. +extern void (* const glVertexAttrib2fv)(GLuint, const GLfloat *); +/// Pointer to glVertexAttrib3f OpenGL function. +extern void (* const glVertexAttrib3f)(GLuint, GLfloat, GLfloat, GLfloat); +/// Pointer to glVertexAttrib3fv OpenGL function. +extern void (* const glVertexAttrib3fv)(GLuint, const GLfloat *); +/// Pointer to glVertexAttrib4f OpenGL function. +extern void (* const glVertexAttrib4f)(GLuint, GLfloat, GLfloat, GLfloat, GLfloat); +/// Pointer to glVertexAttrib4fv OpenGL function. +extern void (* const glVertexAttrib4fv)(GLuint, const GLfloat *); +/// Pointer to glVertexAttribPointer OpenGL function. +extern void (* const glVertexAttribPointer)(GLuint, GLint, GLenum, GLboolean, GLsizei, const void *); +/// Pointer to glViewport OpenGL function. +extern void (* const glViewport)(GLint, GLint, GLsizei, GLsizei); + +#ifndef MBGL_USE_GLES2 +/// Pointer to glDrawPixels OpenGL function. +extern void (* const glDrawPixels)(GLsizei, GLsizei, GLenum, GLenum, const GLvoid *); +/// Pointer to glGetDoublev OpenGL function. +extern void (* const glGetDoublev)(GLenum, GLdouble *); +/// Pointer to glPixelTransferf OpenGL function. +extern void (* const glPixelTransferf)(GLenum, GLfloat); +/// Pointer to glPixelZoom OpenGL function. +extern void (* const glPixelZoom)(GLfloat, GLfloat); +/// Pointer to glPointSize OpenGL function. +extern void (* const glPointSize)(GLfloat); +/// Pointer to glRasterPos4d OpenGL function. +extern void (* const glRasterPos4d)(GLdouble, GLdouble, GLdouble, GLdouble); +#endif + +#ifndef NDEBUG +/// Check for GL errors and print on the console. +void glCheckError(const char *cmd, const char *file, int line); +#endif + +} // namespace platform +} // namespace mbgl
\ No newline at end of file diff --git a/platform/gfx/gl/src/mbgl/gl/attribute.cpp b/platform/gfx/gl/src/mbgl/gl/attribute.cpp new file mode 100644 index 0000000000..d5240b5b7a --- /dev/null +++ b/platform/gfx/gl/src/mbgl/gl/attribute.cpp @@ -0,0 +1,19 @@ +#include <mbgl/gl/attribute.hpp> +#include <mbgl/gl/context.hpp> + +namespace mbgl { +namespace gl { + +using namespace platform; + +optional<AttributeLocation> queryLocation(ProgramID id, const char* name) { + GLint attributeLocation = MBGL_CHECK_ERROR(glGetAttribLocation(id, name)); + if (attributeLocation != -1) { + return attributeLocation; + } else { + return {}; + } +} + +} // namespace gl +} // namespace mbgl diff --git a/platform/gfx/gl/src/mbgl/gl/attribute.hpp b/platform/gfx/gl/src/mbgl/gl/attribute.hpp new file mode 100644 index 0000000000..d578bdb361 --- /dev/null +++ b/platform/gfx/gl/src/mbgl/gl/attribute.hpp @@ -0,0 +1,115 @@ +#pragma once + +#include <mbgl/gfx/attribute.hpp> +#include <mbgl/gl/types.hpp> +#include <mbgl/programs/attributes.hpp> +#include <mbgl/util/literal.hpp> +#include <mbgl/util/optional.hpp> + +#include <vector> +#include <string> + +namespace mbgl { +namespace gl { + +using AttributeBindingArray = std::vector<optional<gfx::AttributeBinding>>; +using NamedAttributeLocations = std::vector<std::pair<const std::string, AttributeLocation>>; + +optional<AttributeLocation> queryLocation(ProgramID id, const char* name); + +template <class> +class AttributeLocations; + +template <class... As> +class AttributeLocations<TypeList<As...>> final { +private: + using Locations = + IndexedTuple<TypeList<As...>, TypeList<ExpandToType<As, optional<AttributeLocation>>...>>; + + Locations locations; + +public: + AttributeLocations() = default; + + void queryLocations(const ProgramID& id) { + locations = Locations{ + queryLocation(id, concat_literals<&string_literal<'a', '_'>::value, &As::name>::value())... }; + using TypeOfFirst = typename std::tuple_element<0, std::tuple<As...>>::type; + auto first = locations.template get<TypeOfFirst>(); + assert(first && first.value() == 0); + } + + static constexpr const char* getFirstAttribName() { + // Static assert that attribute list starts with position: we bind it on location 0. + using TypeOfFirst = typename std::tuple_element<0, std::tuple<As...>>::type; + static_assert(std::is_same<attributes::pos, TypeOfFirst>::value || std::is_same<attributes::pos_offset, TypeOfFirst>::value || + std::is_same<attributes::pos_normal, TypeOfFirst>::value, "Program must start with position related attribute."); + return concat_literals<&string_literal<'a', '_'>::value, TypeOfFirst::name>::value(); + } + + NamedAttributeLocations getNamedLocations() const { + NamedAttributeLocations result; + + auto maybeAddLocation = [&] (const std::string& name, const optional<AttributeLocation>& location) { + if (location) { + result.emplace_back(name, *location); + } + }; + + util::ignore({ (maybeAddLocation(concat_literals<&string_literal<'a', '_'>::value, &As::name>::value(), + locations.template get<As>()), + 0)... }); + + return result; + } + + AttributeBindingArray toBindingArray(const gfx::AttributeBindings<TypeList<As...>>& bindings) const { + AttributeBindingArray result; + result.resize(sizeof...(As)); + + auto maybeAddBinding = [&] (const optional<AttributeLocation>& location, + const optional<gfx::AttributeBinding>& binding) { + if (location) { + result.at(*location) = binding; + } + }; + + util::ignore({ (maybeAddBinding(locations.template get<As>(), bindings.template get<As>()), 0)... }); + + return result; + } +}; + +template <class> +class AttributeKey; + +constexpr auto attributeDefinePrefix() { + return "#define HAS_UNIFORM_u_"; +} + +template <class... As> +class AttributeKey<TypeList<As...>> final { +public: + static_assert(sizeof...(As) <= 32, "attribute count exceeds 32"); + + static uint32_t compute(const gfx::AttributeBindings<TypeList<As...>>& bindings) { + uint32_t value = 0; + util::ignore( + { (bindings.template get<As>() ? (void)(value |= 1 << TypeIndex<As, As...>::value) + : (void)0, + 0)... }); + return value; + } + + static std::string defines(const gfx::AttributeBindings<TypeList<As...>>& bindings) { + std::string result; + util::ignore({ (!bindings.template get<As>() + ? (void)(result += concat_literals<&attributeDefinePrefix, &As::name, &string_literal<'\n'>::value>::value()) + : (void)0, + 0)... }); + return result; + } +}; + +} // namespace gl +} // namespace mbgl diff --git a/platform/gfx/gl/src/mbgl/gl/command_encoder.cpp b/platform/gfx/gl/src/mbgl/gl/command_encoder.cpp new file mode 100644 index 0000000000..a7df14df09 --- /dev/null +++ b/platform/gfx/gl/src/mbgl/gl/command_encoder.cpp @@ -0,0 +1,60 @@ +#include <mbgl/gl/command_encoder.hpp> +#include <mbgl/gl/upload_pass.hpp> +#include <mbgl/gl/render_pass.hpp> +#include <mbgl/gl/context.hpp> +#include <mbgl/gl/renderable_resource.hpp> +#include <mbgl/gl/debugging_extension.hpp> +#include <mbgl/platform/gl_functions.hpp> + +#include <cstring> + +namespace mbgl { +namespace gl { + +CommandEncoder::~CommandEncoder() { + const auto debugGroup(createDebugGroup("cleanup")); + context.performCleanup(); +} + +std::unique_ptr<gfx::UploadPass> +CommandEncoder::createUploadPass(const char* name) { + return std::make_unique<gl::UploadPass>(*this, name); +} + +std::unique_ptr<gfx::RenderPass> +CommandEncoder::createRenderPass(const char* name, const gfx::RenderPassDescriptor& descriptor) { + return std::make_unique<gl::RenderPass>(*this, name, descriptor); +} + +void CommandEncoder::present(gfx::Renderable& renderable) { + renderable.getResource<gl::RenderableResource>().swap(); +} + +void CommandEncoder::pushDebugGroup(const char* name) { + (void)name; +#ifndef NDEBUG + if (auto debugging = context.getDebuggingExtension()) { + if (debugging->pushDebugGroup) { + MBGL_CHECK_ERROR(debugging->pushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, 0, + platform::GLsizei(strlen(name)), name)); + } else if (debugging->pushGroupMarkerEXT) { + MBGL_CHECK_ERROR(debugging->pushGroupMarkerEXT(platform::GLsizei(strlen(name) + 1), name)); + } + } +#endif +} + +void CommandEncoder::popDebugGroup() { +#ifndef NDEBUG + if (auto debugging = context.getDebuggingExtension()) { + if (debugging->popDebugGroup) { + MBGL_CHECK_ERROR(debugging->popDebugGroup()); + } else if (debugging->popGroupMarkerEXT) { + MBGL_CHECK_ERROR(debugging->popGroupMarkerEXT()); + } + } +#endif +} + +} // namespace gl +} // namespace mbgl diff --git a/platform/gfx/gl/src/mbgl/gl/command_encoder.hpp b/platform/gfx/gl/src/mbgl/gl/command_encoder.hpp new file mode 100644 index 0000000000..f47aad4946 --- /dev/null +++ b/platform/gfx/gl/src/mbgl/gl/command_encoder.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include <mbgl/gfx/command_encoder.hpp> + +namespace mbgl { +namespace gl { + +class Context; + +class CommandEncoder final : public gfx::CommandEncoder { +public: + explicit CommandEncoder(gl::Context& context_) : context(context_) { + } + + ~CommandEncoder() override; + + friend class UploadPass; + friend class RenderPass; + + std::unique_ptr<gfx::UploadPass> createUploadPass(const char* name) override; + std::unique_ptr<gfx::RenderPass> createRenderPass(const char* name, const gfx::RenderPassDescriptor&) override; + void present(gfx::Renderable&) override; + +private: + void pushDebugGroup(const char* name) override; + void popDebugGroup() override; + +public: + gl::Context& context; +}; + +} // namespace gl +} // namespace mbgl diff --git a/platform/gfx/gl/src/mbgl/gl/context.cpp b/platform/gfx/gl/src/mbgl/gl/context.cpp new file mode 100644 index 0000000000..4d9c2055de --- /dev/null +++ b/platform/gfx/gl/src/mbgl/gl/context.cpp @@ -0,0 +1,755 @@ +#include <mbgl/gl/context.hpp> +#include <mbgl/gl/enum.hpp> +#include <mbgl/gl/renderer_backend.hpp> +#include <mbgl/gl/texture_resource.hpp> +#include <mbgl/gl/renderbuffer_resource.hpp> +#include <mbgl/gl/draw_scope_resource.hpp> +#include <mbgl/gl/texture.hpp> +#include <mbgl/gl/offscreen_texture.hpp> +#include <mbgl/gl/command_encoder.hpp> +#include <mbgl/gl/debugging_extension.hpp> +#include <mbgl/gl/vertex_array_extension.hpp> +#include <mbgl/util/traits.hpp> +#include <mbgl/util/std.hpp> +#include <mbgl/util/logging.hpp> + +#include <cstring> + +namespace mbgl { +namespace gl { + +using namespace platform; + +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(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"); +static_assert(std::is_same<TextureID, GLuint>::value, "OpenGL type mismatch"); +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(underlying_type(UniformDataType::Float) == GL_FLOAT, "OpenGL type mismatch"); +static_assert(underlying_type(UniformDataType::FloatVec2) == GL_FLOAT_VEC2, "OpenGL type mismatch"); +static_assert(underlying_type(UniformDataType::FloatVec3) == GL_FLOAT_VEC3, "OpenGL type mismatch"); +static_assert(underlying_type(UniformDataType::FloatVec4) == GL_FLOAT_VEC4, "OpenGL type mismatch"); +static_assert(underlying_type(UniformDataType::Int) == GL_INT, "OpenGL type mismatch"); +static_assert(underlying_type(UniformDataType::IntVec2) == GL_INT_VEC2, "OpenGL type mismatch"); +static_assert(underlying_type(UniformDataType::IntVec3) == GL_INT_VEC3, "OpenGL type mismatch"); +static_assert(underlying_type(UniformDataType::IntVec4) == GL_INT_VEC4, "OpenGL type mismatch"); +static_assert(underlying_type(UniformDataType::Bool) == GL_BOOL, "OpenGL type mismatch"); +static_assert(underlying_type(UniformDataType::BoolVec2) == GL_BOOL_VEC2, "OpenGL type mismatch"); +static_assert(underlying_type(UniformDataType::BoolVec3) == GL_BOOL_VEC3, "OpenGL type mismatch"); +static_assert(underlying_type(UniformDataType::BoolVec4) == GL_BOOL_VEC4, "OpenGL type mismatch"); +static_assert(underlying_type(UniformDataType::FloatMat2) == GL_FLOAT_MAT2, "OpenGL type mismatch"); +static_assert(underlying_type(UniformDataType::FloatMat3) == GL_FLOAT_MAT3, "OpenGL type mismatch"); +static_assert(underlying_type(UniformDataType::FloatMat4) == GL_FLOAT_MAT4, "OpenGL type mismatch"); +static_assert(underlying_type(UniformDataType::Sampler2D) == GL_SAMPLER_2D, "OpenGL type mismatch"); +static_assert(underlying_type(UniformDataType::SamplerCube) == GL_SAMPLER_CUBE, "OpenGL type mismatch"); + +Context::Context(RendererBackend& backend_) + : gfx::Context([] { + GLint value; + MBGL_CHECK_ERROR(glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &value)); + return value; + }()), backend(backend_) { +} + +Context::~Context() { + if (cleanupOnDestruction) { + reset(); + } +} + +void Context::initializeExtensions(const std::function<gl::ProcAddress(const char*)>& getProcAddress) { + if (const auto* extensions = + reinterpret_cast<const char*>(MBGL_CHECK_ERROR(glGetString(GL_EXTENSIONS)))) { + + auto fn = [&]( + std::initializer_list<std::pair<const char*, const char*>> probes) -> ProcAddress { + for (auto probe : probes) { + if (strstr(extensions, probe.first) != nullptr) { + if (ProcAddress ptr = getProcAddress(probe.second)) { + return ptr; + } + } + } + return nullptr; + }; + + static const std::string renderer = []() { + std::string r = reinterpret_cast<const char*>(MBGL_CHECK_ERROR(glGetString(GL_RENDERER))); + Log::Info(Event::General, "GPU Identifier: %s", r.c_str()); + return r; + }(); + + // Block ANGLE on Direct3D since the debugging extension is causing crashes + if (!(renderer.find("ANGLE") != std::string::npos + && renderer.find("Direct3D") != std::string::npos)) { + debugging = std::make_unique<extension::Debugging>(fn); + } + + // Block Adreno 2xx, 3xx as it crashes on glBuffer(Sub)Data + // Block ARM Mali-T720 (in some MT8163 chipsets) as it crashes on glBindVertexArray + // Block ANGLE on Direct3D as the combination of Qt + Windows + ANGLE leads to crashes + if (renderer.find("Adreno (TM) 2") == std::string::npos + && renderer.find("Adreno (TM) 3") == std::string::npos + && (!(renderer.find("ANGLE") != std::string::npos + && renderer.find("Direct3D") != std::string::npos)) + && renderer.find("Mali-T720") == std::string::npos + && renderer.find("Sapphire 650") == std::string::npos + && !disableVAOExtension) { + vertexArray = std::make_unique<extension::VertexArray>(fn); + } + +#if MBGL_USE_GLES2 + constexpr const char* halfFloatExtensionName = "OES_texture_half_float"; + constexpr const char* halfFloatColorBufferExtensionName = "EXT_color_buffer_half_float"; +#else + constexpr const char* halfFloatExtensionName = "ARB_half_float_pixel"; + constexpr const char* halfFloatColorBufferExtensionName = "ARB_color_buffer_float"; +#endif + if (strstr(extensions, halfFloatExtensionName) != nullptr && + strstr(extensions, halfFloatColorBufferExtensionName) != nullptr) { + + supportsHalfFloatTextures = true; + } + + if (!supportsVertexArrays()) { + Log::Warning(Event::OpenGL, "Not using Vertex Array Objects"); + } + } +} + +void Context::enableDebugging() { + if (!debugging || !debugging->debugMessageControl || !debugging->debugMessageCallback) { + return; + } + + // This will enable all messages including performance hints + // MBGL_CHECK_ERROR(debugging->debugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, nullptr, GL_TRUE)); + + // This will only enable high and medium severity messages + MBGL_CHECK_ERROR(debugging->debugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_HIGH, 0, nullptr, GL_TRUE)); + MBGL_CHECK_ERROR(debugging->debugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_MEDIUM, 0, nullptr, GL_TRUE)); + MBGL_CHECK_ERROR(debugging->debugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_NOTIFICATION, 0, nullptr, GL_FALSE)); + + MBGL_CHECK_ERROR(debugging->debugMessageCallback(extension::Debugging::DebugCallback, nullptr)); +} + +UniqueShader Context::createShader(ShaderType type, const std::initializer_list<const char*>& sources) { + UniqueShader result { MBGL_CHECK_ERROR(glCreateShader(static_cast<GLenum>(type))), { this } }; + + MBGL_CHECK_ERROR(glShaderSource(result, static_cast<GLsizei>(sources.size()), sources.begin(), nullptr)); + 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"); +} + +UniqueProgram Context::createProgram(ShaderID vertexShader, ShaderID fragmentShader, const char* location0AttribName) { + UniqueProgram result { MBGL_CHECK_ERROR(glCreateProgram()), { this } }; + + MBGL_CHECK_ERROR(glAttachShader(result, vertexShader)); + MBGL_CHECK_ERROR(glAttachShader(result, fragmentShader)); + + // It is important to have attribute at position 0 enabled: conveniently, + // position attribute is always first and always enabled. The integrity of + // this assumption is verified in AttributeLocations::queryLocations and + // AttributeLocations::getFirstAttribName. + MBGL_CHECK_ERROR(glBindAttribLocation(result, 0, location0AttribName)); + + linkProgram(result); + + return result; +} + +void Context::linkProgram(ProgramID program_) { + MBGL_CHECK_ERROR(glLinkProgram(program_)); + verifyProgramLinkage(program_); +} + +void Context::verifyProgramLinkage(ProgramID 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"); +} + +UniqueTexture Context::createUniqueTexture() { + if (pooledTextures.empty()) { + pooledTextures.resize(TextureMax); + MBGL_CHECK_ERROR(glGenTextures(TextureMax, pooledTextures.data())); + } + + TextureID id = pooledTextures.back(); + pooledTextures.pop_back(); + return UniqueTexture{ std::move(id), { this } }; +} + +bool Context::supportsVertexArrays() const { + return vertexArray && + vertexArray->genVertexArrays && + vertexArray->bindVertexArray && + vertexArray->deleteVertexArrays; +} + +VertexArray Context::createVertexArray() { + if (supportsVertexArrays()) { + VertexArrayID id = 0; + MBGL_CHECK_ERROR(vertexArray->genVertexArrays(1, &id)); + UniqueVertexArray vao(std::move(id), { this }); + return { UniqueVertexArrayState(new VertexArrayState(std::move(vao)), VertexArrayStateDeleter { true })}; + } else { + // On GL implementations which do not support vertex arrays, attribute bindings are global state. + // So return a VertexArray which shares our global state tracking and whose deleter is a no-op. + return { UniqueVertexArrayState(&globalVertexArrayState, VertexArrayStateDeleter { false }) }; + } +} + +UniqueFramebuffer Context::createFramebuffer() { + FramebufferID id = 0; + MBGL_CHECK_ERROR(glGenFramebuffers(1, &id)); + return UniqueFramebuffer{ std::move(id), { this } }; +} + +std::unique_ptr<gfx::TextureResource> Context::createTextureResource( + const Size size, const gfx::TexturePixelType format, const gfx::TextureChannelDataType type) { + auto obj = createUniqueTexture(); + std::unique_ptr<gfx::TextureResource> resource = + std::make_unique<gl::TextureResource>(std::move(obj)); + + // Always use texture unit 0 for manipulating it. + activeTextureUnit = 0; + texture[0] = static_cast<gl::TextureResource&>(*resource).texture; + + // Creates an empty texture with the specified size and format. + MBGL_CHECK_ERROR(glTexImage2D(GL_TEXTURE_2D, 0, Enum<gfx::TexturePixelType>::to(format), + size.width, size.height, 0, + Enum<gfx::TexturePixelType>::to(format), + Enum<gfx::TextureChannelDataType>::to(type), nullptr)); + + // 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)); + + return resource; +} + +std::unique_ptr<gfx::RenderbufferResource> +Context::createRenderbufferResource(const gfx::RenderbufferPixelType 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, Enum<gfx::RenderbufferPixelType>::to(type), size.width, size.height)); + bindRenderbuffer = 0; + return std::make_unique<gl::RenderbufferResource>(std::move(renderbuffer)); +} + + +std::unique_ptr<uint8_t[]> Context::readFramebuffer(const Size size, const gfx::TexturePixelType format, const bool flip) { + const size_t stride = size.width * (format == gfx::TexturePixelType::RGBA ? 4 : 1); + auto data = std::make_unique<uint8_t[]>(stride * size.height); + + // 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 }; + + MBGL_CHECK_ERROR(glReadPixels(0, 0, size.width, size.height, + Enum<gfx::TexturePixelType>::to(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, gfx::TexturePixelType format) { + pixelStoreUnpack = { 1 }; + // TODO + if (format != gfx::TexturePixelType::RGBA) { + format = gfx::TexturePixelType::Luminance; + } + MBGL_CHECK_ERROR(glDrawPixels(size.width, size.height, Enum<gfx::TexturePixelType>::to(format), + GL_UNSIGNED_BYTE, data)); +} +#endif // MBGL_USE_GLES2 + +namespace { + +void checkFramebuffer() { + GLenum status = MBGL_CHECK_ERROR(glCheckFramebufferStatus(GL_FRAMEBUFFER)); + if (status != GL_FRAMEBUFFER_COMPLETE) { + switch (status) { + case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: + throw std::runtime_error("Couldn't create framebuffer: incomplete attachment"); + case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: + throw std::runtime_error("Couldn't create framebuffer: incomplete missing attachment"); +#ifdef GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER + case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: + throw std::runtime_error("Couldn't create framebuffer: incomplete draw buffer"); +#endif +#ifdef GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER + case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER: + throw std::runtime_error("Couldn't create framebuffer: incomplete read buffer"); +#endif +#ifdef GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS + case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS: + throw std::runtime_error("Couldn't create framebuffer: incomplete dimensions"); +#endif + + case GL_FRAMEBUFFER_UNSUPPORTED: + throw std::runtime_error("Couldn't create framebuffer: unsupported"); + default: + throw std::runtime_error("Couldn't create framebuffer: other"); + } + } +} + +void bindDepthStencilRenderbuffer( + const gfx::Renderbuffer<gfx::RenderbufferPixelType::DepthStencil>& depthStencil) { + auto& depthStencilResource = depthStencil.getResource<gl::RenderbufferResource>(); +#ifdef GL_DEPTH_STENCIL_ATTACHMENT + MBGL_CHECK_ERROR(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, + GL_RENDERBUFFER, depthStencilResource.renderbuffer)); +#else + MBGL_CHECK_ERROR(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, + depthStencilResource.renderbuffer)); + MBGL_CHECK_ERROR(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, + GL_RENDERBUFFER, depthStencilResource.renderbuffer)); +#endif +} + +} // namespace + +Framebuffer +Context::createFramebuffer(const gfx::Renderbuffer<gfx::RenderbufferPixelType::RGBA>& color, + const gfx::Renderbuffer<gfx::RenderbufferPixelType::DepthStencil>& depthStencil) { + if (color.getSize() != depthStencil.getSize()) { + throw std::runtime_error("Renderbuffer size mismatch"); + } + auto fbo = createFramebuffer(); + bindFramebuffer = fbo; + + auto& colorResource = color.getResource<gl::RenderbufferResource>(); + MBGL_CHECK_ERROR(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_RENDERBUFFER, colorResource.renderbuffer)); + bindDepthStencilRenderbuffer(depthStencil); + checkFramebuffer(); + return { color.getSize(), std::move(fbo) }; +} + +Framebuffer Context::createFramebuffer(const gfx::Renderbuffer<gfx::RenderbufferPixelType::RGBA>& color) { + auto fbo = createFramebuffer(); + bindFramebuffer = fbo; + auto& colorResource = color.getResource<gl::RenderbufferResource>(); + MBGL_CHECK_ERROR(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_RENDERBUFFER, colorResource.renderbuffer)); + checkFramebuffer(); + return { color.getSize(), std::move(fbo) }; +} + +Framebuffer +Context::createFramebuffer(const gfx::Texture& color, + const gfx::Renderbuffer<gfx::RenderbufferPixelType::DepthStencil>& depthStencil) { + if (color.size != depthStencil.getSize()) { + throw std::runtime_error("Renderbuffer size mismatch"); + } + auto fbo = createFramebuffer(); + bindFramebuffer = fbo; + MBGL_CHECK_ERROR(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, + color.getResource<gl::TextureResource>().texture, 0)); + bindDepthStencilRenderbuffer(depthStencil); + checkFramebuffer(); + return { color.size, std::move(fbo) }; +} + +Framebuffer Context::createFramebuffer(const gfx::Texture& color) { + auto fbo = createFramebuffer(); + bindFramebuffer = fbo; + MBGL_CHECK_ERROR(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, + color.getResource<gl::TextureResource>().texture, 0)); + checkFramebuffer(); + return { color.size, std::move(fbo) }; +} + +Framebuffer +Context::createFramebuffer(const gfx::Texture& color, + const gfx::Renderbuffer<gfx::RenderbufferPixelType::Depth>& depth) { + if (color.size != depth.getSize()) { + throw std::runtime_error("Renderbuffer size mismatch"); + } + auto fbo = createFramebuffer(); + bindFramebuffer = fbo; + MBGL_CHECK_ERROR(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, + color.getResource<gl::TextureResource>().texture, 0)); + + auto& depthResource = depth.getResource<gl::RenderbufferResource>(); + MBGL_CHECK_ERROR(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, + depthResource.renderbuffer)); + checkFramebuffer(); + return { depth.getSize(), std::move(fbo) }; +} + +std::unique_ptr<gfx::OffscreenTexture> +Context::createOffscreenTexture(const Size size, const gfx::TextureChannelDataType type) { + return std::make_unique<gl::OffscreenTexture>(*this, size, type); +} + +std::unique_ptr<gfx::DrawScopeResource> Context::createDrawScopeResource() { + return std::make_unique<gl::DrawScopeResource>(createVertexArray()); +} + +void Context::reset() { + std::copy(pooledTextures.begin(), pooledTextures.end(), std::back_inserter(abandonedTextures)); + pooledTextures.resize(0); + performCleanup(); +} + +void Context::setDirtyState() { + // Note: does not set viewport/scissorTest/bindFramebuffer to dirty + // since they are handled separately in the view object. + stencilFunc.setDirty(); + stencilMask.setDirty(); + stencilTest.setDirty(); + stencilOp.setDirty(); + depthRange.setDirty(); + depthMask.setDirty(); + depthTest.setDirty(); + depthFunc.setDirty(); + blend.setDirty(); + blendEquation.setDirty(); + blendFunc.setDirty(); + blendColor.setDirty(); + colorMask.setDirty(); + clearDepth.setDirty(); + clearColor.setDirty(); + clearStencil.setDirty(); + cullFace.setDirty(); + cullFaceSide.setDirty(); + cullFaceWinding.setDirty(); + program.setDirty(); + lineWidth.setDirty(); + activeTextureUnit.setDirty(); + pixelStorePack.setDirty(); + pixelStoreUnpack.setDirty(); +#if not MBGL_USE_GLES2 + pointSize.setDirty(); + pixelZoom.setDirty(); + rasterPos.setDirty(); + pixelTransferDepth.setDirty(); + pixelTransferStencil.setDirty(); +#endif // MBGL_USE_GLES2 + for (auto& tex : texture) { + tex.setDirty(); + } + vertexBuffer.setDirty(); + bindVertexArray.setDirty(); + globalVertexArrayState.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 = value::ColorMask::Default; + } + + if (depth) { + mask |= GL_DEPTH_BUFFER_BIT; + clearDepth = *depth; + depthMask = value::DepthMask::Default; + } + + if (stencil) { + mask |= GL_STENCIL_BUFFER_BIT; + clearStencil = *stencil; + stencilMask = value::StencilMask::Default; + } + + MBGL_CHECK_ERROR(glClear(mask)); +} + +void Context::setCullFaceMode(const gfx::CullFaceMode& mode) { + cullFace = mode.enabled; + + // These shouldn't need to be updated when face culling is disabled, but we + // might end up having the same isssues with Adreno 2xx GPUs as noted in + // Context::setDepthMode. + cullFaceSide = mode.side; + cullFaceWinding = mode.winding; +} + +void Context::setDepthMode(const gfx::DepthMode& depth) { + if (depth.func == gfx::DepthFunctionType::Always && depth.mask != gfx::DepthMaskType::ReadWrite) { + depthTest = false; + + // Workaround for rendering errors on Adreno 2xx GPUs. Depth-related state should + // not matter when the depth test is disabled, but on these GPUs it apparently does. + // https://github.com/mapbox/mapbox-gl-native/issues/9164 + depthFunc = depth.func; + depthMask = depth.mask; + depthRange = depth.range; + } else { + depthTest = true; + depthFunc = depth.func; + depthMask = depth.mask; + depthRange = depth.range; + } +} + +void Context::setStencilMode(const gfx::StencilMode& stencil) { + if (stencil.test.is<gfx::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 gfx::ColorMode& color) { + if (color.blendFunction.is<gfx::ColorMode::Replace>()) { + blend = false; + } else { + blend = true; + blendColor = color.blendColor; + apply_visitor([&] (const auto& blendFunction) { + blendEquation = gfx::ColorBlendEquationType(blendFunction.equation); + blendFunc = { blendFunction.srcFactor, blendFunction.dstFactor }; + }, color.blendFunction); + } + + colorMask = color.mask; +} + +std::unique_ptr<gfx::CommandEncoder> Context::createCommandEncoder() { + backend.updateAssumedState(); + if (backend.contextIsShared()) { + setDirtyState(); + } + return std::make_unique<gl::CommandEncoder>(*this); +} + +void Context::draw(const gfx::DrawMode& drawMode, + std::size_t indexOffset, + std::size_t indexLength) { + switch (drawMode.type) { + case gfx::DrawModeType::Points: +#if not MBGL_USE_GLES2 + // In OpenGL ES 2, the point size is set in the vertex shader. + pointSize = drawMode.size; +#endif // MBGL_USE_GLES2 + break; + case gfx::DrawModeType::Lines: + case gfx::DrawModeType::LineLoop: + case gfx::DrawModeType::LineStrip: + lineWidth = drawMode.size; + break; + default: + break; + } + + MBGL_CHECK_ERROR(glDrawElements( + Enum<gfx::DrawModeType>::to(drawMode.type), + static_cast<GLsizei>(indexLength), + GL_UNSIGNED_SHORT, + reinterpret_cast<GLvoid*>(sizeof(uint16_t) * indexOffset))); +} + +void Context::performCleanup() { + // TODO: Find a better way to unbind VAOs after we're done with them without introducing + // unnecessary bind(0)/bind(N) sequences. + { + activeTextureUnit = 1; + texture[1] = 0; + activeTextureUnit = 0; + texture[0] = 0; + + bindVertexArray = 0; + } + + for (auto id : abandonedPrograms) { + if (program == id) { + program.setDirty(); + } + MBGL_CHECK_ERROR(glDeleteProgram(id)); + } + abandonedPrograms.clear(); + + for (auto id : abandonedShaders) { + MBGL_CHECK_ERROR(glDeleteShader(id)); + } + abandonedShaders.clear(); + + if (!abandonedBuffers.empty()) { + for (const auto id : abandonedBuffers) { + if (vertexBuffer == id) { + vertexBuffer.setDirty(); + } else if (globalVertexArrayState.indexBuffer == id) { + globalVertexArrayState.indexBuffer.setDirty(); + } + } + MBGL_CHECK_ERROR(glDeleteBuffers(int(abandonedBuffers.size()), abandonedBuffers.data())); + abandonedBuffers.clear(); + } + + if (!abandonedTextures.empty()) { + for (const auto id : abandonedTextures) { + for (auto& binding : texture) { + if (binding == id) { + binding.setDirty(); + } + } + } + MBGL_CHECK_ERROR(glDeleteTextures(int(abandonedTextures.size()), abandonedTextures.data())); + abandonedTextures.clear(); + } + + if (!abandonedVertexArrays.empty()) { + assert(supportsVertexArrays()); + for (const auto id : abandonedVertexArrays) { + if (bindVertexArray == id) { + bindVertexArray.setDirty(); + } + } + MBGL_CHECK_ERROR(vertexArray->deleteVertexArrays(int(abandonedVertexArrays.size()), + abandonedVertexArrays.data())); + abandonedVertexArrays.clear(); + } + + if (!abandonedFramebuffers.empty()) { + for (const auto id : abandonedFramebuffers) { + if (bindFramebuffer == id) { + bindFramebuffer.setDirty(); + } + } + MBGL_CHECK_ERROR( + glDeleteFramebuffers(int(abandonedFramebuffers.size()), abandonedFramebuffers.data())); + abandonedFramebuffers.clear(); + } + + if (!abandonedRenderbuffers.empty()) { + MBGL_CHECK_ERROR(glDeleteRenderbuffers(int(abandonedRenderbuffers.size()), + abandonedRenderbuffers.data())); + abandonedRenderbuffers.clear(); + } +} + +void Context::reduceMemoryUsage() { + performCleanup(); + + // Ensure that all pending actions are executed to ensure that they happen before the app goes + // to the background. + MBGL_CHECK_ERROR(glFinish()); +} + +#if not defined(NDEBUG) +void Context::visualizeStencilBuffer() { +#if not MBGL_USE_GLES2 + setStencilMode(gfx::StencilMode::disabled()); + setDepthMode(gfx::DepthMode::disabled()); + setColorMode(gfx::ColorMode::unblended()); + program = 0; + + // Reset the value in case someone else changed it, or it's dirty. + pixelTransferStencil = gl::value::PixelTransferStencil::Default; + + // Read the stencil buffer + const auto viewportValue = viewport.getCurrentValue(); + auto image = readFramebuffer<AlphaImage, gfx::TexturePixelType::Stencil>(viewportValue.size, false); + + // Scale the Stencil buffer to cover the entire color space. + auto it = image.data.get(); + auto end = it + viewportValue.size.width * viewportValue.size.height; + const auto factor = 255.0f / *std::max_element(it, end); + for (; it != end; ++it) { + *it *= factor; + } + + pixelZoom = { 1, 1 }; + rasterPos = { -1, -1, 0, 1 }; + drawPixels(image); +#endif +} + +void Context::visualizeDepthBuffer(const float depthRangeSize) { + (void)depthRangeSize; +#if not MBGL_USE_GLES2 + setStencilMode(gfx::StencilMode::disabled()); + setDepthMode(gfx::DepthMode::disabled()); + setColorMode(gfx::ColorMode::unblended()); + program = 0; + + // Scales the values in the depth buffer so that they cover the entire grayscale range. This + // makes it easier to spot tiny differences. + const float base = 1.0f / (1.0f - depthRangeSize); + pixelTransferDepth = { base, 1.0f - base }; + + // Read the stencil buffer + auto viewportValue = viewport.getCurrentValue(); + auto image = readFramebuffer<AlphaImage, gfx::TexturePixelType::Depth>(viewportValue.size, false); + + pixelZoom = { 1, 1 }; + rasterPos = { -1, -1, 0, 1 }; + drawPixels(image); +#endif +} + +#endif + +void Context::clearStencilBuffer(const int32_t bits) { + MBGL_CHECK_ERROR(glClearStencil(bits)); + MBGL_CHECK_ERROR(glClear(GL_STENCIL_BUFFER_BIT)); +} + +} // namespace gl +} // namespace mbgl diff --git a/platform/gfx/gl/src/mbgl/gl/context.hpp b/platform/gfx/gl/src/mbgl/gl/context.hpp new file mode 100644 index 0000000000..70f12e5a8d --- /dev/null +++ b/platform/gfx/gl/src/mbgl/gl/context.hpp @@ -0,0 +1,235 @@ +#pragma once + +#include <mbgl/gfx/context.hpp> +#include <mbgl/gl/object.hpp> +#include <mbgl/gl/state.hpp> +#include <mbgl/gl/value.hpp> +#include <mbgl/gl/framebuffer.hpp> +#include <mbgl/gl/vertex_array.hpp> +#include <mbgl/gl/types.hpp> +#include <mbgl/gfx/texture.hpp> +#include <mbgl/gfx/draw_mode.hpp> +#include <mbgl/gfx/depth_mode.hpp> +#include <mbgl/gfx/stencil_mode.hpp> +#include <mbgl/gfx/color_mode.hpp> +#include <mbgl/platform/gl_functions.hpp> +#include <mbgl/util/noncopyable.hpp> + + +#include <functional> +#include <memory> +#include <vector> +#include <array> +#include <string> + +namespace mbgl { +namespace gl { + +constexpr size_t TextureMax = 64; +using ProcAddress = void (*)(); +class RendererBackend; + +namespace extension { +class VertexArray; +class Debugging; +} // namespace extension + +class Context final : public gfx::Context { +public: + Context(RendererBackend&); + ~Context() override; + Context(const Context&) = delete; + Context& operator=(const Context& other) = delete; + + std::unique_ptr<gfx::CommandEncoder> createCommandEncoder() override; + + void initializeExtensions(const std::function<gl::ProcAddress(const char*)>&); + + void enableDebugging(); + + UniqueShader createShader(ShaderType type, const std::initializer_list<const char*>& sources); + UniqueProgram createProgram(ShaderID vertexShader, ShaderID fragmentShader, const char* location0AttribName); + void verifyProgramLinkage(ProgramID); + void linkProgram(ProgramID); + UniqueTexture createUniqueTexture(); + + Framebuffer createFramebuffer(const gfx::Renderbuffer<gfx::RenderbufferPixelType::RGBA>&, + const gfx::Renderbuffer<gfx::RenderbufferPixelType::DepthStencil>&); + Framebuffer createFramebuffer(const gfx::Renderbuffer<gfx::RenderbufferPixelType::RGBA>&); + Framebuffer createFramebuffer(const gfx::Texture&, + const gfx::Renderbuffer<gfx::RenderbufferPixelType::DepthStencil>&); + Framebuffer createFramebuffer(const gfx::Texture&); + Framebuffer createFramebuffer(const gfx::Texture&, + const gfx::Renderbuffer<gfx::RenderbufferPixelType::Depth>&); + + template <typename Image, + gfx::TexturePixelType format = Image::channels == 4 ? gfx::TexturePixelType::RGBA + : gfx::TexturePixelType::Alpha> + Image readFramebuffer(const Size size, bool flip = true) { + static_assert(Image::channels == (format == gfx::TexturePixelType::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 ? gfx::TexturePixelType::RGBA : gfx::TexturePixelType::Alpha; + drawPixels(image.size, image.data.get(), format); + } +#endif // MBGL_USE_GLES2 + + void clear(optional<mbgl::Color> color, + optional<float> depth, + optional<int32_t> stencil); + + void setDepthMode(const gfx::DepthMode&); + void setStencilMode(const gfx::StencilMode&); + void setColorMode(const gfx::ColorMode&); + void setCullFaceMode(const gfx::CullFaceMode&); + + void draw(const gfx::DrawMode&, + std::size_t indexOffset, + std::size_t indexLength); + + // Actually remove the objects we marked as abandoned with the above methods. + // Only call this while the OpenGL context is exclusive to this thread. + void performCleanup() override; + + void reduceMemoryUsage() override; + + // Drain pools and remove abandoned objects, in preparation for destroying the store. + // Only call this while the OpenGL context is exclusive to this thread. + void reset(); + + bool empty() const { + return pooledTextures.empty() + && abandonedPrograms.empty() + && abandonedShaders.empty() + && abandonedBuffers.empty() + && abandonedTextures.empty() + && abandonedVertexArrays.empty() + && abandonedFramebuffers.empty(); + } + + void setDirtyState(); + + extension::Debugging* getDebuggingExtension() const { + return debugging.get(); + } + + extension::VertexArray* getVertexArrayExtension() const { + return vertexArray.get(); + } + + void setCleanupOnDestruction(bool cleanup) { + cleanupOnDestruction = cleanup; + } + +private: + RendererBackend& backend; + bool cleanupOnDestruction = true; + + std::unique_ptr<extension::Debugging> debugging; + std::unique_ptr<extension::VertexArray> vertexArray; + +public: + State<value::ActiveTextureUnit> activeTextureUnit; + State<value::BindFramebuffer> bindFramebuffer; + State<value::Viewport> viewport; + State<value::ScissorTest> scissorTest; + std::array<State<value::BindTexture>, 2> texture; + State<value::Program> program; + State<value::BindVertexBuffer> vertexBuffer; + + State<value::BindVertexArray, const Context&> bindVertexArray { *this }; + VertexArrayState globalVertexArrayState { UniqueVertexArray(0, { this }) }; + + State<value::PixelStorePack> pixelStorePack; + State<value::PixelStoreUnpack> pixelStoreUnpack; + +#if not MBGL_USE_GLES2 + State<value::PixelZoom> pixelZoom; + State<value::RasterPos> rasterPos; + 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; + State<value::StencilOp> stencilOp; + State<value::DepthRange> depthRange; + State<value::DepthMask> depthMask; + 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::LineWidth> lineWidth; + State<value::BindRenderbuffer> bindRenderbuffer; + State<value::CullFace> cullFace; + State<value::CullFaceSide> cullFaceSide; + State<value::CullFaceWinding> cullFaceWinding; +#if not MBGL_USE_GLES2 + State<value::PointSize> pointSize; +#endif // MBGL_USE_GLES2 + + std::unique_ptr<gfx::OffscreenTexture> createOffscreenTexture( + Size, gfx::TextureChannelDataType = gfx::TextureChannelDataType::UnsignedByte) override; + + std::unique_ptr<gfx::TextureResource> + createTextureResource(Size, gfx::TexturePixelType, gfx::TextureChannelDataType) override; + + std::unique_ptr<gfx::RenderbufferResource> createRenderbufferResource(gfx::RenderbufferPixelType, Size size) override; + + std::unique_ptr<gfx::DrawScopeResource> createDrawScopeResource() override; + + UniqueFramebuffer createFramebuffer(); + std::unique_ptr<uint8_t[]> readFramebuffer(Size, gfx::TexturePixelType, bool flip); +#if not MBGL_USE_GLES2 + void drawPixels(Size size, const void* data, gfx::TexturePixelType); +#endif // MBGL_USE_GLES2 + + VertexArray createVertexArray(); + bool supportsVertexArrays() const; + + friend detail::ProgramDeleter; + friend detail::ShaderDeleter; + friend detail::BufferDeleter; + friend detail::TextureDeleter; + friend detail::VertexArrayDeleter; + friend detail::FramebufferDeleter; + friend detail::RenderbufferDeleter; + + std::vector<TextureID> pooledTextures; + + std::vector<ProgramID> abandonedPrograms; + std::vector<ShaderID> abandonedShaders; + std::vector<BufferID> abandonedBuffers; + std::vector<TextureID> abandonedTextures; + std::vector<VertexArrayID> abandonedVertexArrays; + std::vector<FramebufferID> abandonedFramebuffers; + std::vector<RenderbufferID> abandonedRenderbuffers; + +public: + // For testing + bool disableVAOExtension = false; + +#if not defined(NDEBUG) +public: + void visualizeStencilBuffer() override; + void visualizeDepthBuffer(float depthRangeSize) override; +#endif + + void clearStencilBuffer(int32_t) override; +}; + +} // namespace gl +} // namespace mbgl diff --git a/platform/gfx/gl/src/mbgl/gl/debugging_extension.cpp b/platform/gfx/gl/src/mbgl/gl/debugging_extension.cpp new file mode 100644 index 0000000000..5afa4f50fc --- /dev/null +++ b/platform/gfx/gl/src/mbgl/gl/debugging_extension.cpp @@ -0,0 +1,55 @@ +#include <mbgl/gl/debugging_extension.hpp> +#include <mbgl/util/logging.hpp> + +namespace mbgl { +namespace gl { +namespace extension { + +void Debugging::DebugCallback(GLenum source, + GLenum type, + GLuint id, + GLenum severity, + GLsizei /* length */, + const GLchar* message, + const void* /* userParam */) { + std::string strSource; + switch (source) { + case GL_DEBUG_SOURCE_API: strSource = "DEBUG_SOURCE_API"; break; + case GL_DEBUG_SOURCE_WINDOW_SYSTEM: strSource = "DEBUG_SOURCE_WINDOW_SYSTEM"; break; + case GL_DEBUG_SOURCE_SHADER_COMPILER: strSource = "DEBUG_SOURCE_SHADER_COMPILER"; break; + case GL_DEBUG_SOURCE_THIRD_PARTY: strSource = "DEBUG_SOURCE_THIRD_PARTY"; break; + case GL_DEBUG_SOURCE_APPLICATION: strSource = "DEBUG_SOURCE_APPLICATION"; break; + case GL_DEBUG_SOURCE_OTHER: strSource = "DEBUG_SOURCE_OTHER"; break; + default: strSource = "(unknown)"; break; + } + + std::string strType; + switch (type) { + case GL_DEBUG_TYPE_ERROR: strType = "DEBUG_TYPE_ERROR"; break; + case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: strType = "DEBUG_TYPE_DEPRECATED_BEHAVIOR"; break; + case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: strType = "DEBUG_TYPE_UNDEFINED_BEHAVIOR"; break; + case GL_DEBUG_TYPE_PERFORMANCE: strType = "DEBUG_TYPE_PERFORMANCE"; break; + case GL_DEBUG_TYPE_PORTABILITY: strType = "DEBUG_TYPE_PORTABILITY"; break; + case GL_DEBUG_TYPE_OTHER: strType = "DEBUG_TYPE_OTHER"; break; + case GL_DEBUG_TYPE_MARKER: strType = "DEBUG_TYPE_MARKER"; break; + case GL_DEBUG_TYPE_PUSH_GROUP: strType = "DEBUG_TYPE_OTHER"; break; + case GL_DEBUG_TYPE_POP_GROUP: strType = "DEBUG_TYPE_POP_GROUP"; break; + default: strSource = "(unknown)"; break; + } + + std::string strSeverity; + mbgl::EventSeverity evtSeverity; + switch (severity) { + case GL_DEBUG_SEVERITY_HIGH: strSeverity = "DEBUG_SEVERITY_HIGH"; evtSeverity = mbgl::EventSeverity::Error; break; + case GL_DEBUG_SEVERITY_MEDIUM: strSeverity = "DEBUG_SEVERITY_MEDIUM"; evtSeverity = mbgl::EventSeverity::Warning; break; + case GL_DEBUG_SEVERITY_LOW: strSeverity = "DEBUG_SEVERITY_LOW"; evtSeverity = mbgl::EventSeverity::Info; break; + case GL_DEBUG_SEVERITY_NOTIFICATION: strSeverity = "DEBUG_SEVERITY_NOTIFICATION"; evtSeverity = mbgl::EventSeverity::Debug; break; + default: strSource = "(unknown)"; evtSeverity = mbgl::EventSeverity::Debug; break; + } + + mbgl::Log::Record(evtSeverity, mbgl::Event::OpenGL, "GL_%s GL_%s %u GL_%s - %s", strSource.c_str(), strType.c_str(), id, strSeverity.c_str(), message); +} + +} // namespace extension +} // namespace gl +} // namespace mbgl diff --git a/platform/gfx/gl/src/mbgl/gl/debugging_extension.hpp b/platform/gfx/gl/src/mbgl/gl/debugging_extension.hpp new file mode 100644 index 0000000000..0fa5a7b424 --- /dev/null +++ b/platform/gfx/gl/src/mbgl/gl/debugging_extension.hpp @@ -0,0 +1,122 @@ +#pragma once + +#include <mbgl/gl/extension.hpp> +#include <mbgl/platform/gl_functions.hpp> + +#define GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242 +#define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH 0x8243 +#define GL_DEBUG_CALLBACK_FUNCTION 0x8244 +#define GL_DEBUG_CALLBACK_USER_PARAM 0x8245 +#define GL_DEBUG_SOURCE_API 0x8246 +#define GL_DEBUG_SOURCE_WINDOW_SYSTEM 0x8247 +#define GL_DEBUG_SOURCE_SHADER_COMPILER 0x8248 +#define GL_DEBUG_SOURCE_THIRD_PARTY 0x8249 +#define GL_DEBUG_SOURCE_APPLICATION 0x824A +#define GL_DEBUG_SOURCE_OTHER 0x824B +#define GL_DEBUG_TYPE_ERROR 0x824C +#define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR 0x824D +#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR 0x824E +#define GL_DEBUG_TYPE_PORTABILITY 0x824F +#define GL_DEBUG_TYPE_PERFORMANCE 0x8250 +#define GL_DEBUG_TYPE_OTHER 0x8251 +#define GL_MAX_DEBUG_MESSAGE_LENGTH 0x9143 +#define GL_MAX_DEBUG_LOGGED_MESSAGES 0x9144 +#define GL_DEBUG_LOGGED_MESSAGES 0x9145 +#define GL_DEBUG_SEVERITY_HIGH 0x9146 +#define GL_DEBUG_SEVERITY_MEDIUM 0x9147 +#define GL_DEBUG_SEVERITY_LOW 0x9148 +#define GL_DEBUG_TYPE_MARKER 0x8268 +#define GL_DEBUG_TYPE_PUSH_GROUP 0x8269 +#define GL_DEBUG_TYPE_POP_GROUP 0x826A +#define GL_DEBUG_SEVERITY_NOTIFICATION 0x826B +#define GL_MAX_DEBUG_GROUP_STACK_DEPTH 0x826C +#define GL_DEBUG_GROUP_STACK_DEPTH 0x826D +#define GL_BUFFER 0x82E0 +#define GL_SHADER 0x82E1 +#define GL_PROGRAM 0x82E2 +#define GL_QUERY 0x82E3 +#define GL_PROGRAM_PIPELINE 0x82E4 +#define GL_SAMPLER 0x82E6 +#define GL_MAX_LABEL_LENGTH 0x82E8 +#define GL_DEBUG_OUTPUT 0x92E0 +#define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002 +#define GL_DISPLAY_LIST 0x82E7 +#define GL_VERTEX_ARRAY 0x8074 +#define GL_TRANSFORM_FEEDBACK 0x8E22 +#define GL_TEXTURE 0x1702 +#define GL_RENDERBUFFER 0x8D41 +#define GL_FRAMEBUFFER 0x8D40 + +namespace mbgl { +namespace gl { +namespace extension { + +using namespace platform; + +class Debugging { +public: + using Callback = void (*)(GLenum source, + GLenum type, + GLuint id, + GLenum severity, + GLsizei length, + const GLchar* message, + const void* userParam); + + static void DebugCallback(GLenum source, + GLenum type, + GLuint id, + GLenum severity, + GLsizei /* length */, + const GLchar* message, + const void* /* userParam */); + + template <typename Fn> + Debugging(const Fn& loadExtension) + : +#ifndef NDEBUG + pushDebugGroup( + loadExtension({ { "GL_KHR_debug", "glPushDebugGroup" } })), + popDebugGroup( + loadExtension({ { "GL_KHR_debug", "glPopDebugGroup" } })), + pushGroupMarkerEXT( + loadExtension({ { "GL_EXT_debug_marker", "glPushGroupMarkerEXT" } })), + popGroupMarkerEXT( + loadExtension({ { "GL_EXT_debug_marker", "glPopGroupMarkerEXT" } })), +#endif + debugMessageControl( + loadExtension({ { "GL_KHR_debug", "glDebugMessageControl" }, + { "GL_ARB_debug_output", "glDebugMessageControlARB" } })), + debugMessageCallback( + loadExtension({ { "GL_KHR_debug", "glDebugMessageCallback" }, + { "GL_ARB_debug_output", "glDebugMessageCallbackARB" } })) { + } + +#ifndef NDEBUG + const ExtensionFunction<void(GLenum source, + GLuint id, + GLsizei length, + const GLchar* message)> pushDebugGroup; + + const ExtensionFunction<void()> popDebugGroup; + + const ExtensionFunction<void(GLsizei length, + const GLchar* marker)> pushGroupMarkerEXT; + + const ExtensionFunction<void()> popGroupMarkerEXT; +#endif + + const ExtensionFunction<void(GLenum source, + GLenum type, + GLenum severity, + GLsizei count, + const GLuint* ids, + GLboolean enabled)> debugMessageControl; + + const ExtensionFunction<void(Callback callback, + const void* userParam)> debugMessageCallback; +}; + +} // namespace extension +} // namespace gl +} // namespace mbgl diff --git a/platform/gfx/gl/src/mbgl/gl/defines.hpp b/platform/gfx/gl/src/mbgl/gl/defines.hpp new file mode 100644 index 0000000000..75325dfb75 --- /dev/null +++ b/platform/gfx/gl/src/mbgl/gl/defines.hpp @@ -0,0 +1,179 @@ +#pragma once + +#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A +#define GL_ACTIVE_ATTRIBUTES 0x8B89 +#define GL_ACTIVE_TEXTURE 0x84E0 +#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87 +#define GL_ACTIVE_UNIFORMS 0x8B86 +#define GL_ALPHA 0x1906 +#define GL_ALWAYS 0x0207 +#define GL_ARRAY_BUFFER 0x8892 +#define GL_ARRAY_BUFFER_BINDING 0x8894 +#define GL_BACK 0x0405 +#define GL_BLEND 0x0BE2 +#define GL_BLEND_COLOR 0x8005 +#define GL_BLEND_DST_ALPHA 0x80CA +#define GL_BLEND_EQUATION_RGB 0x8009 +#define GL_BLEND_SRC_ALPHA 0x80CB +#define GL_BOOL 0x8B56 +#define GL_BOOL_VEC2 0x8B57 +#define GL_BOOL_VEC3 0x8B58 +#define GL_BOOL_VEC4 0x8B59 +#define GL_BYTE 0x1400 +#define GL_CCW 0x0901 +#define GL_CLAMP_TO_EDGE 0x812F +#define GL_COLOR_ATTACHMENT0 0x8CE0 +#define GL_COLOR_BUFFER_BIT 0x00004000 +#define GL_COLOR_CLEAR_VALUE 0x0C22 +#define GL_COLOR_WRITEMASK 0x0C23 +#define GL_COMPILE_STATUS 0x8B81 +#define GL_CONSTANT_ALPHA 0x8003 +#define GL_CONSTANT_COLOR 0x8001 +#define GL_CULL_FACE 0x0B44 +#define GL_CULL_FACE_MODE 0x0B45 +#define GL_CURRENT_PROGRAM 0x8B8D +#define GL_CW 0x0900 +#define GL_DECR 0x1E03 +#define GL_DECR_WRAP 0x8508 +#define GL_DEPTH24_STENCIL8_OES 0x88F0 +#define GL_DEPTH_ATTACHMENT 0x8D00 +#define GL_DEPTH_BUFFER_BIT 0x00000100 +#define GL_DEPTH_CLEAR_VALUE 0x0B73 +#define GL_DEPTH_COMPONENT 0x1902 +#define GL_DEPTH_COMPONENT16 0x81A5 +#define GL_DEPTH_FUNC 0x0B74 +#define GL_DEPTH_RANGE 0x0B70 +#define GL_DEPTH_TEST 0x0B71 +#define GL_DEPTH_WRITEMASK 0x0B72 +#define GL_DONT_CARE 0x1100 +#define GL_DST_ALPHA 0x0304 +#define GL_DST_COLOR 0x0306 +#define GL_DYNAMIC_DRAW 0x88E8 +#define GL_ELEMENT_ARRAY_BUFFER 0x8893 +#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895 +#define GL_EQUAL 0x0202 +#define GL_EXTENSIONS 0x1F03 +#define GL_FALSE 0 +#define GL_FLOAT 0x1406 +#define GL_FLOAT_MAT2 0x8B5A +#define GL_FLOAT_MAT3 0x8B5B +#define GL_FLOAT_MAT4 0x8B5C +#define GL_FLOAT_VEC2 0x8B50 +#define GL_FLOAT_VEC3 0x8B51 +#define GL_FLOAT_VEC4 0x8B52 +#define GL_FRAGMENT_SHADER 0x8B30 +#define GL_FRAMEBUFFER 0x8D40 +#define GL_FRAMEBUFFER_BINDING 0x8CA6 +#define GL_FRAMEBUFFER_COMPLETE 0x8CD5 +#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6 +#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7 +#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD +#define GL_FRONT 0x0404 +#define GL_FRONT_AND_BACK 0x0408 +#define GL_FRONT_FACE 0x0B46 +#define GL_FUNC_ADD 0x8006 +#define GL_FUNC_REVERSE_SUBTRACT 0x800B +#define GL_FUNC_SUBTRACT 0x800A +#define GL_GEQUAL 0x0206 +#define GL_GREATER 0x0204 +#define GL_INCR 0x1E02 +#define GL_INCR_WRAP 0x8507 +#define GL_INFO_LOG_LENGTH 0x8B84 +#define GL_INT 0x1404 +#define GL_INT_VEC2 0x8B53 +#define GL_INT_VEC3 0x8B54 +#define GL_INT_VEC4 0x8B55 +#define GL_INVALID_ENUM 0x0500 +#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506 +#define GL_INVALID_OPERATION 0x0502 +#define GL_INVALID_VALUE 0x0501 +#define GL_INVERT 0x150A +#define GL_KEEP 0x1E00 +#define GL_LEQUAL 0x0203 +#define GL_LESS 0x0201 +#define GL_LINEAR 0x2601 +#define GL_LINEAR_MIPMAP_NEAREST 0x2701 +#define GL_LINE_LOOP 0x0002 +#define GL_LINES 0x0001 +#define GL_LINE_STRIP 0x0003 +#define GL_LINE_WIDTH 0x0B21 +#define GL_LINK_STATUS 0x8B82 +#define GL_LUMINANCE 0x1909 +#define GL_MAX_VERTEX_ATTRIBS 0x8869 +#define GL_NEAREST 0x2600 +#define GL_NEAREST_MIPMAP_NEAREST 0x2700 +#define GL_NEVER 0x0200 +#define GL_NO_ERROR 0 +#define GL_NOTEQUAL 0x0205 +#define GL_ONE 1 +#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004 +#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002 +#define GL_ONE_MINUS_DST_ALPHA 0x0305 +#define GL_ONE_MINUS_DST_COLOR 0x0307 +#define GL_ONE_MINUS_SRC_ALPHA 0x0303 +#define GL_ONE_MINUS_SRC_COLOR 0x0301 +#define GL_OUT_OF_MEMORY 0x0505 +#define GL_PACK_ALIGNMENT 0x0D05 +#define GL_POINTS 0x0000 +#define GL_RENDERBUFFER 0x8D41 +#define GL_RENDERBUFFER_BINDING 0x8CA7 +#define GL_RENDERER 0x1F01 +#define GL_REPEAT 0x2901 +#define GL_REPLACE 0x1E01 +#define GL_RGBA 0x1908 +#define GL_RGBA8_OES 0x8058 +#define GL_SAMPLER_2D 0x8B5E +#define GL_SAMPLER_CUBE 0x8B60 +#define GL_SCISSOR_TEST 0x0C11 +#define GL_SHORT 0x1402 +#define GL_SRC_ALPHA 0x0302 +#define GL_SRC_ALPHA_SATURATE 0x0308 +#define GL_SRC_COLOR 0x0300 +#define GL_STATIC_DRAW 0x88E4 +#define GL_STENCIL_ATTACHMENT 0x8D20 +#define GL_STENCIL_BUFFER_BIT 0x00000400 +#define GL_STENCIL_CLEAR_VALUE 0x0B91 +#define GL_STENCIL_FAIL 0x0B94 +#define GL_STENCIL_FUNC 0x0B92 +#define GL_STENCIL_INDEX 0x1901 +#define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95 +#define GL_STENCIL_PASS_DEPTH_PASS 0x0B96 +#define GL_STENCIL_REF 0x0B97 +#define GL_STENCIL_TEST 0x0B90 +#define GL_STENCIL_VALUE_MASK 0x0B93 +#define GL_STENCIL_WRITEMASK 0x0B98 +#define GL_STREAM_DRAW 0x88E0 +#define GL_TEXTURE0 0x84C0 +#define GL_TEXTURE_2D 0x0DE1 +#define GL_TEXTURE_BINDING_2D 0x8069 +#define GL_TEXTURE_MAG_FILTER 0x2800 +#define GL_TEXTURE_MIN_FILTER 0x2801 +#define GL_TEXTURE_WRAP_S 0x2802 +#define GL_TEXTURE_WRAP_T 0x2803 +#define GL_TRIANGLE_FAN 0x0006 +#define GL_TRIANGLES 0x0004 +#define GL_TRIANGLE_STRIP 0x0005 +#define GL_TRUE 1 +#define GL_UNPACK_ALIGNMENT 0x0CF5 +#define GL_UNSIGNED_BYTE 0x1401 +#define GL_UNSIGNED_INT 0x1405 +#define GL_UNSIGNED_SHORT 0x1403 +#define GL_VERTEX_SHADER 0x8B31 +#define GL_VIEWPORT 0x0BA2 +#define GL_ZERO 0 + +#ifdef MBGL_USE_GLES2 +#define GL_HALF_FLOAT 0x8D61 +#else +#define GL_CURRENT_RASTER_POSITION 0x0B07 +#define GL_DEPTH24_STENCIL8 0x88F0 +#define GL_DEPTH_BIAS 0x0D1F +#define GL_DEPTH_SCALE 0x0D1E +#define GL_HALF_FLOAT 0x140B +#define GL_INDEX_OFFSET 0x0D13 +#define GL_INDEX_SHIFT 0x0D12 +#define GL_POINT_SIZE 0x0B11 +#define GL_RGBA8 0x8058 +#define GL_ZOOM_X 0x0D16 +#define GL_ZOOM_Y 0x0D17 +#endif
\ No newline at end of file diff --git a/platform/gfx/gl/src/mbgl/gl/draw_scope_resource.hpp b/platform/gfx/gl/src/mbgl/gl/draw_scope_resource.hpp new file mode 100644 index 0000000000..4c446cd4fe --- /dev/null +++ b/platform/gfx/gl/src/mbgl/gl/draw_scope_resource.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include <mbgl/gfx/draw_scope.hpp> +#include <mbgl/gl/vertex_array.hpp> + +namespace mbgl { +namespace gl { + +class DrawScopeResource : public gfx::DrawScopeResource { +public: + DrawScopeResource(VertexArray&& vertexArray_) : vertexArray(std::move(vertexArray_)) { + } + + VertexArray vertexArray; +}; + +} // namespace gl +} // namespace mbgl diff --git a/platform/gfx/gl/src/mbgl/gl/enum.cpp b/platform/gfx/gl/src/mbgl/gl/enum.cpp new file mode 100644 index 0000000000..5f8cd77ad6 --- /dev/null +++ b/platform/gfx/gl/src/mbgl/gl/enum.cpp @@ -0,0 +1,319 @@ +#include <mbgl/gl/enum.hpp> +#include <mbgl/gfx/types.hpp> +#include <mbgl/gl/defines.hpp> + +namespace mbgl { +namespace gl { + +template <> +platform::GLenum Enum<gfx::DrawModeType>::to(const gfx::DrawModeType value) { + switch (value) { + case gfx::DrawModeType::Points: return GL_POINTS; + case gfx::DrawModeType::Lines: return GL_LINES; + case gfx::DrawModeType::LineLoop: return GL_LINE_LOOP; + case gfx::DrawModeType::LineStrip: return GL_LINE_STRIP; + case gfx::DrawModeType::Triangles: return GL_TRIANGLES; + case gfx::DrawModeType::TriangleStrip: return GL_TRIANGLE_STRIP; + case gfx::DrawModeType::TriangleFan: return GL_TRIANGLE_FAN; + } + return GL_INVALID_ENUM; +} + +template <> +gfx::ColorBlendEquationType Enum<gfx::ColorBlendEquationType>::from(const platform::GLint value) { + switch (value) { + case GL_FUNC_ADD: return gfx::ColorBlendEquationType::Add; + case GL_FUNC_SUBTRACT: return gfx::ColorBlendEquationType::Subtract; + case GL_FUNC_REVERSE_SUBTRACT: return gfx::ColorBlendEquationType::ReverseSubtract; + } + return {}; +} + +template <> +platform::GLenum Enum<gfx::ColorBlendEquationType>::to(const gfx::ColorBlendEquationType value) { + switch (value) { + case gfx::ColorBlendEquationType::Add: return GL_FUNC_ADD; + case gfx::ColorBlendEquationType::Subtract: return GL_FUNC_SUBTRACT; + case gfx::ColorBlendEquationType::ReverseSubtract: return GL_FUNC_REVERSE_SUBTRACT; + } + return GL_INVALID_ENUM; +} + +template <> +gfx::ColorBlendFactorType Enum<gfx::ColorBlendFactorType>::from(const platform::GLint value) { + switch (value) { + case GL_ZERO: return gfx::ColorBlendFactorType::Zero; + case GL_ONE: return gfx::ColorBlendFactorType::One; + case GL_SRC_COLOR: return gfx::ColorBlendFactorType::SrcColor; + case GL_ONE_MINUS_SRC_COLOR: return gfx::ColorBlendFactorType::OneMinusSrcColor; + case GL_DST_COLOR: return gfx::ColorBlendFactorType::DstColor; + case GL_ONE_MINUS_DST_COLOR: return gfx::ColorBlendFactorType::OneMinusDstColor; + case GL_SRC_ALPHA: return gfx::ColorBlendFactorType::SrcAlpha; + case GL_ONE_MINUS_SRC_ALPHA: return gfx::ColorBlendFactorType::OneMinusSrcAlpha; + case GL_DST_ALPHA: return gfx::ColorBlendFactorType::DstAlpha; + case GL_ONE_MINUS_DST_ALPHA: return gfx::ColorBlendFactorType::OneMinusDstAlpha; + case GL_CONSTANT_COLOR: return gfx::ColorBlendFactorType::ConstantColor; + case GL_ONE_MINUS_CONSTANT_COLOR: return gfx::ColorBlendFactorType::OneMinusConstantColor; + case GL_CONSTANT_ALPHA: return gfx::ColorBlendFactorType::ConstantAlpha; + case GL_ONE_MINUS_CONSTANT_ALPHA: return gfx::ColorBlendFactorType::OneMinusConstantAlpha; + case GL_SRC_ALPHA_SATURATE: return gfx::ColorBlendFactorType::SrcAlphaSaturate; + } + return {}; +} + +template <> +platform::GLenum Enum<gfx::ColorBlendFactorType>::to(const gfx::ColorBlendFactorType value) { + switch (value) { + case gfx::ColorBlendFactorType::Zero: return GL_ZERO; + case gfx::ColorBlendFactorType::One: return GL_ONE; + case gfx::ColorBlendFactorType::SrcColor: return GL_SRC_COLOR; + case gfx::ColorBlendFactorType::OneMinusSrcColor: return GL_ONE_MINUS_SRC_COLOR; + case gfx::ColorBlendFactorType::DstColor: return GL_DST_COLOR; + case gfx::ColorBlendFactorType::OneMinusDstColor: return GL_ONE_MINUS_DST_COLOR; + case gfx::ColorBlendFactorType::SrcAlpha: return GL_SRC_ALPHA; + case gfx::ColorBlendFactorType::OneMinusSrcAlpha: return GL_ONE_MINUS_SRC_ALPHA; + case gfx::ColorBlendFactorType::DstAlpha: return GL_DST_ALPHA; + case gfx::ColorBlendFactorType::OneMinusDstAlpha: return GL_ONE_MINUS_DST_ALPHA; + case gfx::ColorBlendFactorType::ConstantColor: return GL_CONSTANT_COLOR; + case gfx::ColorBlendFactorType::OneMinusConstantColor: return GL_ONE_MINUS_CONSTANT_COLOR; + case gfx::ColorBlendFactorType::ConstantAlpha: return GL_CONSTANT_ALPHA; + case gfx::ColorBlendFactorType::OneMinusConstantAlpha: return GL_ONE_MINUS_CONSTANT_ALPHA; + case gfx::ColorBlendFactorType::SrcAlphaSaturate: return GL_SRC_ALPHA_SATURATE; + } + return GL_INVALID_ENUM; +} + +template <> +gfx::DepthFunctionType Enum<gfx::DepthFunctionType>::from(const platform::GLint value) { + switch (value) { + case GL_NEVER: return gfx::DepthFunctionType::Never; + case GL_LESS: return gfx::DepthFunctionType::Less; + case GL_EQUAL: return gfx::DepthFunctionType::Equal; + case GL_LEQUAL: return gfx::DepthFunctionType::LessEqual; + case GL_GREATER: return gfx::DepthFunctionType::Greater; + case GL_NOTEQUAL: return gfx::DepthFunctionType::NotEqual; + case GL_GEQUAL: return gfx::DepthFunctionType::GreaterEqual; + case GL_ALWAYS: return gfx::DepthFunctionType::Always; + } + return {}; +} + +template <> +platform::GLenum Enum<gfx::DepthFunctionType>::to(const gfx::DepthFunctionType value) { + switch (value) { + case gfx::DepthFunctionType::Never: return GL_NEVER; + case gfx::DepthFunctionType::Less: return GL_LESS; + case gfx::DepthFunctionType::Equal: return GL_EQUAL; + case gfx::DepthFunctionType::LessEqual: return GL_LEQUAL; + case gfx::DepthFunctionType::Greater: return GL_GREATER; + case gfx::DepthFunctionType::NotEqual: return GL_NOTEQUAL; + case gfx::DepthFunctionType::GreaterEqual: return GL_GEQUAL; + case gfx::DepthFunctionType::Always: return GL_ALWAYS; + } + return GL_INVALID_ENUM; +} + +template <> +gfx::DepthMaskType Enum<gfx::DepthMaskType>::from(const platform::GLboolean value) { + return value ? gfx::DepthMaskType::ReadWrite : gfx::DepthMaskType::ReadOnly; +} + +template <> +platform::GLboolean Enum<gfx::DepthMaskType>::to(const gfx::DepthMaskType value) { + return value == gfx::DepthMaskType::ReadWrite ? GL_TRUE : GL_FALSE; +} + +template <> +gfx::StencilFunctionType Enum<gfx::StencilFunctionType>::from(const platform::GLint value) { + switch (value) { + case GL_NEVER: return gfx::StencilFunctionType::Never; + case GL_LESS: return gfx::StencilFunctionType::Less; + case GL_EQUAL: return gfx::StencilFunctionType::Equal; + case GL_LEQUAL: return gfx::StencilFunctionType::LessEqual; + case GL_GREATER: return gfx::StencilFunctionType::Greater; + case GL_NOTEQUAL: return gfx::StencilFunctionType::NotEqual; + case GL_GEQUAL: return gfx::StencilFunctionType::GreaterEqual; + case GL_ALWAYS: return gfx::StencilFunctionType::Always; + } + return {}; +} + +template <> +platform::GLenum Enum<gfx::StencilFunctionType>::to(const gfx::StencilFunctionType value) { + switch (value) { + case gfx::StencilFunctionType::Never: return GL_NEVER; + case gfx::StencilFunctionType::Less: return GL_LESS; + case gfx::StencilFunctionType::Equal: return GL_EQUAL; + case gfx::StencilFunctionType::LessEqual: return GL_LEQUAL; + case gfx::StencilFunctionType::Greater: return GL_GREATER; + case gfx::StencilFunctionType::NotEqual: return GL_NOTEQUAL; + case gfx::StencilFunctionType::GreaterEqual: return GL_GEQUAL; + case gfx::StencilFunctionType::Always: return GL_ALWAYS; + } + return GL_INVALID_ENUM; +} + +template <> +gfx::StencilOpType Enum<gfx::StencilOpType>::from(const platform::GLint value) { + switch (value) { + case GL_KEEP: return gfx::StencilOpType::Keep; + case GL_ZERO: return gfx::StencilOpType::Zero; + case GL_REPLACE: return gfx::StencilOpType::Replace; + case GL_INCR: return gfx::StencilOpType::Increment; + case GL_INCR_WRAP: return gfx::StencilOpType::IncrementWrap; + case GL_DECR: return gfx::StencilOpType::Decrement; + case GL_DECR_WRAP: return gfx::StencilOpType::DecrementWrap; + case GL_INVERT: return gfx::StencilOpType::Invert; + } + return {}; +} + +template <> +platform::GLenum Enum<gfx::StencilOpType>::to(const gfx::StencilOpType value) { + switch (value) { + case gfx::StencilOpType::Keep: return GL_KEEP; + case gfx::StencilOpType::Zero: return GL_ZERO; + case gfx::StencilOpType::Replace: return GL_REPLACE; + case gfx::StencilOpType::Increment: return GL_INCR; + case gfx::StencilOpType::IncrementWrap: return GL_INCR_WRAP; + case gfx::StencilOpType::Decrement: return GL_DECR; + case gfx::StencilOpType::DecrementWrap: return GL_DECR_WRAP; + case gfx::StencilOpType::Invert: return GL_INVERT; + } + return GL_INVALID_ENUM; +} + +template <> +gfx::CullFaceSideType Enum<gfx::CullFaceSideType>::from(const platform::GLint value) { + switch (value) { + case GL_FRONT: return gfx::CullFaceSideType::Front; + case GL_BACK: return gfx::CullFaceSideType::Back; + case GL_FRONT_AND_BACK: return gfx::CullFaceSideType::FrontAndBack; + } + return {}; +} + +template <> +platform::GLenum Enum<gfx::CullFaceSideType>::to(const gfx::CullFaceSideType value) { + switch (value) { + case gfx::CullFaceSideType::Front: return GL_FRONT; + case gfx::CullFaceSideType::Back: return GL_BACK; + case gfx::CullFaceSideType::FrontAndBack: return GL_FRONT_AND_BACK; + } + return GL_INVALID_ENUM; +} + +template <> +gfx::CullFaceWindingType Enum<gfx::CullFaceWindingType>::from(const platform::GLint value) { + switch (value) { + case GL_CW: return gfx::CullFaceWindingType::Clockwise; + case GL_CCW: return gfx::CullFaceWindingType::CounterClockwise; + } + return {}; +} + +template <> +platform::GLenum Enum<gfx::CullFaceWindingType>::to(const gfx::CullFaceWindingType value) { + switch (value) { + case gfx::CullFaceWindingType::Clockwise: return GL_CW; + case gfx::CullFaceWindingType::CounterClockwise: return GL_CCW; + } + return GL_INVALID_ENUM; +} + +template <> +gfx::BufferUsageType Enum<gfx::BufferUsageType>::from(const platform::GLint value) { + switch (value) { + case GL_STREAM_DRAW: return gfx::BufferUsageType::StreamDraw; + case GL_STATIC_DRAW: return gfx::BufferUsageType::StaticDraw; + case GL_DYNAMIC_DRAW: return gfx::BufferUsageType::DynamicDraw; + } + return {}; +} + +template <> +platform::GLenum Enum<gfx::BufferUsageType>::to(const gfx::BufferUsageType value) { + switch (value) { + case gfx::BufferUsageType::StreamDraw: return GL_STREAM_DRAW; + case gfx::BufferUsageType::StaticDraw: return GL_STATIC_DRAW; + case gfx::BufferUsageType::DynamicDraw: return GL_DYNAMIC_DRAW; + } + return GL_INVALID_ENUM; +} + +template <> +gfx::TexturePixelType Enum<gfx::TexturePixelType>::from(const platform::GLint value) { + switch (value) { + case GL_RGBA: return gfx::TexturePixelType::RGBA; + case GL_ALPHA: return gfx::TexturePixelType::Alpha; + case GL_STENCIL_INDEX: return gfx::TexturePixelType::Stencil; + case GL_DEPTH_COMPONENT: return gfx::TexturePixelType::Depth; + case GL_LUMINANCE: return gfx::TexturePixelType::Luminance; + } + return {}; +} + +template <> +platform::GLenum Enum<gfx::TexturePixelType>::to(const gfx::TexturePixelType value) { + switch (value) { + case gfx::TexturePixelType::RGBA: return GL_RGBA; + case gfx::TexturePixelType::Alpha: return GL_ALPHA; + case gfx::TexturePixelType::Stencil: return GL_STENCIL_INDEX; + case gfx::TexturePixelType::Depth: return GL_DEPTH_COMPONENT; + case gfx::TexturePixelType::Luminance: return GL_LUMINANCE; + } + return GL_INVALID_ENUM; +} + +template <> +gfx::TextureChannelDataType Enum<gfx::TextureChannelDataType>::from(const platform::GLint value) { + switch (value) { + case GL_UNSIGNED_BYTE: return gfx::TextureChannelDataType::UnsignedByte; + case GL_HALF_FLOAT: return gfx::TextureChannelDataType::HalfFloat; + } + return {}; +} + +template <> +platform::GLenum Enum<gfx::TextureChannelDataType>::to(const gfx::TextureChannelDataType value) { + switch (value) { + case gfx::TextureChannelDataType::UnsignedByte: return GL_UNSIGNED_BYTE; + case gfx::TextureChannelDataType::HalfFloat: return GL_HALF_FLOAT; + } + return GL_INVALID_ENUM; +} + +template <> +gfx::RenderbufferPixelType Enum<gfx::RenderbufferPixelType>::from(const platform::GLint value) { + switch (value) { +#if not MBGL_USE_GLES2 + case GL_RGBA8: return gfx::RenderbufferPixelType::RGBA; + case GL_DEPTH_COMPONENT: return gfx::RenderbufferPixelType::Depth; + case GL_DEPTH24_STENCIL8: return gfx::RenderbufferPixelType::DepthStencil; +#else + case GL_RGBA8_OES: return gfx::RenderbufferPixelType::RGBA; + case GL_DEPTH_COMPONENT16: return gfx::RenderbufferPixelType::Depth; + case GL_DEPTH24_STENCIL8_OES: return gfx::RenderbufferPixelType::DepthStencil; +#endif + } + return {}; +} + +template <> +platform::GLenum Enum<gfx::RenderbufferPixelType>::to(const gfx::RenderbufferPixelType value) { + switch (value) { +#if not MBGL_USE_GLES2 + case gfx::RenderbufferPixelType::RGBA: return GL_RGBA8; + case gfx::RenderbufferPixelType::Depth: return GL_DEPTH_COMPONENT; + case gfx::RenderbufferPixelType::DepthStencil: return GL_DEPTH24_STENCIL8; +#else + case gfx::RenderbufferPixelType::RGBA: return GL_RGBA8_OES; + case gfx::RenderbufferPixelType::Depth: return GL_DEPTH_COMPONENT16; + case gfx::RenderbufferPixelType::DepthStencil: return GL_DEPTH24_STENCIL8_OES; +#endif + } + return GL_INVALID_ENUM; +} + +} // namespace gl +} // namespace mbgl diff --git a/platform/gfx/gl/src/mbgl/gl/enum.hpp b/platform/gfx/gl/src/mbgl/gl/enum.hpp new file mode 100644 index 0000000000..6aa29efdb1 --- /dev/null +++ b/platform/gfx/gl/src/mbgl/gl/enum.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include <mbgl/platform/gl_functions.hpp> + +#include <type_traits> + +namespace mbgl { +namespace gl { + +template <typename T> +class Enum { +public: + using InType = std::conditional_t<std::is_same<std::underlying_type_t<T>, bool>::value, platform::GLboolean, platform::GLint>; + using OutType = std::conditional_t<std::is_same<std::underlying_type_t<T>, bool>::value, platform::GLboolean, platform::GLenum>; + + static T from(const InType); + static OutType to(T); +}; + +} // namespace gl +} // namespace mbgl diff --git a/platform/gfx/gl/src/mbgl/gl/extension.hpp b/platform/gfx/gl/src/mbgl/gl/extension.hpp new file mode 100644 index 0000000000..8710314ef2 --- /dev/null +++ b/platform/gfx/gl/src/mbgl/gl/extension.hpp @@ -0,0 +1,34 @@ +#pragma once + +#include <initializer_list> +#include <utility> +#include <functional> + +namespace mbgl { +namespace gl { + +using ProcAddress = void (*)(); + +template <class> +class ExtensionFunction; + +template <class R, class... Args> +class ExtensionFunction<R(Args...)> { +public: + ExtensionFunction(const ProcAddress ptr_) : ptr(ptr_) { + } + + explicit operator bool() const { + return ptr; + } + + R operator()(Args... args) const { + return (*reinterpret_cast<R (*)(Args...)>(ptr))(std::forward<Args>(args)...); + } + +private: + const ProcAddress ptr; +}; + +} // namespace gl +} // namespace mbgl diff --git a/platform/gfx/gl/src/mbgl/gl/framebuffer.hpp b/platform/gfx/gl/src/mbgl/gl/framebuffer.hpp new file mode 100644 index 0000000000..91ed467b40 --- /dev/null +++ b/platform/gfx/gl/src/mbgl/gl/framebuffer.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include <mbgl/gl/object.hpp> +#include <mbgl/util/size.hpp> + +namespace mbgl { +namespace gl { + +class Framebuffer { +public: + Size size; + gl::UniqueFramebuffer framebuffer; +}; + +} // namespace gl +} // namespace mbgl diff --git a/platform/gfx/gl/src/mbgl/gl/index_buffer_resource.hpp b/platform/gfx/gl/src/mbgl/gl/index_buffer_resource.hpp new file mode 100644 index 0000000000..2da25fdb96 --- /dev/null +++ b/platform/gfx/gl/src/mbgl/gl/index_buffer_resource.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include <mbgl/gfx/index_buffer.hpp> +#include <mbgl/gl/object.hpp> + +namespace mbgl { +namespace gl { + +class IndexBufferResource : public gfx::IndexBufferResource { +public: + IndexBufferResource(UniqueBuffer&& buffer_) : buffer(std::move(buffer_)) { + } + + UniqueBuffer buffer; +}; + +} // namespace gl +} // namespace mbgl diff --git a/platform/gfx/gl/src/mbgl/gl/object.cpp b/platform/gfx/gl/src/mbgl/gl/object.cpp new file mode 100644 index 0000000000..ec2998a27d --- /dev/null +++ b/platform/gfx/gl/src/mbgl/gl/object.cpp @@ -0,0 +1,52 @@ +#include <mbgl/gl/object.hpp> +#include <mbgl/gl/context.hpp> + +#include <cassert> + +namespace mbgl { +namespace gl { +namespace detail { + +void ProgramDeleter::operator()(ProgramID id) const { + assert(context); + context->abandonedPrograms.push_back(id); +} + +void ShaderDeleter::operator()(ShaderID id) const { + assert(context); + context->abandonedShaders.push_back(id); +} + +void BufferDeleter::operator()(BufferID id) const { + context.abandonedBuffers.push_back(id); +} + +void TextureDeleter::operator()(TextureID id) const { + assert(context); + if (context->pooledTextures.size() >= TextureMax) { + context->abandonedTextures.push_back(id); + } else { + context->pooledTextures.push_back(id); + } +} + +void VertexArrayDeleter::operator()(VertexArrayID id) const { + assert(context); + if (id != 0) { + context->abandonedVertexArrays.push_back(id); + } +} + +void FramebufferDeleter::operator()(FramebufferID id) const { + assert(context); + context->abandonedFramebuffers.push_back(id); +} + +void RenderbufferDeleter::operator()(RenderbufferID id) const { + assert(context); + context->abandonedRenderbuffers.push_back(id); +} + +} // namespace detail +} // namespace gl +} // namespace mbgl diff --git a/platform/gfx/gl/src/mbgl/gl/object.hpp b/platform/gfx/gl/src/mbgl/gl/object.hpp new file mode 100644 index 0000000000..9598e0c59e --- /dev/null +++ b/platform/gfx/gl/src/mbgl/gl/object.hpp @@ -0,0 +1,60 @@ +#pragma once + +#include <mbgl/gl/types.hpp> + +#include <unique_resource.hpp> + +namespace mbgl { +namespace gl { + +class Context; + +namespace detail { + +struct ProgramDeleter { + Context* context; + void operator()(ProgramID) const; +}; + +struct ShaderDeleter { + Context* context; + void operator()(ShaderID) const; +}; + +struct BufferDeleter { + Context& context; + void operator()(BufferID) const; +}; + +struct TextureDeleter { + Context* context; + void operator()(TextureID) const; +}; + +struct VertexArrayDeleter { + Context* context; + void operator()(VertexArrayID) const; +}; + +struct FramebufferDeleter { + Context* context; + void operator()(FramebufferID) const; +}; + +struct RenderbufferDeleter { + Context* context; + void operator()(RenderbufferID) const; +}; + +} // namespace detail + +using UniqueProgram = std_experimental::unique_resource<ProgramID, detail::ProgramDeleter>; +using UniqueShader = std_experimental::unique_resource<ShaderID, detail::ShaderDeleter>; +using UniqueBuffer = std_experimental::unique_resource<BufferID, detail::BufferDeleter>; +using UniqueTexture = std_experimental::unique_resource<TextureID, detail::TextureDeleter>; +using UniqueVertexArray = std_experimental::unique_resource<VertexArrayID, detail::VertexArrayDeleter>; +using UniqueFramebuffer = std_experimental::unique_resource<FramebufferID, detail::FramebufferDeleter>; +using UniqueRenderbuffer = std_experimental::unique_resource<RenderbufferID, detail::RenderbufferDeleter>; + +} // namespace gl +} // namespace mbgl diff --git a/platform/gfx/gl/src/mbgl/gl/offscreen_texture.cpp b/platform/gfx/gl/src/mbgl/gl/offscreen_texture.cpp new file mode 100644 index 0000000000..92f80a87b4 --- /dev/null +++ b/platform/gfx/gl/src/mbgl/gl/offscreen_texture.cpp @@ -0,0 +1,75 @@ +#include <mbgl/gl/offscreen_texture.hpp> +#include <mbgl/gl/renderable_resource.hpp> +#include <mbgl/gl/context.hpp> +#include <mbgl/gl/framebuffer.hpp> + +namespace mbgl { +namespace gl { + +class OffscreenTextureResource final : public gl::RenderableResource { +public: + OffscreenTextureResource(gl::Context& context_, + const Size size_, + const gfx::TextureChannelDataType type_) + : context(context_), size(size_), type(type_) { + assert(!size.isEmpty()); + } + + void bind() override { + if (!framebuffer) { + assert(!texture); + texture = context.createTexture(size, gfx::TexturePixelType::RGBA, type); + framebuffer = context.createFramebuffer(*texture); + } else { + context.bindFramebuffer = framebuffer->framebuffer; + } + + context.activeTextureUnit = 0; + context.scissorTest = false; + context.viewport = { 0, 0, size }; + } + + PremultipliedImage readStillImage() { + assert(framebuffer); + context.bindFramebuffer = framebuffer->framebuffer; + return context.readFramebuffer<PremultipliedImage>(size); + } + + gfx::Texture& getTexture() { + assert(texture); + return *texture; + } + +private: + gl::Context& context; + const Size size; + optional<gfx::Texture> texture; + const gfx::TextureChannelDataType type; + optional<gl::Framebuffer> framebuffer; +}; + +OffscreenTexture::OffscreenTexture(gl::Context& context, + const Size size_, + const gfx::TextureChannelDataType type) + : gfx::OffscreenTexture(size, std::make_unique<OffscreenTextureResource>(context, size_, type)) { +} + +bool OffscreenTexture::isRenderable() { + try { + getResource<OffscreenTextureResource>().bind(); + return true; + } catch (const std::runtime_error& ex) { + return false; + } +} + +PremultipliedImage OffscreenTexture::readStillImage() { + return getResource<OffscreenTextureResource>().readStillImage(); +} + +gfx::Texture& OffscreenTexture::getTexture() { + return getResource<OffscreenTextureResource>().getTexture(); +} + +} // namespace gl +} // namespace mbgl diff --git a/platform/gfx/gl/src/mbgl/gl/offscreen_texture.hpp b/platform/gfx/gl/src/mbgl/gl/offscreen_texture.hpp new file mode 100644 index 0000000000..5f3863d3e9 --- /dev/null +++ b/platform/gfx/gl/src/mbgl/gl/offscreen_texture.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include <mbgl/gfx/offscreen_texture.hpp> +#include <mbgl/gfx/types.hpp> + +namespace mbgl { +namespace gl { + +class Context; + +class OffscreenTexture final : public gfx::OffscreenTexture { +public: + OffscreenTexture(gl::Context&, + Size size, + gfx::TextureChannelDataType type = gfx::TextureChannelDataType::UnsignedByte); + + bool isRenderable() override; + + PremultipliedImage readStillImage() override; + gfx::Texture& getTexture() override; +}; + +} // namespace gl +} // namespace mbgl diff --git a/platform/gfx/gl/src/mbgl/gl/program.hpp b/platform/gfx/gl/src/mbgl/gl/program.hpp new file mode 100644 index 0000000000..6cfe05bf54 --- /dev/null +++ b/platform/gfx/gl/src/mbgl/gl/program.hpp @@ -0,0 +1,141 @@ +#pragma once + +#include <mbgl/gfx/program.hpp> +#include <mbgl/gl/types.hpp> +#include <mbgl/gl/object.hpp> +#include <mbgl/gl/context.hpp> +#include <mbgl/gl/draw_scope_resource.hpp> +#include <mbgl/gfx/vertex_buffer.hpp> +#include <mbgl/gfx/index_buffer.hpp> +#include <mbgl/gfx/uniform.hpp> +#include <mbgl/gl/vertex_array.hpp> +#include <mbgl/gl/attribute.hpp> +#include <mbgl/gl/uniform.hpp> +#include <mbgl/gl/texture.hpp> +#include <mbgl/util/io.hpp> + +#include <mbgl/util/logging.hpp> +#include <mbgl/programs/program_parameters.hpp> +#include <mbgl/programs/gl/shader_source.hpp> +#include <mbgl/programs/gl/shaders.hpp> + +#include <string> + +namespace mbgl { +namespace gl { + +template <class Name> +class Program final : public gfx::Program<Name> { +public: + using AttributeList = typename Name::AttributeList; + using UniformList = typename Name::UniformList; + using TextureList = typename Name::TextureList; + + Program(ProgramParameters programParameters_) + : programParameters(std::move(programParameters_)) { + } + + const ProgramParameters programParameters; + + static constexpr const auto vertexOffset = programs::gl::ShaderSource<Name>::vertexOffset; + static constexpr const auto fragmentOffset = programs::gl::ShaderSource<Name>::fragmentOffset; + + class Instance { + public: + Instance(Context& context, + const std::initializer_list<const char*>& vertexSource, + const std::initializer_list<const char*>& fragmentSource) + : program(context.createProgram( + context.createShader(ShaderType::Vertex, vertexSource), + context.createShader(ShaderType::Fragment, fragmentSource), + attributeLocations.getFirstAttribName())) { + attributeLocations.queryLocations(program); + uniformStates.queryLocations(program); + // Texture units are specified via uniforms as well, so we need query their locations + textureStates.queryLocations(program); + } + + static std::unique_ptr<Instance> + createInstance(gl::Context& context, + const ProgramParameters& programParameters, + const std::string& additionalDefines) { + // Compile the shader + const std::initializer_list<const char*> vertexSource = { + programParameters.getDefines().c_str(), + additionalDefines.c_str(), + (programs::gl::shaderSource() + programs::gl::vertexPreludeOffset), + (programs::gl::shaderSource() + vertexOffset) + }; + const std::initializer_list<const char*> fragmentSource = { + programParameters.getDefines().c_str(), + additionalDefines.c_str(), + (programs::gl::shaderSource() + programs::gl::fragmentPreludeOffset), + (programs::gl::shaderSource() + fragmentOffset) + }; + auto result = std::make_unique<Instance>(context, vertexSource, fragmentSource); + + return std::move(result); + } + + UniqueProgram program; + gl::AttributeLocations<AttributeList> attributeLocations; + gl::UniformStates<UniformList> uniformStates; + gl::TextureStates<TextureList> textureStates; + }; + + void draw(gfx::Context& genericContext, + gfx::RenderPass&, + const gfx::DrawMode& drawMode, + const gfx::DepthMode& depthMode, + const gfx::StencilMode& stencilMode, + const gfx::ColorMode& colorMode, + const gfx::CullFaceMode& cullFaceMode, + const gfx::UniformValues<UniformList>& uniformValues, + gfx::DrawScope& drawScope, + const gfx::AttributeBindings<AttributeList>& attributeBindings, + const gfx::TextureBindings<TextureList>& textureBindings, + const gfx::IndexBuffer& indexBuffer, + std::size_t indexOffset, + std::size_t indexLength) override { + auto& context = static_cast<gl::Context&>(genericContext); + + context.setDepthMode(depthMode); + context.setStencilMode(stencilMode); + context.setColorMode(colorMode); + context.setCullFaceMode(cullFaceMode); + + const uint32_t key = gl::AttributeKey<AttributeList>::compute(attributeBindings); + auto it = instances.find(key); + if (it == instances.end()) { + it = instances + .emplace(key, + Instance::createInstance( + context, + programParameters, + gl::AttributeKey<AttributeList>::defines(attributeBindings))) + .first; + } + + auto& instance = *it->second; + context.program = instance.program; + + instance.uniformStates.bind(uniformValues); + + instance.textureStates.bind(context, textureBindings); + + auto& vertexArray = drawScope.getResource<gl::DrawScopeResource>().vertexArray; + vertexArray.bind(context, + indexBuffer, + instance.attributeLocations.toBindingArray(attributeBindings)); + + context.draw(drawMode, + indexOffset, + indexLength); + } + +private: + std::map<uint32_t, std::unique_ptr<Instance>> instances; +}; + +} // namespace gl +} // namespace mbgl diff --git a/platform/gfx/gl/src/mbgl/gl/render_pass.cpp b/platform/gfx/gl/src/mbgl/gl/render_pass.cpp new file mode 100644 index 0000000000..b327f7954f --- /dev/null +++ b/platform/gfx/gl/src/mbgl/gl/render_pass.cpp @@ -0,0 +1,28 @@ +#include <mbgl/gl/render_pass.hpp> +#include <mbgl/gl/command_encoder.hpp> +#include <mbgl/gl/renderable_resource.hpp> +#include <mbgl/gl/context.hpp> + +namespace mbgl { +namespace gl { + +RenderPass::RenderPass(gl::CommandEncoder& commandEncoder_, + const char* name, + const gfx::RenderPassDescriptor& descriptor) + : commandEncoder(commandEncoder_), debugGroup(commandEncoder.createDebugGroup(name)) { + descriptor.renderable.getResource<gl::RenderableResource>().bind(); + const auto clearDebugGroup(commandEncoder.createDebugGroup("clear")); + commandEncoder.context.clear(descriptor.clearColor, descriptor.clearDepth, + descriptor.clearStencil); +} + +void RenderPass::pushDebugGroup(const char* name) { + commandEncoder.pushDebugGroup(name); +} + +void RenderPass::popDebugGroup() { + commandEncoder.popDebugGroup(); +} + +} // namespace gl +} // namespace mbgl diff --git a/platform/gfx/gl/src/mbgl/gl/render_pass.hpp b/platform/gfx/gl/src/mbgl/gl/render_pass.hpp new file mode 100644 index 0000000000..85a56243a6 --- /dev/null +++ b/platform/gfx/gl/src/mbgl/gl/render_pass.hpp @@ -0,0 +1,31 @@ +#pragma once + +#include <mbgl/gfx/render_pass.hpp> + +namespace mbgl { +namespace gfx { + +class CommandEncoder; + +} // namespace gfx + +namespace gl { + +class CommandEncoder; +class Context; + +class RenderPass final : public gfx::RenderPass { +public: + RenderPass(gl::CommandEncoder&, const char* name, const gfx::RenderPassDescriptor&); + +private: + void pushDebugGroup(const char* name) override; + void popDebugGroup() override; + +private: + gl::CommandEncoder& commandEncoder; + const gfx::DebugGroup<gfx::CommandEncoder> debugGroup; +}; + +} // namespace gl +} // namespace mbgl diff --git a/platform/gfx/gl/src/mbgl/gl/renderbuffer_resource.hpp b/platform/gfx/gl/src/mbgl/gl/renderbuffer_resource.hpp new file mode 100644 index 0000000000..52865b42f7 --- /dev/null +++ b/platform/gfx/gl/src/mbgl/gl/renderbuffer_resource.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include <mbgl/gfx/renderbuffer.hpp> +#include <mbgl/gl/object.hpp> + +namespace mbgl { +namespace gl { + +class RenderbufferResource final : public gfx::RenderbufferResource { +public: + explicit RenderbufferResource(UniqueRenderbuffer renderbuffer_) + : renderbuffer(std::move(renderbuffer_)) { + } + + UniqueRenderbuffer renderbuffer; +}; + +} // namespace gl +} // namespace mbgl diff --git a/platform/gfx/gl/src/mbgl/gl/renderer_backend.cpp b/platform/gfx/gl/src/mbgl/gl/renderer_backend.cpp new file mode 100644 index 0000000000..fe0ca4b5b2 --- /dev/null +++ b/platform/gfx/gl/src/mbgl/gl/renderer_backend.cpp @@ -0,0 +1,69 @@ +#include <mbgl/gl/renderer_backend.hpp> +#include <mbgl/gfx/backend_scope.hpp> +#include <mbgl/gl/context.hpp> +#include <mbgl/gl/extension.hpp> + +#include <cassert> + +namespace mbgl { +namespace gl { + +RendererBackend::RendererBackend(const gfx::ContextMode contextMode_) + : gfx::RendererBackend(contextMode_) { +} + +std::unique_ptr<gfx::Context> RendererBackend::createContext() { + auto result = std::make_unique<gl::Context>(*this); + result->enableDebugging(); + result->initializeExtensions( + std::bind(&RendererBackend::getExtensionFunctionPointer, this, std::placeholders::_1)); + // Needs move to placate GCC 4.9 + return std::move(result); +} + +PremultipliedImage RendererBackend::readFramebuffer(const Size& size) { + return getContext<gl::Context>().readFramebuffer<PremultipliedImage>(size); +} + +void RendererBackend::assumeFramebufferBinding(const gl::FramebufferID fbo) { + getContext<gl::Context>().bindFramebuffer.setCurrentValue(fbo); + if (fbo != ImplicitFramebufferBinding) { + assert(gl::value::BindFramebuffer::Get() == getContext<gl::Context>().bindFramebuffer.getCurrentValue()); + } +} + +void RendererBackend::assumeViewport(int32_t x, int32_t y, const Size& size) { + getContext<gl::Context>().viewport.setCurrentValue({ x, y, size }); + assert(gl::value::Viewport::Get() == getContext<gl::Context>().viewport.getCurrentValue()); +} + +void RendererBackend::assumeScissorTest(bool enabled) { + getContext<gl::Context>().scissorTest.setCurrentValue(enabled); + assert(gl::value::ScissorTest::Get() == getContext<gl::Context>().scissorTest.getCurrentValue()); +} + +bool RendererBackend::implicitFramebufferBound() { + return getContext<gl::Context>().bindFramebuffer.getCurrentValue() == ImplicitFramebufferBinding; +} + +void RendererBackend::setFramebufferBinding(const gl::FramebufferID fbo) { + getContext<gl::Context>().bindFramebuffer = fbo; + if (fbo != ImplicitFramebufferBinding) { + assert(gl::value::BindFramebuffer::Get() == getContext<gl::Context>().bindFramebuffer.getCurrentValue()); + } +} + +void RendererBackend::setViewport(int32_t x, int32_t y, const Size& size) { + getContext<gl::Context>().viewport = { x, y, size }; + assert(gl::value::Viewport::Get() == getContext<gl::Context>().viewport.getCurrentValue()); +} + +void RendererBackend::setScissorTest(bool enabled) { + getContext<gl::Context>().scissorTest = enabled; + assert(gl::value::ScissorTest::Get() == getContext<gl::Context>().scissorTest.getCurrentValue()); +} + +RendererBackend::~RendererBackend() = default; + +} // namespace gl +} // namespace mbgl diff --git a/platform/gfx/gl/src/mbgl/gl/state.hpp b/platform/gfx/gl/src/mbgl/gl/state.hpp new file mode 100644 index 0000000000..17503cc043 --- /dev/null +++ b/platform/gfx/gl/src/mbgl/gl/state.hpp @@ -0,0 +1,70 @@ +#pragma once + +#include <tuple> + +namespace mbgl { +namespace gl { + +// Wraps a piece of OpenGL state and remember its value to avoid redundant state calls. +// Wrapped types need to implement to the Value class interface: +// +// class Value { +// using Type = ...; +// static const constexpr Type Default = ...; +// static void Set(const Type& value); +// static Type Get(); +// }; +template <typename T, typename... Args> +class State { +public: + State(Args&&... args) : params(std::forward_as_tuple(::std::forward<Args>(args)...)) { + } + + void operator=(const typename T::Type& value) { + if (*this != value) { + setCurrentValue(value); + set(std::index_sequence_for<Args...>{}); + } + } + + bool operator==(const typename T::Type& value) const { + return !(*this != value); + } + + bool operator!=(const typename T::Type& value) const { + return dirty || currentValue != value; + } + + void setCurrentValue(const typename T::Type& value) { + dirty = false; + currentValue = value; + } + + // Mark the state as dirty. This means that the next time we are assigning a value to this + // piece of OpenGL state will always result in an actual OpenGL call. + void setDirty() { + dirty = true; + } + + typename T::Type getCurrentValue() const { + return currentValue; + } + + bool isDirty() const { + return dirty; + } + +private: + template <std::size_t... I> + void set(std::index_sequence<I...>) { + T::Set(currentValue, std::get<I>(params)...); + } + +private: + typename T::Type currentValue = T::Default; + bool dirty = true; + const std::tuple<Args...> params; +}; + +} // namespace gl +} // namespace mbgl diff --git a/platform/gfx/gl/src/mbgl/gl/texture.cpp b/platform/gfx/gl/src/mbgl/gl/texture.cpp new file mode 100644 index 0000000000..ef4d083677 --- /dev/null +++ b/platform/gfx/gl/src/mbgl/gl/texture.cpp @@ -0,0 +1,54 @@ +#include <mbgl/gl/texture.hpp> +#include <mbgl/gl/context.hpp> +#include <mbgl/gl/texture_resource.hpp> +#include <mbgl/gl/defines.hpp> + +namespace mbgl { +namespace gl { + +using namespace platform; + +void bindTexture(gl::Context& context, const uint8_t unit, const gfx::TextureBinding& binding) { + auto& resource = static_cast<gl::TextureResource&>(*binding.resource); + if (binding.filter != resource.filter || binding.mipmap != resource.mipmap || + binding.wrapX != resource.wrapX || binding.wrapY != resource.wrapY) { + context.activeTextureUnit = unit; + context.texture[unit] = resource.texture; + + if (binding.filter != resource.filter || binding.mipmap != resource.mipmap) { + MBGL_CHECK_ERROR(glTexParameteri( + GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, + binding.filter == gfx::TextureFilterType::Linear + ? (binding.mipmap == gfx::TextureMipMapType::Yes ? GL_LINEAR_MIPMAP_NEAREST + : GL_LINEAR) + : (binding.mipmap == gfx::TextureMipMapType::Yes ? GL_NEAREST_MIPMAP_NEAREST + : GL_NEAREST))); + MBGL_CHECK_ERROR(glTexParameteri( + GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, + binding.filter == gfx::TextureFilterType::Linear ? GL_LINEAR : GL_NEAREST)); + resource.filter = binding.filter; + resource.mipmap = binding.mipmap; + } + if (binding.wrapX != resource.wrapX) { + + MBGL_CHECK_ERROR(glTexParameteri( + GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, + binding.wrapX == gfx::TextureWrapType::Clamp ? GL_CLAMP_TO_EDGE : GL_REPEAT)); + resource.wrapX = binding.wrapX; + } + if (binding.wrapY != resource.wrapY) { + MBGL_CHECK_ERROR(glTexParameteri( + GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, + binding.wrapY == gfx::TextureWrapType::Clamp ? GL_CLAMP_TO_EDGE : GL_REPEAT)); + resource.wrapY = binding.wrapY; + } + } else if (context.texture[unit] != resource.texture) { + // We are checking first to avoid setting the active texture without a subsequent + // texture bind. + context.activeTextureUnit = unit; + context.texture[unit] = resource.texture; + } +} + +} // namespace gl +} // namespace mbgl diff --git a/platform/gfx/gl/src/mbgl/gl/texture.hpp b/platform/gfx/gl/src/mbgl/gl/texture.hpp new file mode 100644 index 0000000000..74a314d2a7 --- /dev/null +++ b/platform/gfx/gl/src/mbgl/gl/texture.hpp @@ -0,0 +1,49 @@ +#pragma once + +#include <mbgl/gfx/texture.hpp> +#include <mbgl/gl/uniform.hpp> +#include <mbgl/util/literal.hpp> +#include <mbgl/util/ignore.hpp> + +#include <vector> +#include <string> + +namespace mbgl { +namespace gl { + +class Context; + +void bindTexture(gl::Context&, uint8_t unit, const gfx::TextureBinding&); + +template <class> +class TextureStates; + +template <class... Ts> +class TextureStates<TypeList<Ts...>> { +private: + using State = + IndexedTuple<TypeList<Ts...>, TypeList<ExpandToType<Ts, gl::UniformState<uint8_t>>...>>; + + State state; + +public: + void queryLocations(const ProgramID& id) { + state = State{ gl::uniformLocation(id, + concat_literals<&string_literal<'u', '_'>::value, &Ts::name>::value())... }; + } + + NamedUniformLocations getNamedLocations() const { + return NamedUniformLocations{ { concat_literals<&string_literal<'u', '_'>::value, &Ts::name>::value(), + state.template get<Ts>().location }... }; + } + + void bind(gl::Context& context, const gfx::TextureBindings<TypeList<Ts...>>& bindings) { + util::ignore( + { (state.template get<Ts>() = TypeIndex<Ts, Ts...>::value, + gl::bindTexture(context, TypeIndex<Ts, Ts...>::value, bindings.template get<Ts>()), + 0)... }); + } +}; + +} // namespace gl +} // namespace mbgl diff --git a/platform/gfx/gl/src/mbgl/gl/texture_resource.hpp b/platform/gfx/gl/src/mbgl/gl/texture_resource.hpp new file mode 100644 index 0000000000..ed742e75b7 --- /dev/null +++ b/platform/gfx/gl/src/mbgl/gl/texture_resource.hpp @@ -0,0 +1,22 @@ +#pragma once + +#include <mbgl/gfx/texture.hpp> +#include <mbgl/gl/object.hpp> + +namespace mbgl { +namespace gl { + +class TextureResource : public gfx::TextureResource { +public: + TextureResource(UniqueTexture&& texture_) : texture(std::move(texture_)) { + } + + UniqueTexture texture; + gfx::TextureFilterType filter = gfx::TextureFilterType::Nearest; + gfx::TextureMipMapType mipmap = gfx::TextureMipMapType::No; + gfx::TextureWrapType wrapX = gfx::TextureWrapType::Clamp; + gfx::TextureWrapType wrapY = gfx::TextureWrapType::Clamp; +}; + +} // namespace gl +} // namespace mbgl diff --git a/platform/gfx/gl/src/mbgl/gl/types.hpp b/platform/gfx/gl/src/mbgl/gl/types.hpp new file mode 100644 index 0000000000..e679d7646b --- /dev/null +++ b/platform/gfx/gl/src/mbgl/gl/types.hpp @@ -0,0 +1,62 @@ +#pragma once + +#include <cstdint> +#include <type_traits> + +namespace mbgl { +namespace gl { + +// Mapping based on https://www.opengl.org/wiki/OpenGL_Type +using ProgramID = uint32_t; +using ShaderID = uint32_t; +using BufferID = uint32_t; +using TextureID = uint32_t; +using VertexArrayID = uint32_t; +using FramebufferID = uint32_t; +using RenderbufferID = uint32_t; + +// OpenGL does not formally define a type for attribute locations, but most APIs use +// GLuint. The exception is glGetAttribLocation, which returns GLint so that -1 can +// be used as an error indicator. +using AttributeLocation = uint32_t; + +// OpenGL does not formally define a type for uniform locations, but all APIs use GLint. +// The value -1 is special, typically used as a placeholder for an unused uniform and +// "silently ignored". +using UniformLocation = int32_t; + +enum class ShaderType : uint32_t { + Vertex = 0x8B31, + Fragment = 0x8B30 +}; + +struct PixelStorageType { + int32_t alignment; +}; + +constexpr bool operator!=(const PixelStorageType& a, const PixelStorageType& b) { + return a.alignment != b.alignment; +} + +enum class UniformDataType : uint32_t { + Float = 0x1406, + FloatVec2 = 0x8B50, + FloatVec3 = 0x8B51, + FloatVec4 = 0x8B52, + Int = 0x1404, + IntVec2 = 0x8B53, + IntVec3 = 0x8B54, + IntVec4 = 0x8B55, + Bool = 0x8B56, + BoolVec2 = 0x8B57, + BoolVec3 = 0x8B58, + BoolVec4 = 0x8B59, + FloatMat2 = 0x8B5A, + FloatMat3 = 0x8B5B, + FloatMat4 = 0x8B5C, + Sampler2D = 0x8B5E, + SamplerCube = 0x8B60, +}; + +} // namespace gl +} // namespace mbgl diff --git a/platform/gfx/gl/src/mbgl/gl/uniform.cpp b/platform/gfx/gl/src/mbgl/gl/uniform.cpp new file mode 100644 index 0000000000..8d99d4b467 --- /dev/null +++ b/platform/gfx/gl/src/mbgl/gl/uniform.cpp @@ -0,0 +1,202 @@ +#include <mbgl/gl/uniform.hpp> +#include <mbgl/gl/defines.hpp> +#include <mbgl/platform/gl_functions.hpp> +#include <mbgl/util/color.hpp> +#include <mbgl/util/size.hpp> +#include <mbgl/util/convert.hpp> + +#include <memory> + +namespace mbgl { +namespace gl { + +using namespace platform; + +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)); +} + +template <> +void bindUniform<int32_t>(UniformLocation location, const int32_t& t) { + MBGL_CHECK_ERROR(glUniform1i(location, t)); +} + +template <> +void bindUniform<std::array<float, 2>>(UniformLocation location, const std::array<float, 2>& t) { + MBGL_CHECK_ERROR(glUniform2fv(location, 1, t.data())); +} + +template <> +void bindUniform<std::array<float, 3>>(UniformLocation location, const std::array<float, 3>& t) { + MBGL_CHECK_ERROR(glUniform3fv(location, 1, t.data())); +} + +template <> +void bindUniform<std::array<float, 4>>(UniformLocation location, const std::array<float, 4>& t) { + MBGL_CHECK_ERROR(glUniform4fv(location, 1, t.data())); +} + +template <> +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<uint32_t>(UniformLocation location, const uint32_t& t) { + bindUniform(location, int32_t(t)); +} + +template <> +void bindUniform<uint8_t>(UniformLocation location, const uint8_t& t) { + bindUniform(location, int32_t(t)); +} + +template <> +void bindUniform<Color>(UniformLocation location, const Color& t) { + bindUniform(location, std::array<float, 4> {{ t.r, t.g, t.b, t.a }}); +} + +template <> +void bindUniform<Size>(UniformLocation location, const Size& t) { + bindUniform(location, util::convert<float>(std::array<uint32_t, 2> {{ t.width, t.height }})); +} + +template <> +void bindUniform<std::array<uint16_t, 2>>(UniformLocation location, const std::array<uint16_t, 2>& t) { + bindUniform(location, util::convert<float>(t)); +} + +template <> +void bindUniform<std::array<uint16_t, 4>>(UniformLocation location, const std::array<uint16_t, 4>& t) { + bindUniform(location, util::convert<float>(t)); +} + +// Add more as needed. + +#ifndef NDEBUG + +ActiveUniforms activeUniforms(ProgramID id) { + ActiveUniforms active; + + GLint count; + GLint maxLength; + MBGL_CHECK_ERROR(glGetProgramiv(id, GL_ACTIVE_UNIFORMS, &count)); + MBGL_CHECK_ERROR(glGetProgramiv(id, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxLength)); + + auto name = std::make_unique<GLchar[]>(maxLength); + GLsizei length; + GLint size; + GLenum type; + for (GLint index = 0; index < count; index++) { + MBGL_CHECK_ERROR(glGetActiveUniform(id, index, maxLength, &length, &size, &type, name.get())); + active.emplace( + std::string{ name.get(), static_cast<size_t>(length) }, + ActiveUniform{ static_cast<size_t>(size), static_cast<UniformDataType>(type) }); + } + + return active; +} + +template <> +bool verifyUniform<float>(const ActiveUniform& uniform) { + assert(uniform.size == 1 && uniform.type == UniformDataType::Float); + return true; +} + +template <> +bool verifyUniform<std::array<float, 2>>(const ActiveUniform& uniform) { + assert(uniform.size == 1 && uniform.type == UniformDataType::FloatVec2); + return true; +} + +template <> +bool verifyUniform<std::array<float, 3>>(const ActiveUniform& uniform) { + assert(uniform.size == 1 && uniform.type == UniformDataType::FloatVec3); + return true; +} + +template <> +bool verifyUniform<std::array<float, 4>>(const ActiveUniform& uniform) { + assert(uniform.size == 1 && uniform.type == UniformDataType::FloatVec4); + return true; +} + +template <> +bool verifyUniform<std::array<double, 16>>(const ActiveUniform& uniform) { + assert(uniform.size == 1 && uniform.type == UniformDataType::FloatMat4); + return true; +} + +template <> +bool verifyUniform<bool>(const ActiveUniform& uniform) { + assert(uniform.size == 1 && + (uniform.type == UniformDataType::Bool || + uniform.type == UniformDataType::Int || + uniform.type == UniformDataType::Float)); + return true; +} + +template <> +bool verifyUniform<uint32_t>(const ActiveUniform& uniform) { + assert(uniform.size == 1 && + (uniform.type == UniformDataType::Int || + uniform.type == UniformDataType::Float || + uniform.type == UniformDataType::Sampler2D)); + return true; +} + +template <> +bool verifyUniform<Color>(const ActiveUniform& uniform) { + assert(uniform.size == 1 && uniform.type == UniformDataType::FloatVec4); + return true; +} + +template <> +bool verifyUniform<Size>(const ActiveUniform& uniform) { + assert(uniform.size == 1 && uniform.type == UniformDataType::FloatVec2); + return true; +} + +template <> +bool verifyUniform<std::array<uint16_t, 2>>(const ActiveUniform& uniform) { + assert(uniform.size == 1 && + (uniform.type == UniformDataType::IntVec2 || + uniform.type == UniformDataType::FloatVec2)); + return true; +} + +template <> +bool verifyUniform<std::array<uint16_t, 4>>(const ActiveUniform& uniform) { + assert(uniform.size == 1 && + (uniform.type == UniformDataType::IntVec4 || + uniform.type == UniformDataType::FloatVec4)); + return true; +} + +// Add more as needed. + +#endif + +} // namespace gl +} // namespace mbgl diff --git a/platform/gfx/gl/src/mbgl/gl/uniform.hpp b/platform/gfx/gl/src/mbgl/gl/uniform.hpp new file mode 100644 index 0000000000..10501036cb --- /dev/null +++ b/platform/gfx/gl/src/mbgl/gl/uniform.hpp @@ -0,0 +1,95 @@ +#pragma once + +#include <mbgl/gfx/uniform.hpp> +#include <mbgl/gl/types.hpp> +#include <mbgl/util/optional.hpp> +#include <mbgl/util/literal.hpp> +#include <mbgl/util/ignore.hpp> +#include <mbgl/util/indexed_tuple.hpp> + +#include <array> +#include <vector> +#include <map> +#include <functional> + +namespace mbgl { +namespace gl { + +template <class T> +void bindUniform(UniformLocation, const T&); + +class ActiveUniform { +public: + std::size_t size; + UniformDataType type; +}; + +#ifndef NDEBUG + +template <class T> +bool verifyUniform(const ActiveUniform&); + +using ActiveUniforms = std::map<std::string, ActiveUniform>; +ActiveUniforms activeUniforms(ProgramID); + +#endif + +template <class Value> +class UniformState { +public: + UniformState(UniformLocation location_ = -1) : location(std::move(location_)) { + } + + void operator=(const Value& value) { + if (location >= 0 && (!current || *current != value)) { + current = value; + bindUniform(location, value); + } + } + + UniformLocation location; + optional<Value> current = {}; +}; + +UniformLocation uniformLocation(ProgramID, const char* name); + +using NamedUniformLocations = std::vector<std::pair<const std::string, UniformLocation>>; + +template <class> +class UniformStates; + +template <class... Us> +class UniformStates<TypeList<Us...>> final { +private: + using State = IndexedTuple<TypeList<Us...>, TypeList<UniformState<typename Us::Value>...>>; + + State state; + +public: + void queryLocations(const ProgramID& id) { +#ifndef NDEBUG + // Verify active uniform types match the enum + const auto active = gl::activeUniforms(id); + + util::ignore( + { // Some shader programs have uniforms declared, but not used, so they're not active. + // Therefore, we'll only verify them when they are indeed active. + (active.find(concat_literals<&string_literal<'u', '_'>::value, &Us::name>::value()) != active.end() + ? verifyUniform<typename Us::Value>(active.at(concat_literals<&string_literal<'u', '_'>::value, &Us::name>::value())) + : false)... }); +#endif + + state = State{ gl::uniformLocation(id, concat_literals<&string_literal<'u', '_'>::value, &Us::name>::value())... }; + } + + NamedUniformLocations getNamedLocations() const { + return NamedUniformLocations{ { concat_literals<&string_literal<'u', '_'>::value, &Us::name>::value(), state.template get<Us>().location }... }; + } + + void bind(const gfx::UniformValues<TypeList<Us...>>& values) { + util::ignore({ (state.template get<Us>() = values.template get<Us>(), 0)... }); + } +}; + +} // namespace gl +} // namespace mbgl diff --git a/platform/gfx/gl/src/mbgl/gl/upload_pass.cpp b/platform/gfx/gl/src/mbgl/gl/upload_pass.cpp new file mode 100644 index 0000000000..358f1a7203 --- /dev/null +++ b/platform/gfx/gl/src/mbgl/gl/upload_pass.cpp @@ -0,0 +1,117 @@ +#include <mbgl/gl/upload_pass.hpp> +#include <mbgl/gl/context.hpp> +#include <mbgl/gl/enum.hpp> +#include <mbgl/gl/defines.hpp> +#include <mbgl/gl/command_encoder.hpp> +#include <mbgl/gl/vertex_buffer_resource.hpp> +#include <mbgl/gl/index_buffer_resource.hpp> +#include <mbgl/gl/texture_resource.hpp> + +namespace mbgl { +namespace gl { + +using namespace platform; + +UploadPass::UploadPass(gl::CommandEncoder& commandEncoder_, const char* name) + : commandEncoder(commandEncoder_), debugGroup(commandEncoder.createDebugGroup(name)) { +} + +std::unique_ptr<gfx::VertexBufferResource> UploadPass::createVertexBufferResource( + const void* data, std::size_t size, const gfx::BufferUsageType usage) { + BufferID id = 0; + MBGL_CHECK_ERROR(glGenBuffers(1, &id)); + UniqueBuffer result{ std::move(id), { commandEncoder.context } }; + commandEncoder.context.vertexBuffer = result; + MBGL_CHECK_ERROR( + glBufferData(GL_ARRAY_BUFFER, size, data, Enum<gfx::BufferUsageType>::to(usage))); + return std::make_unique<gl::VertexBufferResource>(std::move(result)); +} + +void UploadPass::updateVertexBufferResource(gfx::VertexBufferResource& resource, + const void* data, + std::size_t size) { + commandEncoder.context.vertexBuffer = static_cast<gl::VertexBufferResource&>(resource).buffer; + MBGL_CHECK_ERROR(glBufferSubData(GL_ARRAY_BUFFER, 0, size, data)); +} + +std::unique_ptr<gfx::IndexBufferResource> UploadPass::createIndexBufferResource( + const void* data, std::size_t size, const gfx::BufferUsageType usage) { + BufferID id = 0; + MBGL_CHECK_ERROR(glGenBuffers(1, &id)); + UniqueBuffer result{ std::move(id), { commandEncoder.context } }; + commandEncoder.context.bindVertexArray = 0; + commandEncoder.context.globalVertexArrayState.indexBuffer = result; + MBGL_CHECK_ERROR( + glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, data, Enum<gfx::BufferUsageType>::to(usage))); + return std::make_unique<gl::IndexBufferResource>(std::move(result)); +} + +void UploadPass::updateIndexBufferResource(gfx::IndexBufferResource& resource, + const void* data, + std::size_t size) { + // Be sure to unbind any existing vertex array object before binding the index buffer + // so that we don't mess up another VAO + commandEncoder.context.bindVertexArray = 0; + commandEncoder.context.globalVertexArrayState.indexBuffer = + static_cast<gl::IndexBufferResource&>(resource).buffer; + MBGL_CHECK_ERROR(glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, size, data)); +} + +std::unique_ptr<gfx::TextureResource> +UploadPass::createTextureResource(const Size size, + const void* data, + gfx::TexturePixelType format, + gfx::TextureChannelDataType type) { + auto obj = commandEncoder.context.createUniqueTexture(); + std::unique_ptr<gfx::TextureResource> resource = + std::make_unique<gl::TextureResource>(std::move(obj)); + commandEncoder.context.pixelStoreUnpack = { 1 }; + updateTextureResource(*resource, size, data, format, type); + // 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)); + return resource; +} + +void UploadPass::updateTextureResource(gfx::TextureResource& resource, + const Size size, + const void* data, + gfx::TexturePixelType format, + gfx::TextureChannelDataType type) { + // Always use texture unit 0 for manipulating it. + commandEncoder.context.activeTextureUnit = 0; + commandEncoder.context.texture[0] = static_cast<gl::TextureResource&>(resource).texture; + MBGL_CHECK_ERROR(glTexImage2D(GL_TEXTURE_2D, 0, Enum<gfx::TexturePixelType>::to(format), + size.width, size.height, 0, + Enum<gfx::TexturePixelType>::to(format), + Enum<gfx::TextureChannelDataType>::to(type), data)); +} + +void UploadPass::updateTextureResourceSub(gfx::TextureResource& resource, + const uint16_t xOffset, + const uint16_t yOffset, + const Size size, + const void* data, + gfx::TexturePixelType format, + gfx::TextureChannelDataType type) { + // Always use texture unit 0 for manipulating it. + commandEncoder.context.activeTextureUnit = 0; + commandEncoder.context.texture[0] = static_cast<const gl::TextureResource&>(resource).texture; + MBGL_CHECK_ERROR(glTexSubImage2D(GL_TEXTURE_2D, 0, xOffset, yOffset, size.width, size.height, + Enum<gfx::TexturePixelType>::to(format), + Enum<gfx::TextureChannelDataType>::to(type), data)); +} + +void UploadPass::pushDebugGroup(const char* name) { + commandEncoder.pushDebugGroup(name); +} + +void UploadPass::popDebugGroup() { + commandEncoder.popDebugGroup(); +} + +} // namespace gl +} // namespace mbgl diff --git a/platform/gfx/gl/src/mbgl/gl/upload_pass.hpp b/platform/gfx/gl/src/mbgl/gl/upload_pass.hpp new file mode 100644 index 0000000000..8b4f71b88d --- /dev/null +++ b/platform/gfx/gl/src/mbgl/gl/upload_pass.hpp @@ -0,0 +1,42 @@ +#pragma once + +#include <mbgl/gfx/upload_pass.hpp> + +namespace mbgl { +namespace gfx { + +class CommandEncoder; + +} // namespace gfx + +namespace gl { + +class CommandEncoder; +class Context; + +class UploadPass final : public gfx::UploadPass { +public: + UploadPass(gl::CommandEncoder&, const char* name); + +private: + void pushDebugGroup(const char* name) override; + void popDebugGroup() override; + +public: + std::unique_ptr<gfx::VertexBufferResource> createVertexBufferResource(const void* data, std::size_t size, const gfx::BufferUsageType) override; + void updateVertexBufferResource(gfx::VertexBufferResource&, const void* data, std::size_t size) override; + std::unique_ptr<gfx::IndexBufferResource> createIndexBufferResource(const void* data, std::size_t size, const gfx::BufferUsageType) override; + void updateIndexBufferResource(gfx::IndexBufferResource&, const void* data, std::size_t size) override; + +public: + std::unique_ptr<gfx::TextureResource> createTextureResource(Size, const void* data, gfx::TexturePixelType, gfx::TextureChannelDataType) override; + void updateTextureResource(gfx::TextureResource&, Size, const void* data, gfx::TexturePixelType, gfx::TextureChannelDataType) override; + void updateTextureResourceSub(gfx::TextureResource&, const uint16_t xOffset, const uint16_t yOffset, Size, const void* data, gfx::TexturePixelType, gfx::TextureChannelDataType) override; + +private: + gl::CommandEncoder& commandEncoder; + const gfx::DebugGroup<gfx::CommandEncoder> debugGroup; +}; + +} // namespace gl +} // namespace mbgl diff --git a/platform/gfx/gl/src/mbgl/gl/value.cpp b/platform/gfx/gl/src/mbgl/gl/value.cpp new file mode 100644 index 0000000000..bd08ac48fc --- /dev/null +++ b/platform/gfx/gl/src/mbgl/gl/value.cpp @@ -0,0 +1,602 @@ +#include <mbgl/gl/value.hpp> +#include <mbgl/gl/context.hpp> +#include <mbgl/gl/vertex_buffer_resource.hpp> +#include <mbgl/gl/vertex_array_extension.hpp> +#include <mbgl/gl/enum.hpp> + +namespace mbgl { +namespace gl { +namespace value { + +using namespace platform; + +const constexpr ClearDepth::Type ClearDepth::Default; + +void ClearDepth::Set(const Type& value) { + MBGL_CHECK_ERROR(glClearDepthf(value)); +} + +ClearDepth::Type ClearDepth::Get() { + GLfloat clearDepth; + MBGL_CHECK_ERROR(glGetFloatv(GL_DEPTH_CLEAR_VALUE, &clearDepth)); + return clearDepth; +} + +const ClearColor::Type ClearColor::Default { 0, 0, 0, 0 }; + +void ClearColor::Set(const Type& value) { + MBGL_CHECK_ERROR(glClearColor(value.r, value.g, value.b, value.a)); +} + +ClearColor::Type ClearColor::Get() { + GLfloat clearColor[4]; + MBGL_CHECK_ERROR(glGetFloatv(GL_COLOR_CLEAR_VALUE, clearColor)); + return { clearColor[0], clearColor[1], clearColor[2], clearColor[3] }; +} + +const constexpr ClearStencil::Type ClearStencil::Default; + +void ClearStencil::Set(const Type& value) { + MBGL_CHECK_ERROR(glClearStencil(value)); +} + +ClearStencil::Type ClearStencil::Get() { + GLint clearStencil; + MBGL_CHECK_ERROR(glGetIntegerv(GL_STENCIL_CLEAR_VALUE, &clearStencil)); + return clearStencil; +} + +const constexpr StencilMask::Type StencilMask::Default; + +void StencilMask::Set(const Type& value) { + MBGL_CHECK_ERROR(glStencilMask(value)); +} + +StencilMask::Type StencilMask::Get() { + GLint stencilMask; + MBGL_CHECK_ERROR(glGetIntegerv(GL_STENCIL_WRITEMASK, &stencilMask)); + return stencilMask; +} + +const constexpr DepthMask::Type DepthMask::Default; + +void DepthMask::Set(const Type& value) { + MBGL_CHECK_ERROR(glDepthMask(Enum<gfx::DepthMaskType>::to(value))); +} + +DepthMask::Type DepthMask::Get() { + GLboolean depthMask; + MBGL_CHECK_ERROR(glGetBooleanv(GL_DEPTH_WRITEMASK, &depthMask)); + return Enum<gfx::DepthMaskType>::from(depthMask); +} + +const constexpr ColorMask::Type ColorMask::Default; + +void ColorMask::Set(const Type& value) { + MBGL_CHECK_ERROR(glColorMask(value.r, value.g, value.b, value.a)); +} + +ColorMask::Type ColorMask::Get() { + GLboolean bools[4]; + MBGL_CHECK_ERROR(glGetBooleanv(GL_COLOR_WRITEMASK, bools)); + return { static_cast<bool>(bools[0]), static_cast<bool>(bools[1]), static_cast<bool>(bools[2]), + static_cast<bool>(bools[3]) }; +} + +const constexpr StencilFunc::Type StencilFunc::Default; + +void StencilFunc::Set(const Type& value) { + MBGL_CHECK_ERROR(glStencilFunc(Enum<gfx::StencilFunctionType>::to(value.func), value.ref, value.mask)); +} + +StencilFunc::Type StencilFunc::Get() { + GLint func, ref, mask; + 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 { Enum<gfx::StencilFunctionType>::from(func), ref, static_cast<uint32_t>(mask) }; +} + +const constexpr StencilTest::Type StencilTest::Default; + +void StencilTest::Set(const Type& value) { + MBGL_CHECK_ERROR(value ? glEnable(GL_STENCIL_TEST) : glDisable(GL_STENCIL_TEST)); +} + +StencilTest::Type StencilTest::Get() { + Type stencilTest; + MBGL_CHECK_ERROR(stencilTest = glIsEnabled(GL_STENCIL_TEST)); + return stencilTest; +} + +const constexpr StencilOp::Type StencilOp::Default; + +void StencilOp::Set(const Type& value) { + MBGL_CHECK_ERROR(glStencilOp(Enum<gfx::StencilOpType>::to(value.sfail), + Enum<gfx::StencilOpType>::to(value.dpfail), + Enum<gfx::StencilOpType>::to(value.dppass))); +} + +StencilOp::Type StencilOp::Get() { + GLint sfail, dpfail, dppass; + 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 { Enum<gfx::StencilOpType>::from(sfail), + Enum<gfx::StencilOpType>::from(dpfail), + Enum<gfx::StencilOpType>::from(dppass) }; +} + +const constexpr DepthRange::Type DepthRange::Default; + +void DepthRange::Set(const Type& value) { + MBGL_CHECK_ERROR(glDepthRangef(value.min, value.max)); +} + +DepthRange::Type DepthRange::Get() { + GLfloat floats[2]; + MBGL_CHECK_ERROR(glGetFloatv(GL_DEPTH_RANGE, floats)); + return { floats[0], floats[1] }; +} + +const constexpr DepthTest::Type DepthTest::Default; + +void DepthTest::Set(const Type& value) { + MBGL_CHECK_ERROR(value ? glEnable(GL_DEPTH_TEST) : glDisable(GL_DEPTH_TEST)); +} + +DepthTest::Type DepthTest::Get() { + Type depthTest; + MBGL_CHECK_ERROR(depthTest = glIsEnabled(GL_DEPTH_TEST)); + return depthTest; +} + +const constexpr DepthFunc::Type DepthFunc::Default; + +void DepthFunc::Set(const DepthFunc::Type& value) { + MBGL_CHECK_ERROR(glDepthFunc(Enum<gfx::DepthFunctionType>::to(value))); +} + +DepthFunc::Type DepthFunc::Get() { + GLint depthFunc; + MBGL_CHECK_ERROR(glGetIntegerv(GL_DEPTH_FUNC, &depthFunc)); + return Enum<gfx::DepthFunctionType>::from(depthFunc); +} + +const constexpr Blend::Type Blend::Default; + +void Blend::Set(const Type& value) { + MBGL_CHECK_ERROR(value ? glEnable(GL_BLEND) : glDisable(GL_BLEND)); +} + +Blend::Type Blend::Get() { + Type blend; + MBGL_CHECK_ERROR(blend = glIsEnabled(GL_BLEND)); + return blend; +} + +const constexpr BlendEquation::Type BlendEquation::Default; + +void BlendEquation::Set(const Type& value) { + MBGL_CHECK_ERROR(glBlendEquation(Enum<gfx::ColorBlendEquationType>::to(value))); +} + +BlendEquation::Type BlendEquation::Get() { + GLint blend; + MBGL_CHECK_ERROR(glGetIntegerv(GL_BLEND_EQUATION_RGB, &blend)); + return Enum<gfx::ColorBlendEquationType>::from(blend); +} + +const constexpr BlendFunc::Type BlendFunc::Default; + +void BlendFunc::Set(const Type& value) { + MBGL_CHECK_ERROR(glBlendFunc(Enum<gfx::ColorBlendFactorType>::to(value.sfactor), + Enum<gfx::ColorBlendFactorType>::to(value.dfactor))); +} + +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 { Enum<gfx::ColorBlendFactorType>::from(sfactor), + Enum<gfx::ColorBlendFactorType>::from(dfactor) }; +} + +const BlendColor::Type BlendColor::Default { 0, 0, 0, 0 }; + +void BlendColor::Set(const Type& value) { + MBGL_CHECK_ERROR(glBlendColor(value.r, value.g, value.b, value.a)); +} + +BlendColor::Type BlendColor::Get() { + GLfloat floats[4]; + MBGL_CHECK_ERROR(glGetFloatv(GL_BLEND_COLOR, floats)); + return { floats[0], floats[1], floats[2], floats[3] }; +} + +const constexpr Program::Type Program::Default; + +void Program::Set(const Type& value) { + MBGL_CHECK_ERROR(glUseProgram(value)); +} + +Program::Type Program::Get() { + GLint program; + MBGL_CHECK_ERROR(glGetIntegerv(GL_CURRENT_PROGRAM, &program)); + return program; +} + +const constexpr LineWidth::Type LineWidth::Default; + +void LineWidth::Set(const Type& value) { + MBGL_CHECK_ERROR(glLineWidth(value)); +} + +LineWidth::Type LineWidth::Get() { + GLfloat lineWidth; + MBGL_CHECK_ERROR(glGetFloatv(GL_LINE_WIDTH, &lineWidth)); + return lineWidth; +} + +const constexpr ActiveTextureUnit::Type ActiveTextureUnit::Default; + +void ActiveTextureUnit::Set(const Type& value) { + MBGL_CHECK_ERROR(glActiveTexture(GL_TEXTURE0 + value)); +} + +ActiveTextureUnit::Type ActiveTextureUnit::Get() { + GLint activeTexture; + MBGL_CHECK_ERROR(glGetIntegerv(GL_ACTIVE_TEXTURE, &activeTexture)); + return static_cast<Type>(activeTexture - GL_TEXTURE0); +} + +const constexpr Viewport::Type Viewport::Default; + +void Viewport::Set(const Type& value) { + 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<uint32_t>(viewport[2]), static_cast<uint32_t>(viewport[3]) } }; +} + +const constexpr ScissorTest::Type ScissorTest::Default; + +void ScissorTest::Set(const Type& value) { + MBGL_CHECK_ERROR(value ? glEnable(GL_SCISSOR_TEST) : glDisable(GL_SCISSOR_TEST)); +} + +ScissorTest::Type ScissorTest::Get() { + Type scissorTest; + MBGL_CHECK_ERROR(scissorTest = glIsEnabled(GL_SCISSOR_TEST)); + return scissorTest; +} + +const constexpr BindFramebuffer::Type BindFramebuffer::Default; + +void BindFramebuffer::Set(const Type& value) { + MBGL_CHECK_ERROR(glBindFramebuffer(GL_FRAMEBUFFER, value)); +} + +BindFramebuffer::Type BindFramebuffer::Get() { + GLint binding; + MBGL_CHECK_ERROR(glGetIntegerv(GL_FRAMEBUFFER_BINDING, &binding)); + return binding; +} + +const constexpr BindRenderbuffer::Type BindRenderbuffer::Default; + +void BindRenderbuffer::Set(const Type& value) { + MBGL_CHECK_ERROR(glBindRenderbuffer(GL_RENDERBUFFER, value)); +} + +BindRenderbuffer::Type BindRenderbuffer::Get() { + GLint binding; + MBGL_CHECK_ERROR(glGetIntegerv(GL_RENDERBUFFER_BINDING, &binding)); + return binding; +} + +const constexpr CullFace::Type CullFace::Default; + +void CullFace::Set(const Type& value) { + MBGL_CHECK_ERROR(value ? glEnable(GL_CULL_FACE) : glDisable(GL_CULL_FACE)); +} + +CullFace::Type CullFace::Get() { + GLboolean cullFace; + MBGL_CHECK_ERROR(cullFace = glIsEnabled(GL_CULL_FACE)); + return cullFace; +} + +const constexpr CullFaceSide::Type CullFaceSide::Default; + +void CullFaceSide::Set(const Type& value) { + MBGL_CHECK_ERROR(glCullFace(Enum<gfx::CullFaceSideType>::to(value))); +} + +CullFaceSide::Type CullFaceSide::Get() { + GLint cullFaceMode; + MBGL_CHECK_ERROR(glGetIntegerv(GL_CULL_FACE_MODE, &cullFaceMode)); + return Enum<gfx::CullFaceSideType>::from(cullFaceMode); +} + +const constexpr CullFaceWinding::Type CullFaceWinding::Default; + +void CullFaceWinding::Set(const Type& value) { + MBGL_CHECK_ERROR(glFrontFace(Enum<gfx::CullFaceWindingType>::to(value))); +} + +CullFaceWinding::Type CullFaceWinding::Get() { + GLint frontFace; + MBGL_CHECK_ERROR(glGetIntegerv(GL_FRONT_FACE, &frontFace)); + return Enum<gfx::CullFaceWindingType>::from(frontFace); +} + +const constexpr BindTexture::Type BindTexture::Default; + +void BindTexture::Set(const Type& value) { + MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, value)); +} + +BindTexture::Type BindTexture::Get() { + GLint binding; + MBGL_CHECK_ERROR(glGetIntegerv(GL_TEXTURE_BINDING_2D, &binding)); + return binding; +} + +const constexpr BindVertexBuffer::Type BindVertexBuffer::Default; + +void BindVertexBuffer::Set(const Type& value) { + MBGL_CHECK_ERROR(glBindBuffer(GL_ARRAY_BUFFER, value)); +} + +BindVertexBuffer::Type BindVertexBuffer::Get() { + GLint binding; + MBGL_CHECK_ERROR(glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &binding)); + return binding; +} + +const constexpr BindElementBuffer::Type BindElementBuffer::Default; + +void BindElementBuffer::Set(const Type& value) { + MBGL_CHECK_ERROR(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, value)); +} + +BindElementBuffer::Type BindElementBuffer::Get() { + GLint binding; + MBGL_CHECK_ERROR(glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &binding)); + return binding; +} + +const constexpr BindVertexArray::Type BindVertexArray::Default; + +void BindVertexArray::Set(const Type& value, const Context& context) { + if (auto vertexArray = context.getVertexArrayExtension()) { + if (vertexArray->bindVertexArray) { + MBGL_CHECK_ERROR(vertexArray->bindVertexArray(value)); + } + } +} + +BindVertexArray::Type BindVertexArray::Get(const Context& context) { + GLint binding = 0; + if (context.getVertexArrayExtension()) { +#ifdef GL_VERTEX_ARRAY_BINDING + MBGL_CHECK_ERROR(glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &binding)); +#elif GL_VERTEX_ARRAY_BINDING_OES + MBGL_CHECK_ERROR(glGetIntegerv(GL_VERTEX_ARRAY_BINDING_OES, &binding)); +#elif GL_VERTEX_ARRAY_BINDING_ARB + MBGL_CHECK_ERROR(glGetIntegerv(GL_VERTEX_ARRAY_BINDING_ARB, &binding)); +#elif GLVERTEX_ARRAY_BINDING_APPLE + MBGL_CHECK_ERROR(glGetIntegerv(GLVERTEX_ARRAY_BINDING_APPLE, &binding)); +#endif + } + return binding; +} + +const VertexAttribute::Type VertexAttribute::Default {}; + +namespace { + +GLenum vertexType(const gfx::AttributeDataType type) { + switch (type) { + case gfx::AttributeDataType::Byte: + case gfx::AttributeDataType::Byte2: + case gfx::AttributeDataType::Byte3: + case gfx::AttributeDataType::Byte4: + return GL_BYTE; + case gfx::AttributeDataType::UByte: + case gfx::AttributeDataType::UByte2: + case gfx::AttributeDataType::UByte3: + case gfx::AttributeDataType::UByte4: + return GL_UNSIGNED_BYTE; + case gfx::AttributeDataType::Short: + case gfx::AttributeDataType::Short2: + case gfx::AttributeDataType::Short3: + case gfx::AttributeDataType::Short4: + return GL_SHORT; + case gfx::AttributeDataType::UShort: + case gfx::AttributeDataType::UShort2: + case gfx::AttributeDataType::UShort3: + case gfx::AttributeDataType::UShort4: + return GL_UNSIGNED_SHORT; + case gfx::AttributeDataType::Int: + case gfx::AttributeDataType::Int2: + case gfx::AttributeDataType::Int3: + case gfx::AttributeDataType::Int4: + return GL_INT; + case gfx::AttributeDataType::UInt: + case gfx::AttributeDataType::UInt2: + case gfx::AttributeDataType::UInt3: + case gfx::AttributeDataType::UInt4: + return GL_UNSIGNED_INT; + case gfx::AttributeDataType::Float: + case gfx::AttributeDataType::Float2: + case gfx::AttributeDataType::Float3: + case gfx::AttributeDataType::Float4: + return GL_FLOAT; + default: + return GL_FLOAT; + } +} + +GLint components(const gfx::AttributeDataType type) { + switch (type) { + case gfx::AttributeDataType::Byte: + case gfx::AttributeDataType::UByte: + case gfx::AttributeDataType::Short: + case gfx::AttributeDataType::UShort: + case gfx::AttributeDataType::Int: + case gfx::AttributeDataType::UInt: + case gfx::AttributeDataType::Float: + return 1; + case gfx::AttributeDataType::Byte2: + case gfx::AttributeDataType::UByte2: + case gfx::AttributeDataType::Short2: + case gfx::AttributeDataType::UShort2: + case gfx::AttributeDataType::Int2: + case gfx::AttributeDataType::UInt2: + case gfx::AttributeDataType::Float2: + return 2; + case gfx::AttributeDataType::Byte3: + case gfx::AttributeDataType::UByte3: + case gfx::AttributeDataType::Short3: + case gfx::AttributeDataType::UShort3: + case gfx::AttributeDataType::Int3: + case gfx::AttributeDataType::UInt3: + case gfx::AttributeDataType::Float3: + return 3; + case gfx::AttributeDataType::Byte4: + case gfx::AttributeDataType::UByte4: + case gfx::AttributeDataType::Short4: + case gfx::AttributeDataType::UShort4: + case gfx::AttributeDataType::Int4: + case gfx::AttributeDataType::UInt4: + case gfx::AttributeDataType::Float4: + return 4; + default: + return 0; + } +} + +} // namespace + +void VertexAttribute::Set(const Type& binding, Context& context, AttributeLocation location) { + if (binding) { + context.vertexBuffer = reinterpret_cast<const gl::VertexBufferResource&>(*binding->vertexBufferResource).buffer; + MBGL_CHECK_ERROR(glEnableVertexAttribArray(location)); + MBGL_CHECK_ERROR(glVertexAttribPointer( + location, + components(binding->attribute.dataType), + vertexType(binding->attribute.dataType), + static_cast<GLboolean>(false), + static_cast<GLsizei>(binding->vertexStride), + reinterpret_cast<GLvoid*>(binding->attribute.offset + (binding->vertexStride * binding->vertexOffset)))); + } else { + MBGL_CHECK_ERROR(glDisableVertexAttribArray(location)); + } +} + +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; +} + +#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) { + MBGL_CHECK_ERROR(glPixelZoom(value.xfactor, value.yfactor)); +} + +PixelZoom::Type PixelZoom::Get() { + GLfloat xfactor, yfactor; + MBGL_CHECK_ERROR(glGetFloatv(GL_ZOOM_X, &xfactor)); + MBGL_CHECK_ERROR(glGetFloatv(GL_ZOOM_Y, &yfactor)); + return { xfactor, yfactor }; +} + +const constexpr RasterPos::Type RasterPos::Default; + +void RasterPos::Set(const Type& value) { + MBGL_CHECK_ERROR(glRasterPos4d(value.x, value.y, value.z, value.w)); +} + +RasterPos::Type RasterPos::Get() { + GLdouble pos[4]; + MBGL_CHECK_ERROR(glGetDoublev(GL_CURRENT_RASTER_POSITION, pos)); + return { pos[0], pos[1], pos[2], pos[3] }; +} + +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 +} // namespace mbgl diff --git a/platform/gfx/gl/src/mbgl/gl/value.hpp b/platform/gfx/gl/src/mbgl/gl/value.hpp new file mode 100644 index 0000000000..5bd2132ecf --- /dev/null +++ b/platform/gfx/gl/src/mbgl/gl/value.hpp @@ -0,0 +1,357 @@ +#pragma once + +#include <mbgl/gl/types.hpp> +#include <mbgl/gfx/depth_mode.hpp> +#include <mbgl/gfx/stencil_mode.hpp> +#include <mbgl/gfx/color_mode.hpp> +#include <mbgl/gfx/cull_face_mode.hpp> +#include <mbgl/gl/attribute.hpp> +#include <mbgl/platform/gl_functions.hpp> +#include <mbgl/util/color.hpp> +#include <mbgl/util/size.hpp> +#include <mbgl/util/range.hpp> + +namespace mbgl { +namespace gl { + +class Context; + +namespace value { + +struct ClearDepth { + using Type = float; + static const constexpr Type Default = 1; + static void Set(const Type&); + static Type Get(); +}; + +struct ClearColor { + using Type = Color; + static const Type Default; + static void Set(const Type&); + static Type Get(); +}; + +struct ClearStencil { + using Type = int32_t; + static const constexpr Type Default = 0; + static void Set(const Type&); + static Type Get(); +}; + +struct StencilMask { + using Type = uint32_t; + static const constexpr Type Default = ~0u; + static void Set(const Type&); + static Type Get(); +}; + +struct DepthMask { + using Type = gfx::DepthMaskType; + static const constexpr Type Default = gfx::DepthMaskType::ReadWrite; + static void Set(const Type&); + static Type Get(); +}; + +struct ColorMask { + using Type = gfx::ColorMode::Mask; + static const constexpr Type Default = { true, true, true, true }; + static void Set(const Type&); + static Type Get(); +}; + +struct StencilFunc { + struct Type { + gfx::StencilFunctionType func; + int32_t ref; + uint32_t mask; + }; + static const constexpr Type Default = { gfx::StencilMode::Always::func, 0, ~0u }; + static void Set(const Type&); + static Type Get(); +}; + +constexpr bool operator!=(const StencilFunc::Type& a, const StencilFunc::Type& b) { + return a.func != b.func || a.ref != b.ref || a.mask != b.mask; +} + +struct StencilTest { + using Type = bool; + static const constexpr Type Default = false; + static void Set(const Type&); + static Type Get(); +}; + +struct StencilOp { + struct Type { + gfx::StencilOpType sfail; + gfx::StencilOpType dpfail; + gfx::StencilOpType dppass; + }; + static const constexpr Type Default = { gfx::StencilOpType::Keep, gfx::StencilOpType::Keep, gfx::StencilOpType::Keep }; + static void Set(const Type&); + static Type Get(); +}; + +constexpr bool operator!=(const StencilOp::Type& a, const StencilOp::Type& b) { + return a.sfail != b.sfail || a.dpfail != b.dpfail || a.dppass != b.dppass; +} + +struct DepthRange { + using Type = Range<float>; + static const constexpr Type Default = { 0, 1 }; + static void Set(const Type&); + static Type Get(); +}; + +struct DepthTest { + using Type = bool; + static const constexpr Type Default = false; + static void Set(const Type&); + static Type Get(); +}; + +struct DepthFunc { + using Type = gfx::DepthFunctionType; + static const constexpr Type Default = gfx::DepthFunctionType::Less; + static void Set(const Type&); + static Type Get(); +}; + +struct Blend { + using Type = bool; + static const constexpr Type Default = true; + static void Set(const Type&); + static Type Get(); +}; + +struct BlendEquation { + using Type = gfx::ColorBlendEquationType; + static const constexpr Type Default = gfx::ColorBlendEquationType::Add; + static void Set(const Type&); + static Type Get(); +}; + +struct BlendFunc { + struct Type { + gfx::ColorBlendFactorType sfactor; + gfx::ColorBlendFactorType dfactor; + }; + static const constexpr Type Default = { gfx::ColorBlendFactorType::One, gfx::ColorBlendFactorType::Zero }; + static void Set(const Type&); + static Type Get(); +}; + +constexpr bool operator!=(const BlendFunc::Type& a, const BlendFunc::Type& b) { + return a.sfactor != b.sfactor || a.dfactor != b.dfactor; +} + +struct BlendColor { + using Type = Color; + static const Type Default; + static void Set(const Type&); + static Type Get(); +}; + +struct Program { + using Type = gl::ProgramID; + static const constexpr Type Default = 0; + static void Set(const Type&); + static Type Get(); +}; + +struct LineWidth { + using Type = float; + static const constexpr Type Default = 1; + static void Set(const Type&); + static Type Get(); +}; + +struct ActiveTextureUnit { + using Type = uint8_t; + static const constexpr Type Default = 0; + static void Set(const Type&); + static Type Get(); +}; + +struct Viewport { + struct Type { + int32_t x; + int32_t y; + Size size; + }; + static const constexpr Type Default = { 0, 0, { 0, 0 } }; + static void Set(const Type&); + static Type Get(); +}; + +struct ScissorTest { + using Type = bool; + static const constexpr Type Default = false; + 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.size != b.size; +} + +constexpr bool operator==(const Viewport::Type& a, const Viewport::Type& b) { + return !(a != b); +} + +struct BindFramebuffer { + using Type = FramebufferID; + static const constexpr Type Default = 0; + static void Set(const Type&); + static Type Get(); +}; + +struct BindRenderbuffer { + using Type = RenderbufferID; + static const constexpr Type Default = 0; + static void Set(const Type&); + static Type Get(); +}; + +struct CullFace { + using Type = bool; + static const constexpr Type Default = false; + static void Set(const Type&); + static Type Get(); +}; + +struct CullFaceSide { + using Type = gfx::CullFaceSideType; + static const constexpr Type Default = gfx::CullFaceSideType::Back; + static void Set(const Type&); + static Type Get(); +}; + +struct CullFaceWinding { + using Type = gfx::CullFaceWindingType; + static const constexpr Type Default = gfx::CullFaceWindingType::CounterClockwise; + static void Set(const Type&); + static Type Get(); +}; + +struct BindTexture { + using Type = gl::TextureID; + static const constexpr Type Default = 0; + static void Set(const Type&); + static Type Get(); +}; + +struct BindVertexBuffer { + using Type = gl::BufferID; + static const constexpr Type Default = 0; + static void Set(const Type&); + static Type Get(); +}; + +struct BindElementBuffer { + using Type = gl::BufferID; + static const constexpr Type Default = 0; + static void Set(const Type&); + static Type Get(); +}; + +struct BindVertexArray { + using Type = gl::VertexArrayID; + static const constexpr Type Default = 0; + static void Set(const Type&, const Context&); + static Type Get(const Context&); +}; + +struct VertexAttribute { + using Type = optional<gfx::AttributeBinding>; + static const Type Default; + static void Set(const Type&, Context&, AttributeLocation); +}; + +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(); +}; + +#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; + float yfactor; + }; + static const constexpr Type Default = { 1, 1 }; + static void Set(const Type&); + static Type Get(); +}; + +constexpr bool operator!=(const PixelZoom::Type& a, const PixelZoom::Type& b) { + return a.xfactor != b.xfactor || a.yfactor != b.yfactor; +} + +struct RasterPos { + struct Type { + double x; + double y; + double z; + double w; + }; + static const constexpr Type Default = { 0, 0, 0, 1 }; + static void Set(const Type&); + static Type Get(); +}; + +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 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 +} // namespace gl +} // namespace mbgl diff --git a/platform/gfx/gl/src/mbgl/gl/vertex_array.cpp b/platform/gfx/gl/src/mbgl/gl/vertex_array.cpp new file mode 100644 index 0000000000..831b118fce --- /dev/null +++ b/platform/gfx/gl/src/mbgl/gl/vertex_array.cpp @@ -0,0 +1,24 @@ +#include <mbgl/gl/vertex_array.hpp> +#include <mbgl/gl/index_buffer_resource.hpp> +#include <mbgl/gl/context.hpp> + +namespace mbgl { +namespace gl { + +void VertexArray::bind(Context& context, + const gfx::IndexBuffer& indexBuffer, + const AttributeBindingArray& bindings) { + context.bindVertexArray = state->vertexArray; + state->indexBuffer = indexBuffer.getResource<gl::IndexBufferResource>().buffer; + + state->bindings.reserve(bindings.size()); + for (AttributeLocation location = 0; location < bindings.size(); ++location) { + if (state->bindings.size() <= location) { + state->bindings.emplace_back(context, AttributeLocation(location)); + } + state->bindings[location] = bindings[location]; + } +} + +} // namespace gl +} // namespace mbgl diff --git a/platform/gfx/gl/src/mbgl/gl/vertex_array.hpp b/platform/gfx/gl/src/mbgl/gl/vertex_array.hpp new file mode 100644 index 0000000000..70413050b2 --- /dev/null +++ b/platform/gfx/gl/src/mbgl/gl/vertex_array.hpp @@ -0,0 +1,71 @@ +#pragma once + +#include <mbgl/gl/object.hpp> +#include <mbgl/gl/attribute.hpp> +#include <mbgl/gl/state.hpp> +#include <mbgl/gl/value.hpp> + +#include <array> +#include <memory> + +namespace mbgl { + +namespace gfx { +class IndexBuffer; +} // namespace gfx + +namespace gl { + +class Context; + +class VertexArrayState { +public: + VertexArrayState(UniqueVertexArray vertexArray_) + : vertexArray(std::move(vertexArray_)) { + } + + void setDirty() { + indexBuffer.setDirty(); + for (auto& binding : bindings) { + binding.setDirty(); + } + } + + UniqueVertexArray vertexArray; + State<value::BindElementBuffer> indexBuffer; + + using AttributeState = State<value::VertexAttribute, Context&, AttributeLocation>; + std::vector<AttributeState> bindings; +}; + +class VertexArrayStateDeleter { +public: + VertexArrayStateDeleter(bool destroy_) + : destroy(destroy_) {} + + void operator()(VertexArrayState* ptr) const { + if (destroy) { + delete ptr; + } + } + +private: + bool destroy; +}; + +using UniqueVertexArrayState = std::unique_ptr<VertexArrayState, VertexArrayStateDeleter>; + +class VertexArray { +public: + VertexArray(UniqueVertexArrayState state_) + : state(std::move(state_)) { + } + + void bind(Context&, const gfx::IndexBuffer&, const AttributeBindingArray&); + +private: + UniqueVertexArrayState state; +}; + +} // namespace gl +} // namespace mbgl diff --git a/platform/gfx/gl/src/mbgl/gl/vertex_array_extension.hpp b/platform/gfx/gl/src/mbgl/gl/vertex_array_extension.hpp new file mode 100644 index 0000000000..967d99af32 --- /dev/null +++ b/platform/gfx/gl/src/mbgl/gl/vertex_array_extension.hpp @@ -0,0 +1,38 @@ +#pragma once + +#include <mbgl/gl/extension.hpp> +#include <mbgl/gl/defines.hpp> +#include <mbgl/platform/gl_functions.hpp> + +namespace mbgl { +namespace gl { +namespace extension { + +class VertexArray { +public: + template <typename Fn> + VertexArray(const Fn& loadExtension) + : bindVertexArray( + loadExtension({ { "GL_ARB_vertex_array_object", "glBindVertexArray" }, + { "GL_OES_vertex_array_object", "glBindVertexArrayOES" }, + { "GL_APPLE_vertex_array_object", "glBindVertexArrayAPPLE" } })), + deleteVertexArrays( + loadExtension({ { "GL_ARB_vertex_array_object", "glDeleteVertexArrays" }, + { "GL_OES_vertex_array_object", "glDeleteVertexArraysOES" }, + { "GL_APPLE_vertex_array_object", "glDeleteVertexArraysAPPLE" } })), + genVertexArrays( + loadExtension({ { "GL_ARB_vertex_array_object", "glGenVertexArrays" }, + { "GL_OES_vertex_array_object", "glGenVertexArraysOES" }, + { "GL_APPLE_vertex_array_object", "glGenVertexArraysAPPLE" } })) { + } + + const ExtensionFunction<void(platform::GLuint array)> bindVertexArray; + + const ExtensionFunction<void(platform::GLsizei n, const platform::GLuint* arrays)> deleteVertexArrays; + + const ExtensionFunction<void(platform::GLsizei n, platform::GLuint* arrays)> genVertexArrays; +}; + +} // namespace extension +} // namespace gl +} // namespace mbgl diff --git a/platform/gfx/gl/src/mbgl/gl/vertex_buffer_resource.hpp b/platform/gfx/gl/src/mbgl/gl/vertex_buffer_resource.hpp new file mode 100644 index 0000000000..95e5e75d45 --- /dev/null +++ b/platform/gfx/gl/src/mbgl/gl/vertex_buffer_resource.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include <mbgl/gfx/vertex_buffer.hpp> +#include <mbgl/gl/object.hpp> + +namespace mbgl { +namespace gl { + +class VertexBufferResource : public gfx::VertexBufferResource { +public: + VertexBufferResource(UniqueBuffer&& buffer_) : buffer(std::move(buffer_)) { + } + + UniqueBuffer buffer; +}; + +} // namespace gl +} // namespace mbgl diff --git a/platform/gfx/gl/src/mbgl/platform/gl_functions.cpp b/platform/gfx/gl/src/mbgl/platform/gl_functions.cpp new file mode 100644 index 0000000000..6eb7790ca2 --- /dev/null +++ b/platform/gfx/gl/src/mbgl/platform/gl_functions.cpp @@ -0,0 +1,17 @@ +#include <mbgl/platform/gl_functions.hpp> + +#include <mbgl/util/logging.hpp> + +namespace mbgl { +namespace platform { + +#ifndef NDEBUG +void glCheckError(const char* cmd, const char* file, int line) { + if (GLenum err = glGetError()) { + Log::Warning(Event::OpenGL, "Error %d: %s - %s:%d", err, cmd, file, line); + } +} +#endif + +} // namespace platform +} // namespace mbgl diff --git a/platform/gfx/gl/src/mbgl/programs/gl/background.cpp b/platform/gfx/gl/src/mbgl/programs/gl/background.cpp new file mode 100644 index 0000000000..f3d2cdfd90 --- /dev/null +++ b/platform/gfx/gl/src/mbgl/programs/gl/background.cpp @@ -0,0 +1,66 @@ +// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. + +#include <mbgl/programs/background_program.hpp> +#include <mbgl/programs/gl/preludes.hpp> +#include <mbgl/programs/gl/shader_source.hpp> +#include <mbgl/gl/program.hpp> + +namespace mbgl { +namespace programs { +namespace gl { + +template <typename> +struct ShaderSource; + +template <> +struct ShaderSource<BackgroundProgram> { + static constexpr const char* name = "background"; + static constexpr const uint8_t hash[8] = { 0x2d, 0xef, 0x97, 0xa2, 0xec, 0xb5, 0x67, 0xef }; + static constexpr const auto vertexOffset = 1429; + static constexpr const auto fragmentOffset = 1525; +}; + +constexpr const char* ShaderSource<BackgroundProgram>::name; +constexpr const uint8_t ShaderSource<BackgroundProgram>::hash[8]; + +} // namespace gl +} // namespace programs + +namespace gfx { + +template <> +std::unique_ptr<gfx::Program<BackgroundProgram>> +Backend::Create<gfx::Backend::Type::OpenGL>(const ProgramParameters& programParameters) { + return std::make_unique<gl::Program<BackgroundProgram>>(programParameters); +} + +} // namespace gfx +} // namespace mbgl + +// Uncompressed source of background.vertex.glsl: +/* +attribute vec2 a_pos; + +uniform mat4 u_matrix; + +void main() { + gl_Position = u_matrix * vec4(a_pos, 0, 1); +} + +*/ + +// Uncompressed source of background.fragment.glsl: +/* +uniform vec4 u_color; +uniform float u_opacity; + +void main() { + gl_FragColor = u_color * u_opacity; + +#ifdef OVERDRAW_INSPECTOR + gl_FragColor = vec4(1.0); +#endif +} + +*/ + diff --git a/platform/gfx/gl/src/mbgl/programs/gl/background_pattern.cpp b/platform/gfx/gl/src/mbgl/programs/gl/background_pattern.cpp new file mode 100644 index 0000000000..482814cbda --- /dev/null +++ b/platform/gfx/gl/src/mbgl/programs/gl/background_pattern.cpp @@ -0,0 +1,97 @@ +// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. + +#include <mbgl/programs/background_pattern_program.hpp> +#include <mbgl/programs/gl/preludes.hpp> +#include <mbgl/programs/gl/shader_source.hpp> +#include <mbgl/gl/program.hpp> + +namespace mbgl { +namespace programs { +namespace gl { + +template <typename> +struct ShaderSource; + +template <> +struct ShaderSource<BackgroundPatternProgram> { + static constexpr const char* name = "background_pattern"; + static constexpr const uint8_t hash[8] = { 0x70, 0x13, 0xc8, 0x7e, 0xba, 0x18, 0xf5, 0x19 }; + static constexpr const auto vertexOffset = 1675; + static constexpr const auto fragmentOffset = 2266; +}; + +constexpr const char* ShaderSource<BackgroundPatternProgram>::name; +constexpr const uint8_t ShaderSource<BackgroundPatternProgram>::hash[8]; + +} // namespace gl +} // namespace programs + +namespace gfx { + +template <> +std::unique_ptr<gfx::Program<BackgroundPatternProgram>> +Backend::Create<gfx::Backend::Type::OpenGL>(const ProgramParameters& programParameters) { + return std::make_unique<gl::Program<BackgroundPatternProgram>>(programParameters); +} + +} // namespace gfx +} // namespace mbgl + +// Uncompressed source of background_pattern.vertex.glsl: +/* +uniform mat4 u_matrix; +uniform vec2 u_pattern_size_a; +uniform vec2 u_pattern_size_b; +uniform vec2 u_pixel_coord_upper; +uniform vec2 u_pixel_coord_lower; +uniform float u_scale_a; +uniform float u_scale_b; +uniform float u_tile_units_to_pixels; + +attribute vec2 a_pos; + +varying vec2 v_pos_a; +varying vec2 v_pos_b; + +void main() { + gl_Position = u_matrix * vec4(a_pos, 0, 1); + + v_pos_a = get_pattern_pos(u_pixel_coord_upper, u_pixel_coord_lower, u_scale_a * u_pattern_size_a, u_tile_units_to_pixels, a_pos); + v_pos_b = get_pattern_pos(u_pixel_coord_upper, u_pixel_coord_lower, u_scale_b * u_pattern_size_b, u_tile_units_to_pixels, a_pos); +} + +*/ + +// Uncompressed source of background_pattern.fragment.glsl: +/* +uniform vec2 u_pattern_tl_a; +uniform vec2 u_pattern_br_a; +uniform vec2 u_pattern_tl_b; +uniform vec2 u_pattern_br_b; +uniform vec2 u_texsize; +uniform float u_mix; +uniform float u_opacity; + +uniform sampler2D u_image; + +varying vec2 v_pos_a; +varying vec2 v_pos_b; + +void main() { + vec2 imagecoord = mod(v_pos_a, 1.0); + vec2 pos = mix(u_pattern_tl_a / u_texsize, u_pattern_br_a / u_texsize, imagecoord); + vec4 color1 = texture2D(u_image, pos); + + vec2 imagecoord_b = mod(v_pos_b, 1.0); + vec2 pos2 = mix(u_pattern_tl_b / u_texsize, u_pattern_br_b / u_texsize, imagecoord_b); + vec4 color2 = texture2D(u_image, pos2); + + gl_FragColor = mix(color1, color2, u_mix) * u_opacity; + +#ifdef OVERDRAW_INSPECTOR + gl_FragColor = vec4(1.0); +#endif +} + +*/ + diff --git a/platform/gfx/gl/src/mbgl/programs/gl/circle.cpp b/platform/gfx/gl/src/mbgl/programs/gl/circle.cpp new file mode 100644 index 0000000000..bd86c0385a --- /dev/null +++ b/platform/gfx/gl/src/mbgl/programs/gl/circle.cpp @@ -0,0 +1,320 @@ +// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. + +#include <mbgl/programs/circle_program.hpp> +#include <mbgl/programs/gl/preludes.hpp> +#include <mbgl/programs/gl/shader_source.hpp> +#include <mbgl/gl/program.hpp> + +namespace mbgl { +namespace programs { +namespace gl { + +template <typename> +struct ShaderSource; + +template <> +struct ShaderSource<CircleProgram> { + static constexpr const char* name = "circle"; + static constexpr const uint8_t hash[8] = { 0x1d, 0x47, 0x35, 0xbb, 0x94, 0x3d, 0x93, 0xca }; + static constexpr const auto vertexOffset = 2927; + static constexpr const auto fragmentOffset = 6135; +}; + +constexpr const char* ShaderSource<CircleProgram>::name; +constexpr const uint8_t ShaderSource<CircleProgram>::hash[8]; + +} // namespace gl +} // namespace programs + +namespace gfx { + +template <> +std::unique_ptr<gfx::Program<CircleProgram>> +Backend::Create<gfx::Backend::Type::OpenGL>(const ProgramParameters& programParameters) { + return std::make_unique<gl::Program<CircleProgram>>(programParameters); +} + +} // namespace gfx +} // namespace mbgl + +// Uncompressed source of circle.vertex.glsl: +/* +uniform mat4 u_matrix; +uniform bool u_scale_with_map; +uniform bool u_pitch_with_map; +uniform vec2 u_extrude_scale; +uniform lowp float u_device_pixel_ratio; +uniform highp float u_camera_to_center_distance; + +attribute vec2 a_pos; + +varying vec3 v_data; + + +#ifndef HAS_UNIFORM_u_color +uniform lowp float u_color_t; +attribute highp vec4 a_color; +varying highp vec4 color; +#else +uniform highp vec4 u_color; +#endif + + +#ifndef HAS_UNIFORM_u_radius +uniform lowp float u_radius_t; +attribute mediump vec2 a_radius; +varying mediump float radius; +#else +uniform mediump float u_radius; +#endif + + +#ifndef HAS_UNIFORM_u_blur +uniform lowp float u_blur_t; +attribute lowp vec2 a_blur; +varying lowp float blur; +#else +uniform lowp float u_blur; +#endif + + +#ifndef HAS_UNIFORM_u_opacity +uniform lowp float u_opacity_t; +attribute lowp vec2 a_opacity; +varying lowp float opacity; +#else +uniform lowp float u_opacity; +#endif + + +#ifndef HAS_UNIFORM_u_stroke_color +uniform lowp float u_stroke_color_t; +attribute highp vec4 a_stroke_color; +varying highp vec4 stroke_color; +#else +uniform highp vec4 u_stroke_color; +#endif + + +#ifndef HAS_UNIFORM_u_stroke_width +uniform lowp float u_stroke_width_t; +attribute mediump vec2 a_stroke_width; +varying mediump float stroke_width; +#else +uniform mediump float u_stroke_width; +#endif + + +#ifndef HAS_UNIFORM_u_stroke_opacity +uniform lowp float u_stroke_opacity_t; +attribute lowp vec2 a_stroke_opacity; +varying lowp float stroke_opacity; +#else +uniform lowp float u_stroke_opacity; +#endif + + +void main(void) { + +#ifndef HAS_UNIFORM_u_color + color = unpack_mix_color(a_color, u_color_t); +#else + highp vec4 color = u_color; +#endif + + +#ifndef HAS_UNIFORM_u_radius + radius = unpack_mix_vec2(a_radius, u_radius_t); +#else + mediump float radius = u_radius; +#endif + + +#ifndef HAS_UNIFORM_u_blur + blur = unpack_mix_vec2(a_blur, u_blur_t); +#else + lowp float blur = u_blur; +#endif + + +#ifndef HAS_UNIFORM_u_opacity + opacity = unpack_mix_vec2(a_opacity, u_opacity_t); +#else + lowp float opacity = u_opacity; +#endif + + +#ifndef HAS_UNIFORM_u_stroke_color + stroke_color = unpack_mix_color(a_stroke_color, u_stroke_color_t); +#else + highp vec4 stroke_color = u_stroke_color; +#endif + + +#ifndef HAS_UNIFORM_u_stroke_width + stroke_width = unpack_mix_vec2(a_stroke_width, u_stroke_width_t); +#else + mediump float stroke_width = u_stroke_width; +#endif + + +#ifndef HAS_UNIFORM_u_stroke_opacity + stroke_opacity = unpack_mix_vec2(a_stroke_opacity, u_stroke_opacity_t); +#else + lowp float stroke_opacity = u_stroke_opacity; +#endif + + + // unencode the extrusion vector that we snuck into the a_pos vector + vec2 extrude = vec2(mod(a_pos, 2.0) * 2.0 - 1.0); + + // multiply a_pos by 0.5, since we had it * 2 in order to sneak + // in extrusion data + vec2 circle_center = floor(a_pos * 0.5); + if (u_pitch_with_map) { + vec2 corner_position = circle_center; + if (u_scale_with_map) { + corner_position += extrude * (radius + stroke_width) * u_extrude_scale; + } else { + // Pitching the circle with the map effectively scales it with the map + // To counteract the effect for pitch-scale: viewport, we rescale the + // whole circle based on the pitch scaling effect at its central point + vec4 projected_center = u_matrix * vec4(circle_center, 0, 1); + corner_position += extrude * (radius + stroke_width) * u_extrude_scale * (projected_center.w / u_camera_to_center_distance); + } + + gl_Position = u_matrix * vec4(corner_position, 0, 1); + } else { + gl_Position = u_matrix * vec4(circle_center, 0, 1); + + if (u_scale_with_map) { + gl_Position.xy += extrude * (radius + stroke_width) * u_extrude_scale * u_camera_to_center_distance; + } else { + gl_Position.xy += extrude * (radius + stroke_width) * u_extrude_scale * gl_Position.w; + } + } + + // This is a minimum blur distance that serves as a faux-antialiasing for + // the circle. since blur is a ratio of the circle's size and the intent is + // to keep the blur at roughly 1px, the two are inversely related. + lowp float antialiasblur = 1.0 / u_device_pixel_ratio / (radius + stroke_width); + + v_data = vec3(extrude.x, extrude.y, antialiasblur); +} + +*/ + +// Uncompressed source of circle.fragment.glsl: +/* +varying vec3 v_data; + + +#ifndef HAS_UNIFORM_u_color +varying highp vec4 color; +#else +uniform highp vec4 u_color; +#endif + + +#ifndef HAS_UNIFORM_u_radius +varying mediump float radius; +#else +uniform mediump float u_radius; +#endif + + +#ifndef HAS_UNIFORM_u_blur +varying lowp float blur; +#else +uniform lowp float u_blur; +#endif + + +#ifndef HAS_UNIFORM_u_opacity +varying lowp float opacity; +#else +uniform lowp float u_opacity; +#endif + + +#ifndef HAS_UNIFORM_u_stroke_color +varying highp vec4 stroke_color; +#else +uniform highp vec4 u_stroke_color; +#endif + + +#ifndef HAS_UNIFORM_u_stroke_width +varying mediump float stroke_width; +#else +uniform mediump float u_stroke_width; +#endif + + +#ifndef HAS_UNIFORM_u_stroke_opacity +varying lowp float stroke_opacity; +#else +uniform lowp float u_stroke_opacity; +#endif + + +void main() { + +#ifdef HAS_UNIFORM_u_color + highp vec4 color = u_color; +#endif + + +#ifdef HAS_UNIFORM_u_radius + mediump float radius = u_radius; +#endif + + +#ifdef HAS_UNIFORM_u_blur + lowp float blur = u_blur; +#endif + + +#ifdef HAS_UNIFORM_u_opacity + lowp float opacity = u_opacity; +#endif + + +#ifdef HAS_UNIFORM_u_stroke_color + highp vec4 stroke_color = u_stroke_color; +#endif + + +#ifdef HAS_UNIFORM_u_stroke_width + mediump float stroke_width = u_stroke_width; +#endif + + +#ifdef HAS_UNIFORM_u_stroke_opacity + lowp float stroke_opacity = u_stroke_opacity; +#endif + + + vec2 extrude = v_data.xy; + float extrude_length = length(extrude); + + lowp float antialiasblur = v_data.z; + float antialiased_blur = -max(blur, antialiasblur); + + float opacity_t = smoothstep(0.0, antialiased_blur, extrude_length - 1.0); + + float color_t = stroke_width < 0.01 ? 0.0 : smoothstep( + antialiased_blur, + 0.0, + extrude_length - radius / (radius + stroke_width) + ); + + gl_FragColor = opacity_t * mix(color * opacity, stroke_color * stroke_opacity, color_t); + +#ifdef OVERDRAW_INSPECTOR + gl_FragColor = vec4(1.0); +#endif +} + +*/ + diff --git a/platform/gfx/gl/src/mbgl/programs/gl/clipping_mask.cpp b/platform/gfx/gl/src/mbgl/programs/gl/clipping_mask.cpp new file mode 100644 index 0000000000..2c53bc6070 --- /dev/null +++ b/platform/gfx/gl/src/mbgl/programs/gl/clipping_mask.cpp @@ -0,0 +1,59 @@ +// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. + +#include <mbgl/programs/clipping_mask_program.hpp> +#include <mbgl/programs/gl/preludes.hpp> +#include <mbgl/programs/gl/shader_source.hpp> +#include <mbgl/gl/program.hpp> + +namespace mbgl { +namespace programs { +namespace gl { + +template <typename> +struct ShaderSource; + +template <> +struct ShaderSource<ClippingMaskProgram> { + static constexpr const char* name = "clipping_mask"; + static constexpr const uint8_t hash[8] = { 0x3e, 0x17, 0xc2, 0x3a, 0x1f, 0xf0, 0xa8, 0xa3 }; + static constexpr const auto vertexOffset = 7891; + static constexpr const auto fragmentOffset = 7987; +}; + +constexpr const char* ShaderSource<ClippingMaskProgram>::name; +constexpr const uint8_t ShaderSource<ClippingMaskProgram>::hash[8]; + +} // namespace gl +} // namespace programs + +namespace gfx { + +template <> +std::unique_ptr<gfx::Program<ClippingMaskProgram>> +Backend::Create<gfx::Backend::Type::OpenGL>(const ProgramParameters& programParameters) { + return std::make_unique<gl::Program<ClippingMaskProgram>>(programParameters); +} + +} // namespace gfx +} // namespace mbgl + +// Uncompressed source of clipping_mask.vertex.glsl: +/* +attribute vec2 a_pos; + +uniform mat4 u_matrix; + +void main() { + gl_Position = u_matrix * vec4(a_pos, 0, 1); +} + +*/ + +// Uncompressed source of clipping_mask.fragment.glsl: +/* +void main() { + gl_FragColor = vec4(1.0); +} + +*/ + diff --git a/platform/gfx/gl/src/mbgl/programs/gl/collision_box.cpp b/platform/gfx/gl/src/mbgl/programs/gl/collision_box.cpp new file mode 100644 index 0000000000..a3ad030f5c --- /dev/null +++ b/platform/gfx/gl/src/mbgl/programs/gl/collision_box.cpp @@ -0,0 +1,96 @@ +// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. + +#include <mbgl/programs/collision_box_program.hpp> +#include <mbgl/programs/gl/preludes.hpp> +#include <mbgl/programs/gl/shader_source.hpp> +#include <mbgl/gl/program.hpp> + +namespace mbgl { +namespace programs { +namespace gl { + +template <typename> +struct ShaderSource; + +template <> +struct ShaderSource<CollisionBoxProgram> { + static constexpr const char* name = "collision_box"; + static constexpr const uint8_t hash[8] = { 0xcb, 0x6a, 0x9b, 0xd1, 0x1f, 0x31, 0xf8, 0x5b }; + static constexpr const auto vertexOffset = 10000; + static constexpr const auto fragmentOffset = 10679; +}; + +constexpr const char* ShaderSource<CollisionBoxProgram>::name; +constexpr const uint8_t ShaderSource<CollisionBoxProgram>::hash[8]; + +} // namespace gl +} // namespace programs + +namespace gfx { + +template <> +std::unique_ptr<gfx::Program<CollisionBoxProgram>> +Backend::Create<gfx::Backend::Type::OpenGL>(const ProgramParameters& programParameters) { + return std::make_unique<gl::Program<CollisionBoxProgram>>(programParameters); +} + +} // namespace gfx +} // namespace mbgl + +// Uncompressed source of collision_box.vertex.glsl: +/* +attribute vec2 a_pos; +attribute vec2 a_anchor_pos; +attribute vec2 a_extrude; +attribute vec2 a_placed; +attribute vec2 a_shift; + +uniform mat4 u_matrix; +uniform vec2 u_extrude_scale; +uniform float u_camera_to_center_distance; + +varying float v_placed; +varying float v_notUsed; + +void main() { + vec4 projectedPoint = u_matrix * vec4(a_anchor_pos, 0, 1); + highp float camera_to_anchor_distance = projectedPoint.w; + highp float collision_perspective_ratio = clamp( + 0.5 + 0.5 * (u_camera_to_center_distance / camera_to_anchor_distance), + 0.0, // Prevents oversized near-field boxes in pitched/overzoomed tiles + 4.0); + + gl_Position = u_matrix * vec4(a_pos, 0.0, 1.0); + gl_Position.xy += (a_extrude + a_shift) * u_extrude_scale * gl_Position.w * collision_perspective_ratio; + + v_placed = a_placed.x; + v_notUsed = a_placed.y; +} + +*/ + +// Uncompressed source of collision_box.fragment.glsl: +/* + +varying float v_placed; +varying float v_notUsed; + +void main() { + + float alpha = 0.5; + + // Red = collision, hide label + gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0) * alpha; + + // Blue = no collision, label is showing + if (v_placed > 0.5) { + gl_FragColor = vec4(0.0, 0.0, 1.0, 0.5) * alpha; + } + + if (v_notUsed > 0.5) { + // This box not used, fade it out + gl_FragColor *= .1; + } +} +*/ + diff --git a/platform/gfx/gl/src/mbgl/programs/gl/collision_circle.cpp b/platform/gfx/gl/src/mbgl/programs/gl/collision_circle.cpp new file mode 100644 index 0000000000..3878122f4b --- /dev/null +++ b/platform/gfx/gl/src/mbgl/programs/gl/collision_circle.cpp @@ -0,0 +1,119 @@ +// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. + +#include <mbgl/programs/collision_circle_program.hpp> +#include <mbgl/programs/gl/preludes.hpp> +#include <mbgl/programs/gl/shader_source.hpp> +#include <mbgl/gl/program.hpp> + +namespace mbgl { +namespace programs { +namespace gl { + +template <typename> +struct ShaderSource; + +template <> +struct ShaderSource<CollisionCircleProgram> { + static constexpr const char* name = "collision_circle"; + static constexpr const uint8_t hash[8] = { 0x99, 0x2e, 0xad, 0x8c, 0xd3, 0x88, 0xae, 0x82 }; + static constexpr const auto vertexOffset = 10902; + static constexpr const auto fragmentOffset = 11818; +}; + +constexpr const char* ShaderSource<CollisionCircleProgram>::name; +constexpr const uint8_t ShaderSource<CollisionCircleProgram>::hash[8]; + +} // namespace gl +} // namespace programs + +namespace gfx { + +template <> +std::unique_ptr<gfx::Program<CollisionCircleProgram>> +Backend::Create<gfx::Backend::Type::OpenGL>(const ProgramParameters& programParameters) { + return std::make_unique<gl::Program<CollisionCircleProgram>>(programParameters); +} + +} // namespace gfx +} // namespace mbgl + +// Uncompressed source of collision_circle.vertex.glsl: +/* +attribute vec2 a_pos; +attribute vec2 a_anchor_pos; +attribute vec2 a_extrude; +attribute vec2 a_placed; + +uniform mat4 u_matrix; +uniform vec2 u_extrude_scale; +uniform float u_camera_to_center_distance; + +varying float v_placed; +varying float v_notUsed; +varying float v_radius; + +varying vec2 v_extrude; +varying vec2 v_extrude_scale; + +void main() { + vec4 projectedPoint = u_matrix * vec4(a_anchor_pos, 0, 1); + highp float camera_to_anchor_distance = projectedPoint.w; + highp float collision_perspective_ratio = clamp( + 0.5 + 0.5 * (u_camera_to_center_distance / camera_to_anchor_distance), + 0.0, // Prevents oversized near-field circles in pitched/overzoomed tiles + 4.0); + + gl_Position = u_matrix * vec4(a_pos, 0.0, 1.0); + + highp float padding_factor = 1.2; // Pad the vertices slightly to make room for anti-alias blur + gl_Position.xy += a_extrude * u_extrude_scale * padding_factor * gl_Position.w * collision_perspective_ratio; + + v_placed = a_placed.x; + v_notUsed = a_placed.y; + v_radius = abs(a_extrude.y); // We don't pitch the circles, so both units of the extrusion vector are equal in magnitude to the radius + + v_extrude = a_extrude * padding_factor; + v_extrude_scale = u_extrude_scale * u_camera_to_center_distance * collision_perspective_ratio; +} + +*/ + +// Uncompressed source of collision_circle.fragment.glsl: +/* +uniform float u_overscale_factor; + +varying float v_placed; +varying float v_notUsed; +varying float v_radius; +varying vec2 v_extrude; +varying vec2 v_extrude_scale; + +void main() { + float alpha = 0.5; + + // Red = collision, hide label + vec4 color = vec4(1.0, 0.0, 0.0, 1.0) * alpha; + + // Blue = no collision, label is showing + if (v_placed > 0.5) { + color = vec4(0.0, 0.0, 1.0, 0.5) * alpha; + } + + if (v_notUsed > 0.5) { + // This box not used, fade it out + color *= .2; + } + + float extrude_scale_length = length(v_extrude_scale); + float extrude_length = length(v_extrude) * extrude_scale_length; + float stroke_width = 15.0 * extrude_scale_length / u_overscale_factor; + float radius = v_radius * extrude_scale_length; + + float distance_to_edge = abs(extrude_length - radius); + float opacity_t = smoothstep(-stroke_width, 0.0, -distance_to_edge); + + gl_FragColor = opacity_t * color; +} + +*/ + diff --git a/platform/gfx/gl/src/mbgl/programs/gl/debug.cpp b/platform/gfx/gl/src/mbgl/programs/gl/debug.cpp new file mode 100644 index 0000000000..9705fc4801 --- /dev/null +++ b/platform/gfx/gl/src/mbgl/programs/gl/debug.cpp @@ -0,0 +1,61 @@ +// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. + +#include <mbgl/programs/debug_program.hpp> +#include <mbgl/programs/gl/preludes.hpp> +#include <mbgl/programs/gl/shader_source.hpp> +#include <mbgl/gl/program.hpp> + +namespace mbgl { +namespace programs { +namespace gl { + +template <typename> +struct ShaderSource; + +template <> +struct ShaderSource<DebugProgram> { + static constexpr const char* name = "debug"; + static constexpr const uint8_t hash[8] = { 0xa8, 0x7d, 0x87, 0x6e, 0x36, 0xa8, 0x81, 0xe3 }; + static constexpr const auto vertexOffset = 12494; + static constexpr const auto fragmentOffset = 12590; +}; + +constexpr const char* ShaderSource<DebugProgram>::name; +constexpr const uint8_t ShaderSource<DebugProgram>::hash[8]; + +} // namespace gl +} // namespace programs + +namespace gfx { + +template <> +std::unique_ptr<gfx::Program<DebugProgram>> +Backend::Create<gfx::Backend::Type::OpenGL>(const ProgramParameters& programParameters) { + return std::make_unique<gl::Program<DebugProgram>>(programParameters); +} + +} // namespace gfx +} // namespace mbgl + +// Uncompressed source of debug.vertex.glsl: +/* +attribute vec2 a_pos; + +uniform mat4 u_matrix; + +void main() { + gl_Position = u_matrix * vec4(a_pos, 0, 1); +} + +*/ + +// Uncompressed source of debug.fragment.glsl: +/* +uniform highp vec4 u_color; + +void main() { + gl_FragColor = u_color; +} + +*/ + diff --git a/platform/gfx/gl/src/mbgl/programs/gl/fill.cpp b/platform/gfx/gl/src/mbgl/programs/gl/fill.cpp new file mode 100644 index 0000000000..77c839850b --- /dev/null +++ b/platform/gfx/gl/src/mbgl/programs/gl/fill.cpp @@ -0,0 +1,123 @@ +// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. + +#include <mbgl/programs/fill_program.hpp> +#include <mbgl/programs/gl/preludes.hpp> +#include <mbgl/programs/gl/shader_source.hpp> +#include <mbgl/gl/program.hpp> + +namespace mbgl { +namespace programs { +namespace gl { + +template <typename> +struct ShaderSource; + +template <> +struct ShaderSource<FillProgram> { + static constexpr const char* name = "fill"; + static constexpr const uint8_t hash[8] = { 0x87, 0xea, 0x65, 0x7f, 0x0c, 0x9b, 0x97, 0x5d }; + static constexpr const auto vertexOffset = 12654; + static constexpr const auto fragmentOffset = 13298; +}; + +constexpr const char* ShaderSource<FillProgram>::name; +constexpr const uint8_t ShaderSource<FillProgram>::hash[8]; + +} // namespace gl +} // namespace programs + +namespace gfx { + +template <> +std::unique_ptr<gfx::Program<FillProgram>> +Backend::Create<gfx::Backend::Type::OpenGL>(const ProgramParameters& programParameters) { + return std::make_unique<gl::Program<FillProgram>>(programParameters); +} + +} // namespace gfx +} // namespace mbgl + +// Uncompressed source of fill.vertex.glsl: +/* +attribute vec2 a_pos; + +uniform mat4 u_matrix; + + +#ifndef HAS_UNIFORM_u_color +uniform lowp float u_color_t; +attribute highp vec4 a_color; +varying highp vec4 color; +#else +uniform highp vec4 u_color; +#endif + + +#ifndef HAS_UNIFORM_u_opacity +uniform lowp float u_opacity_t; +attribute lowp vec2 a_opacity; +varying lowp float opacity; +#else +uniform lowp float u_opacity; +#endif + + +void main() { + +#ifndef HAS_UNIFORM_u_color + color = unpack_mix_color(a_color, u_color_t); +#else + highp vec4 color = u_color; +#endif + + +#ifndef HAS_UNIFORM_u_opacity + opacity = unpack_mix_vec2(a_opacity, u_opacity_t); +#else + lowp float opacity = u_opacity; +#endif + + + gl_Position = u_matrix * vec4(a_pos, 0, 1); +} + +*/ + +// Uncompressed source of fill.fragment.glsl: +/* + +#ifndef HAS_UNIFORM_u_color +varying highp vec4 color; +#else +uniform highp vec4 u_color; +#endif + + +#ifndef HAS_UNIFORM_u_opacity +varying lowp float opacity; +#else +uniform lowp float u_opacity; +#endif + + +void main() { + +#ifdef HAS_UNIFORM_u_color + highp vec4 color = u_color; +#endif + + +#ifdef HAS_UNIFORM_u_opacity + lowp float opacity = u_opacity; +#endif + + + gl_FragColor = color * opacity; + +#ifdef OVERDRAW_INSPECTOR + gl_FragColor = vec4(1.0); +#endif +} + +*/ + diff --git a/platform/gfx/gl/src/mbgl/programs/gl/fill_extrusion.cpp b/platform/gfx/gl/src/mbgl/programs/gl/fill_extrusion.cpp new file mode 100644 index 0000000000..87ef4858fc --- /dev/null +++ b/platform/gfx/gl/src/mbgl/programs/gl/fill_extrusion.cpp @@ -0,0 +1,163 @@ +// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. + +#include <mbgl/programs/fill_extrusion_program.hpp> +#include <mbgl/programs/gl/preludes.hpp> +#include <mbgl/programs/gl/shader_source.hpp> +#include <mbgl/gl/program.hpp> + +namespace mbgl { +namespace programs { +namespace gl { + +template <typename> +struct ShaderSource; + +template <> +struct ShaderSource<FillExtrusionProgram> { + static constexpr const char* name = "fill_extrusion"; + static constexpr const uint8_t hash[8] = { 0x9d, 0x76, 0x7f, 0xaa, 0x86, 0x57, 0x56, 0x96 }; + static constexpr const auto vertexOffset = 21283; + static constexpr const auto fragmentOffset = 23214; +}; + +constexpr const char* ShaderSource<FillExtrusionProgram>::name; +constexpr const uint8_t ShaderSource<FillExtrusionProgram>::hash[8]; + +} // namespace gl +} // namespace programs + +namespace gfx { + +template <> +std::unique_ptr<gfx::Program<FillExtrusionProgram>> +Backend::Create<gfx::Backend::Type::OpenGL>(const ProgramParameters& programParameters) { + return std::make_unique<gl::Program<FillExtrusionProgram>>(programParameters); +} + +} // namespace gfx +} // namespace mbgl + +// Uncompressed source of fill_extrusion.vertex.glsl: +/* +uniform mat4 u_matrix; +uniform vec3 u_lightcolor; +uniform lowp vec3 u_lightpos; +uniform lowp float u_lightintensity; +uniform float u_vertical_gradient; +uniform lowp float u_opacity; + +attribute vec2 a_pos; +attribute vec4 a_normal_ed; + +varying vec4 v_color; + + +#ifndef HAS_UNIFORM_u_base +uniform lowp float u_base_t; +attribute highp vec2 a_base; +#else +uniform highp float u_base; +#endif + + +#ifndef HAS_UNIFORM_u_height +uniform lowp float u_height_t; +attribute highp vec2 a_height; +#else +uniform highp float u_height; +#endif + + + +#ifndef HAS_UNIFORM_u_color +uniform lowp float u_color_t; +attribute highp vec4 a_color; +#else +uniform highp vec4 u_color; +#endif + + +void main() { + +#ifndef HAS_UNIFORM_u_base + highp float base = unpack_mix_vec2(a_base, u_base_t); +#else + highp float base = u_base; +#endif + + +#ifndef HAS_UNIFORM_u_height + highp float height = unpack_mix_vec2(a_height, u_height_t); +#else + highp float height = u_height; +#endif + + +#ifndef HAS_UNIFORM_u_color + highp vec4 color = unpack_mix_color(a_color, u_color_t); +#else + highp vec4 color = u_color; +#endif + + + vec3 normal = a_normal_ed.xyz; + + base = max(0.0, base); + height = max(0.0, height); + + float t = mod(normal.x, 2.0); + + gl_Position = u_matrix * vec4(a_pos, t > 0.0 ? height : base, 1); + + // Relative luminance (how dark/bright is the surface color?) + float colorvalue = color.r * 0.2126 + color.g * 0.7152 + color.b * 0.0722; + + v_color = vec4(0.0, 0.0, 0.0, 1.0); + + // Add slight ambient lighting so no extrusions are totally black + vec4 ambientlight = vec4(0.03, 0.03, 0.03, 1.0); + color += ambientlight; + + // Calculate cos(theta), where theta is the angle between surface normal and diffuse light ray + float directional = clamp(dot(normal / 16384.0, u_lightpos), 0.0, 1.0); + + // Adjust directional so that + // the range of values for highlight/shading is narrower + // with lower light intensity + // and with lighter/brighter surface colors + directional = mix((1.0 - u_lightintensity), max((1.0 - colorvalue + u_lightintensity), 1.0), directional); + + // Add gradient along z axis of side surfaces + if (normal.y != 0.0) { + // This avoids another branching statement, but multiplies by a constant of 0.84 if no vertical gradient, + // and otherwise calculates the gradient based on base + height + directional *= ( + (1.0 - u_vertical_gradient) + + (u_vertical_gradient * clamp((t + base) * pow(height / 150.0, 0.5), mix(0.7, 0.98, 1.0 - u_lightintensity), 1.0))); + } + + // Assign final color based on surface + ambient light color, diffuse light directional, and light color + // with lower bounds adjusted to hue of light + // so that shading is tinted with the complementary (opposite) color to the light color + v_color.r += clamp(color.r * directional * u_lightcolor.r, mix(0.0, 0.3, 1.0 - u_lightcolor.r), 1.0); + v_color.g += clamp(color.g * directional * u_lightcolor.g, mix(0.0, 0.3, 1.0 - u_lightcolor.g), 1.0); + v_color.b += clamp(color.b * directional * u_lightcolor.b, mix(0.0, 0.3, 1.0 - u_lightcolor.b), 1.0); + v_color *= u_opacity; +} + +*/ + +// Uncompressed source of fill_extrusion.fragment.glsl: +/* +varying vec4 v_color; + +void main() { + gl_FragColor = v_color; + +#ifdef OVERDRAW_INSPECTOR + gl_FragColor = vec4(1.0); +#endif +} + +*/ + diff --git a/platform/gfx/gl/src/mbgl/programs/gl/fill_extrusion_pattern.cpp b/platform/gfx/gl/src/mbgl/programs/gl/fill_extrusion_pattern.cpp new file mode 100644 index 0000000000..1d330220e4 --- /dev/null +++ b/platform/gfx/gl/src/mbgl/programs/gl/fill_extrusion_pattern.cpp @@ -0,0 +1,262 @@ +// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. + +#include <mbgl/programs/fill_extrusion_pattern_program.hpp> +#include <mbgl/programs/gl/preludes.hpp> +#include <mbgl/programs/gl/shader_source.hpp> +#include <mbgl/gl/program.hpp> + +namespace mbgl { +namespace programs { +namespace gl { + +template <typename> +struct ShaderSource; + +template <> +struct ShaderSource<FillExtrusionPatternProgram> { + static constexpr const char* name = "fill_extrusion_pattern"; + static constexpr const uint8_t hash[8] = { 0x5a, 0x8f, 0x1a, 0xbf, 0x43, 0x62, 0xf0, 0x86 }; + static constexpr const auto vertexOffset = 23330; + static constexpr const auto fragmentOffset = 26301; +}; + +constexpr const char* ShaderSource<FillExtrusionPatternProgram>::name; +constexpr const uint8_t ShaderSource<FillExtrusionPatternProgram>::hash[8]; + +} // namespace gl +} // namespace programs + +namespace gfx { + +template <> +std::unique_ptr<gfx::Program<FillExtrusionPatternProgram>> +Backend::Create<gfx::Backend::Type::OpenGL>(const ProgramParameters& programParameters) { + return std::make_unique<gl::Program<FillExtrusionPatternProgram>>(programParameters); +} + +} // namespace gfx +} // namespace mbgl + +// Uncompressed source of fill_extrusion_pattern.vertex.glsl: +/* +uniform mat4 u_matrix; +uniform vec2 u_pixel_coord_upper; +uniform vec2 u_pixel_coord_lower; +uniform float u_height_factor; +uniform vec4 u_scale; +uniform float u_vertical_gradient; +uniform lowp float u_opacity; + +uniform vec3 u_lightcolor; +uniform lowp vec3 u_lightpos; +uniform lowp float u_lightintensity; + +attribute vec2 a_pos; +attribute vec4 a_normal_ed; + +varying vec2 v_pos_a; +varying vec2 v_pos_b; +varying vec4 v_lighting; + + +#ifndef HAS_UNIFORM_u_base +uniform lowp float u_base_t; +attribute lowp vec2 a_base; +varying lowp float base; +#else +uniform lowp float u_base; +#endif + + +#ifndef HAS_UNIFORM_u_height +uniform lowp float u_height_t; +attribute lowp vec2 a_height; +varying lowp float height; +#else +uniform lowp float u_height; +#endif + + +#ifndef HAS_UNIFORM_u_pattern_from +uniform lowp float u_pattern_from_t; +attribute lowp vec4 a_pattern_from; +varying lowp vec4 pattern_from; +#else +uniform lowp vec4 u_pattern_from; +#endif + + +#ifndef HAS_UNIFORM_u_pattern_to +uniform lowp float u_pattern_to_t; +attribute lowp vec4 a_pattern_to; +varying lowp vec4 pattern_to; +#else +uniform lowp vec4 u_pattern_to; +#endif + + +void main() { + +#ifndef HAS_UNIFORM_u_base + base = unpack_mix_vec2(a_base, u_base_t); +#else + lowp float base = u_base; +#endif + + +#ifndef HAS_UNIFORM_u_height + height = unpack_mix_vec2(a_height, u_height_t); +#else + lowp float height = u_height; +#endif + + +#ifndef HAS_UNIFORM_u_pattern_from + pattern_from = a_pattern_from; +#else + mediump vec4 pattern_from = u_pattern_from; +#endif + + +#ifndef HAS_UNIFORM_u_pattern_to + pattern_to = a_pattern_to; +#else + mediump vec4 pattern_to = u_pattern_to; +#endif + + + vec2 pattern_tl_a = pattern_from.xy; + vec2 pattern_br_a = pattern_from.zw; + vec2 pattern_tl_b = pattern_to.xy; + vec2 pattern_br_b = pattern_to.zw; + + float pixelRatio = u_scale.x; + float tileRatio = u_scale.y; + float fromScale = u_scale.z; + float toScale = u_scale.w; + + vec3 normal = a_normal_ed.xyz; + float edgedistance = a_normal_ed.w; + + vec2 display_size_a = vec2((pattern_br_a.x - pattern_tl_a.x) / pixelRatio, (pattern_br_a.y - pattern_tl_a.y) / pixelRatio); + vec2 display_size_b = vec2((pattern_br_b.x - pattern_tl_b.x) / pixelRatio, (pattern_br_b.y - pattern_tl_b.y) / pixelRatio); + + base = max(0.0, base); + height = max(0.0, height); + + float t = mod(normal.x, 2.0); + float z = t > 0.0 ? height : base; + + gl_Position = u_matrix * vec4(a_pos, z, 1); + + vec2 pos = normal.x == 1.0 && normal.y == 0.0 && normal.z == 16384.0 + ? a_pos // extrusion top + : vec2(edgedistance, z * u_height_factor); // extrusion side + + v_pos_a = get_pattern_pos(u_pixel_coord_upper, u_pixel_coord_lower, fromScale * display_size_a, tileRatio, pos); + v_pos_b = get_pattern_pos(u_pixel_coord_upper, u_pixel_coord_lower, toScale * display_size_b, tileRatio, pos); + + v_lighting = vec4(0.0, 0.0, 0.0, 1.0); + float directional = clamp(dot(normal / 16383.0, u_lightpos), 0.0, 1.0); + directional = mix((1.0 - u_lightintensity), max((0.5 + u_lightintensity), 1.0), directional); + + if (normal.y != 0.0) { + // This avoids another branching statement, but multiplies by a constant of 0.84 if no vertical gradient, + // and otherwise calculates the gradient based on base + height + directional *= ( + (1.0 - u_vertical_gradient) + + (u_vertical_gradient * clamp((t + base) * pow(height / 150.0, 0.5), mix(0.7, 0.98, 1.0 - u_lightintensity), 1.0))); + } + + v_lighting.rgb += clamp(directional * u_lightcolor, mix(vec3(0.0), vec3(0.3), 1.0 - u_lightcolor), vec3(1.0)); + v_lighting *= u_opacity; +} + +*/ + +// Uncompressed source of fill_extrusion_pattern.fragment.glsl: +/* +uniform vec2 u_texsize; +uniform float u_fade; + +uniform sampler2D u_image; + +varying vec2 v_pos_a; +varying vec2 v_pos_b; +varying vec4 v_lighting; + + +#ifndef HAS_UNIFORM_u_base +varying lowp float base; +#else +uniform lowp float u_base; +#endif + + +#ifndef HAS_UNIFORM_u_height +varying lowp float height; +#else +uniform lowp float u_height; +#endif + + +#ifndef HAS_UNIFORM_u_pattern_from +varying lowp vec4 pattern_from; +#else +uniform lowp vec4 u_pattern_from; +#endif + + +#ifndef HAS_UNIFORM_u_pattern_to +varying lowp vec4 pattern_to; +#else +uniform lowp vec4 u_pattern_to; +#endif + + +void main() { + +#ifdef HAS_UNIFORM_u_base + lowp float base = u_base; +#endif + + +#ifdef HAS_UNIFORM_u_height + lowp float height = u_height; +#endif + + +#ifdef HAS_UNIFORM_u_pattern_from + mediump vec4 pattern_from = u_pattern_from; +#endif + + +#ifdef HAS_UNIFORM_u_pattern_to + mediump vec4 pattern_to = u_pattern_to; +#endif + + + vec2 pattern_tl_a = pattern_from.xy; + vec2 pattern_br_a = pattern_from.zw; + vec2 pattern_tl_b = pattern_to.xy; + vec2 pattern_br_b = pattern_to.zw; + + vec2 imagecoord = mod(v_pos_a, 1.0); + vec2 pos = mix(pattern_tl_a / u_texsize, pattern_br_a / u_texsize, imagecoord); + vec4 color1 = texture2D(u_image, pos); + + vec2 imagecoord_b = mod(v_pos_b, 1.0); + vec2 pos2 = mix(pattern_tl_b / u_texsize, pattern_br_b / u_texsize, imagecoord_b); + vec4 color2 = texture2D(u_image, pos2); + + vec4 mixedColor = mix(color1, color2, u_fade); + + gl_FragColor = mixedColor * v_lighting; + +#ifdef OVERDRAW_INSPECTOR + gl_FragColor = vec4(1.0); +#endif +} + +*/ + diff --git a/platform/gfx/gl/src/mbgl/programs/gl/fill_outline.cpp b/platform/gfx/gl/src/mbgl/programs/gl/fill_outline.cpp new file mode 100644 index 0000000000..efef689f91 --- /dev/null +++ b/platform/gfx/gl/src/mbgl/programs/gl/fill_outline.cpp @@ -0,0 +1,131 @@ +// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. + +#include <mbgl/programs/fill_outline_program.hpp> +#include <mbgl/programs/gl/preludes.hpp> +#include <mbgl/programs/gl/shader_source.hpp> +#include <mbgl/gl/program.hpp> + +namespace mbgl { +namespace programs { +namespace gl { + +template <typename> +struct ShaderSource; + +template <> +struct ShaderSource<FillOutlineProgram> { + static constexpr const char* name = "fill_outline"; + static constexpr const uint8_t hash[8] = { 0x51, 0x25, 0x43, 0x9d, 0x41, 0x73, 0xe1, 0xbb }; + static constexpr const auto vertexOffset = 13722; + static constexpr const auto fragmentOffset = 14547; +}; + +constexpr const char* ShaderSource<FillOutlineProgram>::name; +constexpr const uint8_t ShaderSource<FillOutlineProgram>::hash[8]; + +} // namespace gl +} // namespace programs + +namespace gfx { + +template <> +std::unique_ptr<gfx::Program<FillOutlineProgram>> +Backend::Create<gfx::Backend::Type::OpenGL>(const ProgramParameters& programParameters) { + return std::make_unique<gl::Program<FillOutlineProgram>>(programParameters); +} + +} // namespace gfx +} // namespace mbgl + +// Uncompressed source of fill_outline.vertex.glsl: +/* +attribute vec2 a_pos; + +uniform mat4 u_matrix; +uniform vec2 u_world; + +varying vec2 v_pos; + + +#ifndef HAS_UNIFORM_u_outline_color +uniform lowp float u_outline_color_t; +attribute highp vec4 a_outline_color; +varying highp vec4 outline_color; +#else +uniform highp vec4 u_outline_color; +#endif + + +#ifndef HAS_UNIFORM_u_opacity +uniform lowp float u_opacity_t; +attribute lowp vec2 a_opacity; +varying lowp float opacity; +#else +uniform lowp float u_opacity; +#endif + + +void main() { + +#ifndef HAS_UNIFORM_u_outline_color + outline_color = unpack_mix_color(a_outline_color, u_outline_color_t); +#else + highp vec4 outline_color = u_outline_color; +#endif + + +#ifndef HAS_UNIFORM_u_opacity + opacity = unpack_mix_vec2(a_opacity, u_opacity_t); +#else + lowp float opacity = u_opacity; +#endif + + + gl_Position = u_matrix * vec4(a_pos, 0, 1); + v_pos = (gl_Position.xy / gl_Position.w + 1.0) / 2.0 * u_world; +} + +*/ + +// Uncompressed source of fill_outline.fragment.glsl: +/* +varying vec2 v_pos; + + +#ifndef HAS_UNIFORM_u_outline_color +varying highp vec4 outline_color; +#else +uniform highp vec4 u_outline_color; +#endif + + +#ifndef HAS_UNIFORM_u_opacity +varying lowp float opacity; +#else +uniform lowp float u_opacity; +#endif + + +void main() { + +#ifdef HAS_UNIFORM_u_outline_color + highp vec4 outline_color = u_outline_color; +#endif + + +#ifdef HAS_UNIFORM_u_opacity + lowp float opacity = u_opacity; +#endif + + + float dist = length(v_pos - gl_FragCoord.xy); + float alpha = 1.0 - smoothstep(0.0, 1.0, dist); + gl_FragColor = outline_color * (alpha * opacity); + +#ifdef OVERDRAW_INSPECTOR + gl_FragColor = vec4(1.0); +#endif +} + +*/ + diff --git a/platform/gfx/gl/src/mbgl/programs/gl/fill_outline_pattern.cpp b/platform/gfx/gl/src/mbgl/programs/gl/fill_outline_pattern.cpp new file mode 100644 index 0000000000..d526d5801d --- /dev/null +++ b/platform/gfx/gl/src/mbgl/programs/gl/fill_outline_pattern.cpp @@ -0,0 +1,205 @@ +// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. + +#include <mbgl/programs/fill_outline_pattern_program.hpp> +#include <mbgl/programs/gl/preludes.hpp> +#include <mbgl/programs/gl/shader_source.hpp> +#include <mbgl/gl/program.hpp> + +namespace mbgl { +namespace programs { +namespace gl { + +template <typename> +struct ShaderSource; + +template <> +struct ShaderSource<FillOutlinePatternProgram> { + static constexpr const char* name = "fill_outline_pattern"; + static constexpr const uint8_t hash[8] = { 0x56, 0x9c, 0x2f, 0x58, 0x6b, 0x31, 0xff, 0x84 }; + static constexpr const auto vertexOffset = 15137; + static constexpr const auto fragmentOffset = 16997; +}; + +constexpr const char* ShaderSource<FillOutlinePatternProgram>::name; +constexpr const uint8_t ShaderSource<FillOutlinePatternProgram>::hash[8]; + +} // namespace gl +} // namespace programs + +namespace gfx { + +template <> +std::unique_ptr<gfx::Program<FillOutlinePatternProgram>> +Backend::Create<gfx::Backend::Type::OpenGL>(const ProgramParameters& programParameters) { + return std::make_unique<gl::Program<FillOutlinePatternProgram>>(programParameters); +} + +} // namespace gfx +} // namespace mbgl + +// Uncompressed source of fill_outline_pattern.vertex.glsl: +/* +uniform mat4 u_matrix; +uniform vec2 u_world; +uniform vec2 u_pixel_coord_upper; +uniform vec2 u_pixel_coord_lower; +uniform vec4 u_scale; + +attribute vec2 a_pos; + +varying vec2 v_pos_a; +varying vec2 v_pos_b; +varying vec2 v_pos; + + +#ifndef HAS_UNIFORM_u_opacity +uniform lowp float u_opacity_t; +attribute lowp vec2 a_opacity; +varying lowp float opacity; +#else +uniform lowp float u_opacity; +#endif + + +#ifndef HAS_UNIFORM_u_pattern_from +uniform lowp float u_pattern_from_t; +attribute lowp vec4 a_pattern_from; +varying lowp vec4 pattern_from; +#else +uniform lowp vec4 u_pattern_from; +#endif + + +#ifndef HAS_UNIFORM_u_pattern_to +uniform lowp float u_pattern_to_t; +attribute lowp vec4 a_pattern_to; +varying lowp vec4 pattern_to; +#else +uniform lowp vec4 u_pattern_to; +#endif + + +void main() { + +#ifndef HAS_UNIFORM_u_opacity + opacity = unpack_mix_vec2(a_opacity, u_opacity_t); +#else + lowp float opacity = u_opacity; +#endif + + +#ifndef HAS_UNIFORM_u_pattern_from + pattern_from = a_pattern_from; +#else + mediump vec4 pattern_from = u_pattern_from; +#endif + + +#ifndef HAS_UNIFORM_u_pattern_to + pattern_to = a_pattern_to; +#else + mediump vec4 pattern_to = u_pattern_to; +#endif + + + vec2 pattern_tl_a = pattern_from.xy; + vec2 pattern_br_a = pattern_from.zw; + vec2 pattern_tl_b = pattern_to.xy; + vec2 pattern_br_b = pattern_to.zw; + + float pixelRatio = u_scale.x; + float tileRatio = u_scale.y; + float fromScale = u_scale.z; + float toScale = u_scale.w; + + gl_Position = u_matrix * vec4(a_pos, 0, 1); + + vec2 display_size_a = vec2((pattern_br_a.x - pattern_tl_a.x) / pixelRatio, (pattern_br_a.y - pattern_tl_a.y) / pixelRatio); + vec2 display_size_b = vec2((pattern_br_b.x - pattern_tl_b.x) / pixelRatio, (pattern_br_b.y - pattern_tl_b.y) / pixelRatio); + + v_pos_a = get_pattern_pos(u_pixel_coord_upper, u_pixel_coord_lower, fromScale * display_size_a, tileRatio, a_pos); + v_pos_b = get_pattern_pos(u_pixel_coord_upper, u_pixel_coord_lower, toScale * display_size_b, tileRatio, a_pos); + + v_pos = (gl_Position.xy / gl_Position.w + 1.0) / 2.0 * u_world; +} + +*/ + +// Uncompressed source of fill_outline_pattern.fragment.glsl: +/* + +uniform vec2 u_texsize; +uniform sampler2D u_image; +uniform float u_fade; + +varying vec2 v_pos_a; +varying vec2 v_pos_b; +varying vec2 v_pos; + + +#ifndef HAS_UNIFORM_u_opacity +varying lowp float opacity; +#else +uniform lowp float u_opacity; +#endif + + +#ifndef HAS_UNIFORM_u_pattern_from +varying lowp vec4 pattern_from; +#else +uniform lowp vec4 u_pattern_from; +#endif + + +#ifndef HAS_UNIFORM_u_pattern_to +varying lowp vec4 pattern_to; +#else +uniform lowp vec4 u_pattern_to; +#endif + + +void main() { + +#ifdef HAS_UNIFORM_u_opacity + lowp float opacity = u_opacity; +#endif + + +#ifdef HAS_UNIFORM_u_pattern_from + mediump vec4 pattern_from = u_pattern_from; +#endif + + +#ifdef HAS_UNIFORM_u_pattern_to + mediump vec4 pattern_to = u_pattern_to; +#endif + + + vec2 pattern_tl_a = pattern_from.xy; + vec2 pattern_br_a = pattern_from.zw; + vec2 pattern_tl_b = pattern_to.xy; + vec2 pattern_br_b = pattern_to.zw; + + vec2 imagecoord = mod(v_pos_a, 1.0); + vec2 pos = mix(pattern_tl_a / u_texsize, pattern_br_a / u_texsize, imagecoord); + vec4 color1 = texture2D(u_image, pos); + + vec2 imagecoord_b = mod(v_pos_b, 1.0); + vec2 pos2 = mix(pattern_tl_b / u_texsize, pattern_br_b / u_texsize, imagecoord_b); + vec4 color2 = texture2D(u_image, pos2); + + // find distance to outline for alpha interpolation + + float dist = length(v_pos - gl_FragCoord.xy); + float alpha = 1.0 - smoothstep(0.0, 1.0, dist); + + + gl_FragColor = mix(color1, color2, u_fade) * alpha * opacity; + +#ifdef OVERDRAW_INSPECTOR + gl_FragColor = vec4(1.0); +#endif +} + +*/ + diff --git a/platform/gfx/gl/src/mbgl/programs/gl/fill_pattern.cpp b/platform/gfx/gl/src/mbgl/programs/gl/fill_pattern.cpp new file mode 100644 index 0000000000..0f62206f99 --- /dev/null +++ b/platform/gfx/gl/src/mbgl/programs/gl/fill_pattern.cpp @@ -0,0 +1,193 @@ +// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. + +#include <mbgl/programs/fill_pattern_program.hpp> +#include <mbgl/programs/gl/preludes.hpp> +#include <mbgl/programs/gl/shader_source.hpp> +#include <mbgl/gl/program.hpp> + +namespace mbgl { +namespace programs { +namespace gl { + +template <typename> +struct ShaderSource; + +template <> +struct ShaderSource<FillPatternProgram> { + static constexpr const char* name = "fill_pattern"; + static constexpr const uint8_t hash[8] = { 0x74, 0xa9, 0x97, 0x01, 0x96, 0xbd, 0x87, 0x36 }; + static constexpr const auto vertexOffset = 18304; + static constexpr const auto fragmentOffset = 20083; +}; + +constexpr const char* ShaderSource<FillPatternProgram>::name; +constexpr const uint8_t ShaderSource<FillPatternProgram>::hash[8]; + +} // namespace gl +} // namespace programs + +namespace gfx { + +template <> +std::unique_ptr<gfx::Program<FillPatternProgram>> +Backend::Create<gfx::Backend::Type::OpenGL>(const ProgramParameters& programParameters) { + return std::make_unique<gl::Program<FillPatternProgram>>(programParameters); +} + +} // namespace gfx +} // namespace mbgl + +// Uncompressed source of fill_pattern.vertex.glsl: +/* +uniform mat4 u_matrix; +uniform vec2 u_pixel_coord_upper; +uniform vec2 u_pixel_coord_lower; +uniform vec4 u_scale; + +attribute vec2 a_pos; + +varying vec2 v_pos_a; +varying vec2 v_pos_b; + + +#ifndef HAS_UNIFORM_u_opacity +uniform lowp float u_opacity_t; +attribute lowp vec2 a_opacity; +varying lowp float opacity; +#else +uniform lowp float u_opacity; +#endif + + +#ifndef HAS_UNIFORM_u_pattern_from +uniform lowp float u_pattern_from_t; +attribute lowp vec4 a_pattern_from; +varying lowp vec4 pattern_from; +#else +uniform lowp vec4 u_pattern_from; +#endif + + +#ifndef HAS_UNIFORM_u_pattern_to +uniform lowp float u_pattern_to_t; +attribute lowp vec4 a_pattern_to; +varying lowp vec4 pattern_to; +#else +uniform lowp vec4 u_pattern_to; +#endif + + +void main() { + +#ifndef HAS_UNIFORM_u_opacity + opacity = unpack_mix_vec2(a_opacity, u_opacity_t); +#else + lowp float opacity = u_opacity; +#endif + + +#ifndef HAS_UNIFORM_u_pattern_from + pattern_from = a_pattern_from; +#else + mediump vec4 pattern_from = u_pattern_from; +#endif + + +#ifndef HAS_UNIFORM_u_pattern_to + pattern_to = a_pattern_to; +#else + mediump vec4 pattern_to = u_pattern_to; +#endif + + + vec2 pattern_tl_a = pattern_from.xy; + vec2 pattern_br_a = pattern_from.zw; + vec2 pattern_tl_b = pattern_to.xy; + vec2 pattern_br_b = pattern_to.zw; + + float pixelRatio = u_scale.x; + float tileZoomRatio = u_scale.y; + float fromScale = u_scale.z; + float toScale = u_scale.w; + + vec2 display_size_a = vec2((pattern_br_a.x - pattern_tl_a.x) / pixelRatio, (pattern_br_a.y - pattern_tl_a.y) / pixelRatio); + vec2 display_size_b = vec2((pattern_br_b.x - pattern_tl_b.x) / pixelRatio, (pattern_br_b.y - pattern_tl_b.y) / pixelRatio); + gl_Position = u_matrix * vec4(a_pos, 0, 1); + + v_pos_a = get_pattern_pos(u_pixel_coord_upper, u_pixel_coord_lower, fromScale * display_size_a, tileZoomRatio, a_pos); + v_pos_b = get_pattern_pos(u_pixel_coord_upper, u_pixel_coord_lower, toScale * display_size_b, tileZoomRatio, a_pos); +} + +*/ + +// Uncompressed source of fill_pattern.fragment.glsl: +/* +uniform vec2 u_texsize; +uniform float u_fade; + +uniform sampler2D u_image; + +varying vec2 v_pos_a; +varying vec2 v_pos_b; + + +#ifndef HAS_UNIFORM_u_opacity +varying lowp float opacity; +#else +uniform lowp float u_opacity; +#endif + + +#ifndef HAS_UNIFORM_u_pattern_from +varying lowp vec4 pattern_from; +#else +uniform lowp vec4 u_pattern_from; +#endif + + +#ifndef HAS_UNIFORM_u_pattern_to +varying lowp vec4 pattern_to; +#else +uniform lowp vec4 u_pattern_to; +#endif + + +void main() { + +#ifdef HAS_UNIFORM_u_opacity + lowp float opacity = u_opacity; +#endif + + +#ifdef HAS_UNIFORM_u_pattern_from + mediump vec4 pattern_from = u_pattern_from; +#endif + + +#ifdef HAS_UNIFORM_u_pattern_to + mediump vec4 pattern_to = u_pattern_to; +#endif + + + vec2 pattern_tl_a = pattern_from.xy; + vec2 pattern_br_a = pattern_from.zw; + vec2 pattern_tl_b = pattern_to.xy; + vec2 pattern_br_b = pattern_to.zw; + + vec2 imagecoord = mod(v_pos_a, 1.0); + vec2 pos = mix(pattern_tl_a / u_texsize, pattern_br_a / u_texsize, imagecoord); + vec4 color1 = texture2D(u_image, pos); + + vec2 imagecoord_b = mod(v_pos_b, 1.0); + vec2 pos2 = mix(pattern_tl_b / u_texsize, pattern_br_b / u_texsize, imagecoord_b); + vec4 color2 = texture2D(u_image, pos2); + + gl_FragColor = mix(color1, color2, u_fade) * opacity; + +#ifdef OVERDRAW_INSPECTOR + gl_FragColor = vec4(1.0); +#endif +} + +*/ + diff --git a/platform/gfx/gl/src/mbgl/programs/gl/heatmap.cpp b/platform/gfx/gl/src/mbgl/programs/gl/heatmap.cpp new file mode 100644 index 0000000000..41f804a37b --- /dev/null +++ b/platform/gfx/gl/src/mbgl/programs/gl/heatmap.cpp @@ -0,0 +1,162 @@ +// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. + +#include <mbgl/programs/heatmap_program.hpp> +#include <mbgl/programs/gl/preludes.hpp> +#include <mbgl/programs/gl/shader_source.hpp> +#include <mbgl/gl/program.hpp> + +namespace mbgl { +namespace programs { +namespace gl { + +template <typename> +struct ShaderSource; + +template <> +struct ShaderSource<HeatmapProgram> { + static constexpr const char* name = "heatmap"; + static constexpr const uint8_t hash[8] = { 0xe5, 0xa4, 0x9c, 0x31, 0x01, 0xe5, 0x4a, 0xe0 }; + static constexpr const auto vertexOffset = 8026; + static constexpr const auto fragmentOffset = 9074; +}; + +constexpr const char* ShaderSource<HeatmapProgram>::name; +constexpr const uint8_t ShaderSource<HeatmapProgram>::hash[8]; + +} // namespace gl +} // namespace programs + +namespace gfx { + +template <> +std::unique_ptr<gfx::Program<HeatmapProgram>> +Backend::Create<gfx::Backend::Type::OpenGL>(const ProgramParameters& programParameters) { + return std::make_unique<gl::Program<HeatmapProgram>>(programParameters); +} + +} // namespace gfx +} // namespace mbgl + +// Uncompressed source of heatmap.vertex.glsl: +/* + +uniform mat4 u_matrix; +uniform float u_extrude_scale; +uniform float u_opacity; +uniform float u_intensity; + +attribute vec2 a_pos; + +varying vec2 v_extrude; + + +#ifndef HAS_UNIFORM_u_weight +uniform lowp float u_weight_t; +attribute highp vec2 a_weight; +varying highp float weight; +#else +uniform highp float u_weight; +#endif + + +#ifndef HAS_UNIFORM_u_radius +uniform lowp float u_radius_t; +attribute mediump vec2 a_radius; +#else +uniform mediump float u_radius; +#endif + + +// Effective "0" in the kernel density texture to adjust the kernel size to; +// this empirically chosen number minimizes artifacts on overlapping kernels +// for typical heatmap cases (assuming clustered source) +const highp float ZERO = 1.0 / 255.0 / 16.0; + +// Gaussian kernel coefficient: 1 / sqrt(2 * PI) +#define GAUSS_COEF 0.3989422804014327 + +void main(void) { + +#ifndef HAS_UNIFORM_u_weight + weight = unpack_mix_vec2(a_weight, u_weight_t); +#else + highp float weight = u_weight; +#endif + + +#ifndef HAS_UNIFORM_u_radius + mediump float radius = unpack_mix_vec2(a_radius, u_radius_t); +#else + mediump float radius = u_radius; +#endif + + + // unencode the extrusion vector that we snuck into the a_pos vector + vec2 unscaled_extrude = vec2(mod(a_pos, 2.0) * 2.0 - 1.0); + + // This 'extrude' comes in ranging from [-1, -1], to [1, 1]. We'll use + // it to produce the vertices of a square mesh framing the point feature + // we're adding to the kernel density texture. We'll also pass it as + // a varying, so that the fragment shader can determine the distance of + // each fragment from the point feature. + // Before we do so, we need to scale it up sufficiently so that the + // kernel falls effectively to zero at the edge of the mesh. + // That is, we want to know S such that + // weight * u_intensity * GAUSS_COEF * exp(-0.5 * 3.0^2 * S^2) == ZERO + // Which solves to: + // S = sqrt(-2.0 * log(ZERO / (weight * u_intensity * GAUSS_COEF))) / 3.0 + float S = sqrt(-2.0 * log(ZERO / weight / u_intensity / GAUSS_COEF)) / 3.0; + + // Pass the varying in units of radius + v_extrude = S * unscaled_extrude; + + // Scale by radius and the zoom-based scale factor to produce actual + // mesh position + vec2 extrude = v_extrude * radius * u_extrude_scale; + + // multiply a_pos by 0.5, since we had it * 2 in order to sneak + // in extrusion data + vec4 pos = vec4(floor(a_pos * 0.5) + extrude, 0, 1); + + gl_Position = u_matrix * pos; +} + +*/ + +// Uncompressed source of heatmap.fragment.glsl: +/* +uniform highp float u_intensity; + +varying vec2 v_extrude; + + +#ifndef HAS_UNIFORM_u_weight +varying highp float weight; +#else +uniform highp float u_weight; +#endif + + +// Gaussian kernel coefficient: 1 / sqrt(2 * PI) +#define GAUSS_COEF 0.3989422804014327 + +void main() { + +#ifdef HAS_UNIFORM_u_weight + highp float weight = u_weight; +#endif + + + // Kernel density estimation with a Gaussian kernel of size 5x5 + float d = -0.5 * 3.0 * 3.0 * dot(v_extrude, v_extrude); + float val = weight * u_intensity * GAUSS_COEF * exp(d); + + gl_FragColor = vec4(val, 1.0, 1.0, 1.0); + +#ifdef OVERDRAW_INSPECTOR + gl_FragColor = vec4(1.0); +#endif +} + +*/ + diff --git a/platform/gfx/gl/src/mbgl/programs/gl/heatmap_texture.cpp b/platform/gfx/gl/src/mbgl/programs/gl/heatmap_texture.cpp new file mode 100644 index 0000000000..a6583bfbb7 --- /dev/null +++ b/platform/gfx/gl/src/mbgl/programs/gl/heatmap_texture.cpp @@ -0,0 +1,74 @@ +// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. + +#include <mbgl/programs/heatmap_texture_program.hpp> +#include <mbgl/programs/gl/preludes.hpp> +#include <mbgl/programs/gl/shader_source.hpp> +#include <mbgl/gl/program.hpp> + +namespace mbgl { +namespace programs { +namespace gl { + +template <typename> +struct ShaderSource; + +template <> +struct ShaderSource<HeatmapTextureProgram> { + static constexpr const char* name = "heatmap_texture"; + static constexpr const uint8_t hash[8] = { 0x9f, 0xc7, 0x56, 0xb2, 0x9e, 0x8f, 0x15, 0xff }; + static constexpr const auto vertexOffset = 9535; + static constexpr const auto fragmentOffset = 9715; +}; + +constexpr const char* ShaderSource<HeatmapTextureProgram>::name; +constexpr const uint8_t ShaderSource<HeatmapTextureProgram>::hash[8]; + +} // namespace gl +} // namespace programs + +namespace gfx { + +template <> +std::unique_ptr<gfx::Program<HeatmapTextureProgram>> +Backend::Create<gfx::Backend::Type::OpenGL>(const ProgramParameters& programParameters) { + return std::make_unique<gl::Program<HeatmapTextureProgram>>(programParameters); +} + +} // namespace gfx +} // namespace mbgl + +// Uncompressed source of heatmap_texture.vertex.glsl: +/* +uniform mat4 u_matrix; +uniform vec2 u_world; +attribute vec2 a_pos; +varying vec2 v_pos; + +void main() { + gl_Position = u_matrix * vec4(a_pos * u_world, 0, 1); + + v_pos.x = a_pos.x; + v_pos.y = 1.0 - a_pos.y; +} + +*/ + +// Uncompressed source of heatmap_texture.fragment.glsl: +/* +uniform sampler2D u_image; +uniform sampler2D u_color_ramp; +uniform float u_opacity; +varying vec2 v_pos; + +void main() { + float t = texture2D(u_image, v_pos).r; + vec4 color = texture2D(u_color_ramp, vec2(t, 0.5)); + gl_FragColor = color * u_opacity; + +#ifdef OVERDRAW_INSPECTOR + gl_FragColor = vec4(0.0); +#endif +} + +*/ + diff --git a/platform/gfx/gl/src/mbgl/programs/gl/hillshade.cpp b/platform/gfx/gl/src/mbgl/programs/gl/hillshade.cpp new file mode 100644 index 0000000000..b0c2c95aa8 --- /dev/null +++ b/platform/gfx/gl/src/mbgl/programs/gl/hillshade.cpp @@ -0,0 +1,112 @@ +// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. + +#include <mbgl/programs/hillshade_program.hpp> +#include <mbgl/programs/gl/preludes.hpp> +#include <mbgl/programs/gl/shader_source.hpp> +#include <mbgl/gl/program.hpp> + +namespace mbgl { +namespace programs { +namespace gl { + +template <typename> +struct ShaderSource; + +template <> +struct ShaderSource<HillshadeProgram> { + static constexpr const char* name = "hillshade"; + static constexpr const uint8_t hash[8] = { 0x8a, 0x11, 0x29, 0x18, 0x52, 0x7f, 0x3b, 0xbb }; + static constexpr const auto vertexOffset = 29113; + static constexpr const auto fragmentOffset = 29284; +}; + +constexpr const char* ShaderSource<HillshadeProgram>::name; +constexpr const uint8_t ShaderSource<HillshadeProgram>::hash[8]; + +} // namespace gl +} // namespace programs + +namespace gfx { + +template <> +std::unique_ptr<gfx::Program<HillshadeProgram>> +Backend::Create<gfx::Backend::Type::OpenGL>(const ProgramParameters& programParameters) { + return std::make_unique<gl::Program<HillshadeProgram>>(programParameters); +} + +} // namespace gfx +} // namespace mbgl + +// Uncompressed source of hillshade.vertex.glsl: +/* +uniform mat4 u_matrix; + +attribute vec2 a_pos; +attribute vec2 a_texture_pos; + +varying vec2 v_pos; + +void main() { + gl_Position = u_matrix * vec4(a_pos, 0, 1); + v_pos = a_texture_pos / 8192.0; +} + +*/ + +// Uncompressed source of hillshade.fragment.glsl: +/* +uniform sampler2D u_image; +varying vec2 v_pos; + +uniform vec2 u_latrange; +uniform vec2 u_light; +uniform vec4 u_shadow; +uniform vec4 u_highlight; +uniform vec4 u_accent; + +#define PI 3.141592653589793 + +void main() { + vec4 pixel = texture2D(u_image, v_pos); + + vec2 deriv = ((pixel.rg * 2.0) - 1.0); + + // We divide the slope by a scale factor based on the cosin of the pixel's approximate latitude + // to account for mercator projection distortion. see #4807 for details + float scaleFactor = cos(radians((u_latrange[0] - u_latrange[1]) * (1.0 - v_pos.y) + u_latrange[1])); + // We also multiply the slope by an arbitrary z-factor of 1.25 + float slope = atan(1.25 * length(deriv) / scaleFactor); + float aspect = deriv.x != 0.0 ? atan(deriv.y, -deriv.x) : PI / 2.0 * (deriv.y > 0.0 ? 1.0 : -1.0); + + float intensity = u_light.x; + // We add PI to make this property match the global light object, which adds PI/2 to the light's azimuthal + // position property to account for 0deg corresponding to north/the top of the viewport in the style spec + // and the original shader was written to accept (-illuminationDirection - 90) as the azimuthal. + float azimuth = u_light.y + PI; + + // We scale the slope exponentially based on intensity, using a calculation similar to + // the exponential interpolation function in the style spec: + // https://github.com/mapbox/mapbox-gl-js/blob/master/src/style-spec/expression/definitions/interpolate.js#L217-L228 + // so that higher intensity values create more opaque hillshading. + float base = 1.875 - intensity * 1.75; + float maxValue = 0.5 * PI; + float scaledSlope = intensity != 0.5 ? ((pow(base, slope) - 1.0) / (pow(base, maxValue) - 1.0)) * maxValue : slope; + + // The accent color is calculated with the cosine of the slope while the shade color is calculated with the sine + // so that the accent color's rate of change eases in while the shade color's eases out. + float accent = cos(scaledSlope); + // We multiply both the accent and shade color by a clamped intensity value + // so that intensities >= 0.5 do not additionally affect the color values + // while intensity values < 0.5 make the overall color more transparent. + vec4 accent_color = (1.0 - accent) * u_accent * clamp(intensity * 2.0, 0.0, 1.0); + float shade = abs(mod((aspect + azimuth) / PI + 0.5, 2.0) - 1.0); + vec4 shade_color = mix(u_shadow, u_highlight, shade) * sin(scaledSlope) * clamp(intensity * 2.0, 0.0, 1.0); + gl_FragColor = accent_color * (1.0 - shade_color.a) + shade_color; + +#ifdef OVERDRAW_INSPECTOR + gl_FragColor = vec4(1.0); +#endif +} + +*/ + diff --git a/platform/gfx/gl/src/mbgl/programs/gl/hillshade_prepare.cpp b/platform/gfx/gl/src/mbgl/programs/gl/hillshade_prepare.cpp new file mode 100644 index 0000000000..1aef64293b --- /dev/null +++ b/platform/gfx/gl/src/mbgl/programs/gl/hillshade_prepare.cpp @@ -0,0 +1,136 @@ +// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. + +#include <mbgl/programs/hillshade_prepare_program.hpp> +#include <mbgl/programs/gl/preludes.hpp> +#include <mbgl/programs/gl/shader_source.hpp> +#include <mbgl/gl/program.hpp> + +namespace mbgl { +namespace programs { +namespace gl { + +template <typename> +struct ShaderSource; + +template <> +struct ShaderSource<HillshadePrepareProgram> { + static constexpr const char* name = "hillshade_prepare"; + static constexpr const uint8_t hash[8] = { 0xe6, 0x01, 0xf2, 0xbb, 0xa0, 0x77, 0x1d, 0xeb }; + static constexpr const auto vertexOffset = 27698; + static constexpr const auto fragmentOffset = 27991; +}; + +constexpr const char* ShaderSource<HillshadePrepareProgram>::name; +constexpr const uint8_t ShaderSource<HillshadePrepareProgram>::hash[8]; + +} // namespace gl +} // namespace programs + +namespace gfx { + +template <> +std::unique_ptr<gfx::Program<HillshadePrepareProgram>> +Backend::Create<gfx::Backend::Type::OpenGL>(const ProgramParameters& programParameters) { + return std::make_unique<gl::Program<HillshadePrepareProgram>>(programParameters); +} + +} // namespace gfx +} // namespace mbgl + +// Uncompressed source of hillshade_prepare.vertex.glsl: +/* +uniform mat4 u_matrix; +uniform vec2 u_dimension; + +attribute vec2 a_pos; +attribute vec2 a_texture_pos; + +varying vec2 v_pos; + +void main() { + gl_Position = u_matrix * vec4(a_pos, 0, 1); + + highp vec2 epsilon = 1.0 / u_dimension; + float scale = (u_dimension.x - 2.0) / u_dimension.x; + v_pos = (a_texture_pos / 8192.0) * scale + epsilon; +} + +*/ + +// Uncompressed source of hillshade_prepare.fragment.glsl: +/* +#ifdef GL_ES +precision highp float; +#endif + +uniform sampler2D u_image; +varying vec2 v_pos; +uniform vec2 u_dimension; +uniform float u_zoom; +uniform float u_maxzoom; + +float getElevation(vec2 coord, float bias) { + // Convert encoded elevation value to meters + vec4 data = texture2D(u_image, coord) * 255.0; + return (data.r + data.g * 256.0 + data.b * 256.0 * 256.0) / 4.0; +} + +void main() { + vec2 epsilon = 1.0 / u_dimension; + + // queried pixels: + // +-----------+ + // | | | | + // | a | b | c | + // | | | | + // +-----------+ + // | | | | + // | d | e | f | + // | | | | + // +-----------+ + // | | | | + // | g | h | i | + // | | | | + // +-----------+ + + float a = getElevation(v_pos + vec2(-epsilon.x, -epsilon.y), 0.0); + float b = getElevation(v_pos + vec2(0, -epsilon.y), 0.0); + float c = getElevation(v_pos + vec2(epsilon.x, -epsilon.y), 0.0); + float d = getElevation(v_pos + vec2(-epsilon.x, 0), 0.0); + float e = getElevation(v_pos, 0.0); + float f = getElevation(v_pos + vec2(epsilon.x, 0), 0.0); + float g = getElevation(v_pos + vec2(-epsilon.x, epsilon.y), 0.0); + float h = getElevation(v_pos + vec2(0, epsilon.y), 0.0); + float i = getElevation(v_pos + vec2(epsilon.x, epsilon.y), 0.0); + + // here we divide the x and y slopes by 8 * pixel size + // where pixel size (aka meters/pixel) is: + // circumference of the world / (pixels per tile * number of tiles) + // which is equivalent to: 8 * 40075016.6855785 / (512 * pow(2, u_zoom)) + // which can be reduced to: pow(2, 19.25619978527 - u_zoom) + // we want to vertically exaggerate the hillshading though, because otherwise + // it is barely noticeable at low zooms. to do this, we multiply this by some + // scale factor pow(2, (u_zoom - u_maxzoom) * a) where a is an arbitrary value + // Here we use a=0.3 which works out to the expression below. see + // nickidlugash's awesome breakdown for more info + // https://github.com/mapbox/mapbox-gl-js/pull/5286#discussion_r148419556 + float exaggeration = u_zoom < 2.0 ? 0.4 : u_zoom < 4.5 ? 0.35 : 0.3; + + vec2 deriv = vec2( + (c + f + f + i) - (a + d + d + g), + (g + h + h + i) - (a + b + b + c) + ) / pow(2.0, (u_zoom - u_maxzoom) * exaggeration + 19.2562 - u_zoom); + + gl_FragColor = clamp(vec4( + deriv.x / 2.0 + 0.5, + deriv.y / 2.0 + 0.5, + 1.0, + 1.0), 0.0, 1.0); + +#ifdef OVERDRAW_INSPECTOR + gl_FragColor = vec4(1.0); +#endif +} + +*/ + diff --git a/platform/gfx/gl/src/mbgl/programs/gl/line.cpp b/platform/gfx/gl/src/mbgl/programs/gl/line.cpp new file mode 100644 index 0000000000..8a04f86a5f --- /dev/null +++ b/platform/gfx/gl/src/mbgl/programs/gl/line.cpp @@ -0,0 +1,275 @@ +// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. + +#include <mbgl/programs/line_program.hpp> +#include <mbgl/programs/gl/preludes.hpp> +#include <mbgl/programs/gl/shader_source.hpp> +#include <mbgl/gl/program.hpp> + +namespace mbgl { +namespace programs { +namespace gl { + +template <typename> +struct ShaderSource; + +template <> +struct ShaderSource<LineProgram> { + static constexpr const char* name = "line"; + static constexpr const uint8_t hash[8] = { 0x7f, 0x8e, 0xaa, 0x53, 0x75, 0x78, 0xac, 0x2c }; + static constexpr const auto vertexOffset = 30358; + static constexpr const auto fragmentOffset = 33355; +}; + +constexpr const char* ShaderSource<LineProgram>::name; +constexpr const uint8_t ShaderSource<LineProgram>::hash[8]; + +} // namespace gl +} // namespace programs + +namespace gfx { + +template <> +std::unique_ptr<gfx::Program<LineProgram>> +Backend::Create<gfx::Backend::Type::OpenGL>(const ProgramParameters& programParameters) { + return std::make_unique<gl::Program<LineProgram>>(programParameters); +} + +} // namespace gfx +} // namespace mbgl + +// Uncompressed source of line.vertex.glsl: +/* +// floor(127 / 2) == 63.0 +// the maximum allowed miter limit is 2.0 at the moment. the extrude normal is +// stored in a byte (-128..127). we scale regular normals up to length 63, but +// there are also "special" normals that have a bigger length (of up to 126 in +// this case). +// #define scale 63.0 +#define scale 0.015873016 + +attribute vec2 a_pos_normal; +attribute vec4 a_data; + +uniform mat4 u_matrix; +uniform mediump float u_ratio; +uniform vec2 u_units_to_pixels; +uniform lowp float u_device_pixel_ratio; + +varying vec2 v_normal; +varying vec2 v_width2; +varying float v_gamma_scale; +varying highp float v_linesofar; + + +#ifndef HAS_UNIFORM_u_color +uniform lowp float u_color_t; +attribute highp vec4 a_color; +varying highp vec4 color; +#else +uniform highp vec4 u_color; +#endif + + +#ifndef HAS_UNIFORM_u_blur +uniform lowp float u_blur_t; +attribute lowp vec2 a_blur; +varying lowp float blur; +#else +uniform lowp float u_blur; +#endif + + +#ifndef HAS_UNIFORM_u_opacity +uniform lowp float u_opacity_t; +attribute lowp vec2 a_opacity; +varying lowp float opacity; +#else +uniform lowp float u_opacity; +#endif + + +#ifndef HAS_UNIFORM_u_gapwidth +uniform lowp float u_gapwidth_t; +attribute mediump vec2 a_gapwidth; +#else +uniform mediump float u_gapwidth; +#endif + + +#ifndef HAS_UNIFORM_u_offset +uniform lowp float u_offset_t; +attribute lowp vec2 a_offset; +#else +uniform lowp float u_offset; +#endif + + +#ifndef HAS_UNIFORM_u_width +uniform lowp float u_width_t; +attribute mediump vec2 a_width; +#else +uniform mediump float u_width; +#endif + + +void main() { + +#ifndef HAS_UNIFORM_u_color + color = unpack_mix_color(a_color, u_color_t); +#else + highp vec4 color = u_color; +#endif + + +#ifndef HAS_UNIFORM_u_blur + blur = unpack_mix_vec2(a_blur, u_blur_t); +#else + lowp float blur = u_blur; +#endif + + +#ifndef HAS_UNIFORM_u_opacity + opacity = unpack_mix_vec2(a_opacity, u_opacity_t); +#else + lowp float opacity = u_opacity; +#endif + + +#ifndef HAS_UNIFORM_u_gapwidth + mediump float gapwidth = unpack_mix_vec2(a_gapwidth, u_gapwidth_t); +#else + mediump float gapwidth = u_gapwidth; +#endif + + +#ifndef HAS_UNIFORM_u_offset + lowp float offset = unpack_mix_vec2(a_offset, u_offset_t); +#else + lowp float offset = u_offset; +#endif + + +#ifndef HAS_UNIFORM_u_width + mediump float width = unpack_mix_vec2(a_width, u_width_t); +#else + mediump float width = u_width; +#endif + + + // the distance over which the line edge fades out. + // Retina devices need a smaller distance to avoid aliasing. + float ANTIALIASING = 1.0 / u_device_pixel_ratio / 2.0; + + vec2 a_extrude = a_data.xy - 128.0; + float a_direction = mod(a_data.z, 4.0) - 1.0; + + v_linesofar = (floor(a_data.z / 4.0) + a_data.w * 64.0) * 2.0; + + vec2 pos = floor(a_pos_normal * 0.5); + + // x is 1 if it's a round cap, 0 otherwise + // y is 1 if the normal points up, and -1 if it points down + // We store these in the least significant bit of a_pos_normal + mediump vec2 normal = a_pos_normal - 2.0 * pos; + normal.y = normal.y * 2.0 - 1.0; + v_normal = normal; + + // these transformations used to be applied in the JS and native code bases. + // moved them into the shader for clarity and simplicity. + gapwidth = gapwidth / 2.0; + float halfwidth = width / 2.0; + offset = -1.0 * offset; + + float inset = gapwidth + (gapwidth > 0.0 ? ANTIALIASING : 0.0); + float outset = gapwidth + halfwidth * (gapwidth > 0.0 ? 2.0 : 1.0) + (halfwidth == 0.0 ? 0.0 : ANTIALIASING); + + // Scale the extrusion vector down to a normal and then up by the line width + // of this vertex. + mediump vec2 dist = outset * a_extrude * scale; + + // Calculate the offset when drawing a line that is to the side of the actual line. + // We do this by creating a vector that points towards the extrude, but rotate + // it when we're drawing round end points (a_direction = -1 or 1) since their + // extrude vector points in another direction. + mediump float u = 0.5 * a_direction; + mediump float t = 1.0 - abs(u); + mediump vec2 offset2 = offset * a_extrude * scale * normal.y * mat2(t, -u, u, t); + + vec4 projected_extrude = u_matrix * vec4(dist / u_ratio, 0.0, 0.0); + gl_Position = u_matrix * vec4(pos + offset2 / u_ratio, 0.0, 1.0) + projected_extrude; + + // calculate how much the perspective view squishes or stretches the extrude + float extrude_length_without_perspective = length(dist); + float extrude_length_with_perspective = length(projected_extrude.xy / gl_Position.w * u_units_to_pixels); + v_gamma_scale = extrude_length_without_perspective / extrude_length_with_perspective; + + v_width2 = vec2(outset, inset); +} + +*/ + +// Uncompressed source of line.fragment.glsl: +/* +uniform lowp float u_device_pixel_ratio; + +varying vec2 v_width2; +varying vec2 v_normal; +varying float v_gamma_scale; + + +#ifndef HAS_UNIFORM_u_color +varying highp vec4 color; +#else +uniform highp vec4 u_color; +#endif + + +#ifndef HAS_UNIFORM_u_blur +varying lowp float blur; +#else +uniform lowp float u_blur; +#endif + + +#ifndef HAS_UNIFORM_u_opacity +varying lowp float opacity; +#else +uniform lowp float u_opacity; +#endif + + +void main() { + +#ifdef HAS_UNIFORM_u_color + highp vec4 color = u_color; +#endif + + +#ifdef HAS_UNIFORM_u_blur + lowp float blur = u_blur; +#endif + + +#ifdef HAS_UNIFORM_u_opacity + lowp float opacity = u_opacity; +#endif + + + // Calculate the distance of the pixel from the line in pixels. + float dist = length(v_normal) * v_width2.s; + + // Calculate the antialiasing fade factor. This is either when fading in + // the line in case of an offset line (v_width2.t) or when fading out + // (v_width2.s) + float blur2 = (blur + 1.0 / u_device_pixel_ratio) * v_gamma_scale; + float alpha = clamp(min(dist - (v_width2.t - blur2), v_width2.s - dist) / blur2, 0.0, 1.0); + + gl_FragColor = color * (alpha * opacity); + +#ifdef OVERDRAW_INSPECTOR + gl_FragColor = vec4(1.0); +#endif +} + +*/ + diff --git a/platform/gfx/gl/src/mbgl/programs/gl/line_gradient.cpp b/platform/gfx/gl/src/mbgl/programs/gl/line_gradient.cpp new file mode 100644 index 0000000000..189af6dbbc --- /dev/null +++ b/platform/gfx/gl/src/mbgl/programs/gl/line_gradient.cpp @@ -0,0 +1,257 @@ +// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. + +#include <mbgl/programs/line_gradient_program.hpp> +#include <mbgl/programs/gl/preludes.hpp> +#include <mbgl/programs/gl/shader_source.hpp> +#include <mbgl/gl/program.hpp> + +namespace mbgl { +namespace programs { +namespace gl { + +template <typename> +struct ShaderSource; + +template <> +struct ShaderSource<LineGradientProgram> { + static constexpr const char* name = "line_gradient"; + static constexpr const uint8_t hash[8] = { 0x3f, 0xba, 0xc6, 0x33, 0xcd, 0x86, 0xa2, 0xe8 }; + static constexpr const auto vertexOffset = 34224; + static constexpr const auto fragmentOffset = 37016; +}; + +constexpr const char* ShaderSource<LineGradientProgram>::name; +constexpr const uint8_t ShaderSource<LineGradientProgram>::hash[8]; + +} // namespace gl +} // namespace programs + +namespace gfx { + +template <> +std::unique_ptr<gfx::Program<LineGradientProgram>> +Backend::Create<gfx::Backend::Type::OpenGL>(const ProgramParameters& programParameters) { + return std::make_unique<gl::Program<LineGradientProgram>>(programParameters); +} + +} // namespace gfx +} // namespace mbgl + +// Uncompressed source of line_gradient.vertex.glsl: +/* + +// the attribute conveying progress along a line is scaled to [0, 2^15) +#define MAX_LINE_DISTANCE 32767.0 + +// floor(127 / 2) == 63.0 +// the maximum allowed miter limit is 2.0 at the moment. the extrude normal is +// stored in a byte (-128..127). we scale regular normals up to length 63, but +// there are also "special" normals that have a bigger length (of up to 126 in +// this case). +// #define scale 63.0 +#define scale 0.015873016 + +attribute vec2 a_pos_normal; +attribute vec4 a_data; + +uniform mat4 u_matrix; +uniform mediump float u_ratio; +uniform lowp float u_device_pixel_ratio; +uniform vec2 u_units_to_pixels; + +varying vec2 v_normal; +varying vec2 v_width2; +varying float v_gamma_scale; +varying highp float v_lineprogress; + + +#ifndef HAS_UNIFORM_u_blur +uniform lowp float u_blur_t; +attribute lowp vec2 a_blur; +varying lowp float blur; +#else +uniform lowp float u_blur; +#endif + + +#ifndef HAS_UNIFORM_u_opacity +uniform lowp float u_opacity_t; +attribute lowp vec2 a_opacity; +varying lowp float opacity; +#else +uniform lowp float u_opacity; +#endif + + +#ifndef HAS_UNIFORM_u_gapwidth +uniform lowp float u_gapwidth_t; +attribute mediump vec2 a_gapwidth; +#else +uniform mediump float u_gapwidth; +#endif + + +#ifndef HAS_UNIFORM_u_offset +uniform lowp float u_offset_t; +attribute lowp vec2 a_offset; +#else +uniform lowp float u_offset; +#endif + + +#ifndef HAS_UNIFORM_u_width +uniform lowp float u_width_t; +attribute mediump vec2 a_width; +#else +uniform mediump float u_width; +#endif + + +void main() { + +#ifndef HAS_UNIFORM_u_blur + blur = unpack_mix_vec2(a_blur, u_blur_t); +#else + lowp float blur = u_blur; +#endif + + +#ifndef HAS_UNIFORM_u_opacity + opacity = unpack_mix_vec2(a_opacity, u_opacity_t); +#else + lowp float opacity = u_opacity; +#endif + + +#ifndef HAS_UNIFORM_u_gapwidth + mediump float gapwidth = unpack_mix_vec2(a_gapwidth, u_gapwidth_t); +#else + mediump float gapwidth = u_gapwidth; +#endif + + +#ifndef HAS_UNIFORM_u_offset + lowp float offset = unpack_mix_vec2(a_offset, u_offset_t); +#else + lowp float offset = u_offset; +#endif + + +#ifndef HAS_UNIFORM_u_width + mediump float width = unpack_mix_vec2(a_width, u_width_t); +#else + mediump float width = u_width; +#endif + + + // the distance over which the line edge fades out. + // Retina devices need a smaller distance to avoid aliasing. + float ANTIALIASING = 1.0 / u_device_pixel_ratio / 2.0; + + vec2 a_extrude = a_data.xy - 128.0; + float a_direction = mod(a_data.z, 4.0) - 1.0; + + v_lineprogress = (floor(a_data.z / 4.0) + a_data.w * 64.0) * 2.0 / MAX_LINE_DISTANCE; + + vec2 pos = floor(a_pos_normal * 0.5); + + // x is 1 if it's a round cap, 0 otherwise + // y is 1 if the normal points up, and -1 if it points down + // We store these in the least significant bit of a_pos_normal + mediump vec2 normal = a_pos_normal - 2.0 * pos; + normal.y = normal.y * 2.0 - 1.0; + v_normal = normal; + + // these transformations used to be applied in the JS and native code bases. + // moved them into the shader for clarity and simplicity. + gapwidth = gapwidth / 2.0; + float halfwidth = width / 2.0; + offset = -1.0 * offset; + + float inset = gapwidth + (gapwidth > 0.0 ? ANTIALIASING : 0.0); + float outset = gapwidth + halfwidth * (gapwidth > 0.0 ? 2.0 : 1.0) + (halfwidth == 0.0 ? 0.0 : ANTIALIASING); + + // Scale the extrusion vector down to a normal and then up by the line width + // of this vertex. + mediump vec2 dist = outset * a_extrude * scale; + + // Calculate the offset when drawing a line that is to the side of the actual line. + // We do this by creating a vector that points towards the extrude, but rotate + // it when we're drawing round end points (a_direction = -1 or 1) since their + // extrude vector points in another direction. + mediump float u = 0.5 * a_direction; + mediump float t = 1.0 - abs(u); + mediump vec2 offset2 = offset * a_extrude * scale * normal.y * mat2(t, -u, u, t); + + vec4 projected_extrude = u_matrix * vec4(dist / u_ratio, 0.0, 0.0); + gl_Position = u_matrix * vec4(pos + offset2 / u_ratio, 0.0, 1.0) + projected_extrude; + + // calculate how much the perspective view squishes or stretches the extrude + float extrude_length_without_perspective = length(dist); + float extrude_length_with_perspective = length(projected_extrude.xy / gl_Position.w * u_units_to_pixels); + v_gamma_scale = extrude_length_without_perspective / extrude_length_with_perspective; + + v_width2 = vec2(outset, inset); +} + +*/ + +// Uncompressed source of line_gradient.fragment.glsl: +/* +uniform lowp float u_device_pixel_ratio; +uniform sampler2D u_image; + +varying vec2 v_width2; +varying vec2 v_normal; +varying float v_gamma_scale; +varying highp float v_lineprogress; + + +#ifndef HAS_UNIFORM_u_blur +varying lowp float blur; +#else +uniform lowp float u_blur; +#endif + + +#ifndef HAS_UNIFORM_u_opacity +varying lowp float opacity; +#else +uniform lowp float u_opacity; +#endif + + +void main() { + +#ifdef HAS_UNIFORM_u_blur + lowp float blur = u_blur; +#endif + + +#ifdef HAS_UNIFORM_u_opacity + lowp float opacity = u_opacity; +#endif + + + // Calculate the distance of the pixel from the line in pixels. + float dist = length(v_normal) * v_width2.s; + + // Calculate the antialiasing fade factor. This is either when fading in + // the line in case of an offset line (v_width2.t) or when fading out + // (v_width2.s) + float blur2 = (blur + 1.0 / u_device_pixel_ratio) * v_gamma_scale; + float alpha = clamp(min(dist - (v_width2.t - blur2), v_width2.s - dist) / blur2, 0.0, 1.0); + + // For gradient lines, v_lineprogress is the ratio along the entire line, + // scaled to [0, 2^15), and the gradient ramp is stored in a texture. + vec4 color = texture2D(u_image, vec2(v_lineprogress, 0.5)); + + gl_FragColor = color * (alpha * opacity); + +#ifdef OVERDRAW_INSPECTOR + gl_FragColor = vec4(1.0); +#endif +} + +*/ + diff --git a/platform/gfx/gl/src/mbgl/programs/gl/line_pattern.cpp b/platform/gfx/gl/src/mbgl/programs/gl/line_pattern.cpp new file mode 100644 index 0000000000..96da8a4f2a --- /dev/null +++ b/platform/gfx/gl/src/mbgl/programs/gl/line_pattern.cpp @@ -0,0 +1,345 @@ +// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. + +#include <mbgl/programs/line_pattern_program.hpp> +#include <mbgl/programs/gl/preludes.hpp> +#include <mbgl/programs/gl/shader_source.hpp> +#include <mbgl/gl/program.hpp> + +namespace mbgl { +namespace programs { +namespace gl { + +template <typename> +struct ShaderSource; + +template <> +struct ShaderSource<LinePatternProgram> { + static constexpr const char* name = "line_pattern"; + static constexpr const uint8_t hash[8] = { 0x38, 0x9c, 0x3d, 0xde, 0xb4, 0xe0, 0xd1, 0x61 }; + static constexpr const auto vertexOffset = 37846; + static constexpr const auto fragmentOffset = 41240; +}; + +constexpr const char* ShaderSource<LinePatternProgram>::name; +constexpr const uint8_t ShaderSource<LinePatternProgram>::hash[8]; + +} // namespace gl +} // namespace programs + +namespace gfx { + +template <> +std::unique_ptr<gfx::Program<LinePatternProgram>> +Backend::Create<gfx::Backend::Type::OpenGL>(const ProgramParameters& programParameters) { + return std::make_unique<gl::Program<LinePatternProgram>>(programParameters); +} + +} // namespace gfx +} // namespace mbgl + +// Uncompressed source of line_pattern.vertex.glsl: +/* +// floor(127 / 2) == 63.0 +// the maximum allowed miter limit is 2.0 at the moment. the extrude normal is +// stored in a byte (-128..127). we scale regular normals up to length 63, but +// there are also "special" normals that have a bigger length (of up to 126 in +// this case). +// #define scale 63.0 +#define scale 0.015873016 + +// We scale the distance before adding it to the buffers so that we can store +// long distances for long segments. Use this value to unscale the distance. +#define LINE_DISTANCE_SCALE 2.0 + +attribute vec2 a_pos_normal; +attribute vec4 a_data; + +uniform mat4 u_matrix; +uniform vec2 u_units_to_pixels; +uniform mediump float u_ratio; +uniform lowp float u_device_pixel_ratio; + +varying vec2 v_normal; +varying vec2 v_width2; +varying float v_linesofar; +varying float v_gamma_scale; + + +#ifndef HAS_UNIFORM_u_blur +uniform lowp float u_blur_t; +attribute lowp vec2 a_blur; +varying lowp float blur; +#else +uniform lowp float u_blur; +#endif + + +#ifndef HAS_UNIFORM_u_opacity +uniform lowp float u_opacity_t; +attribute lowp vec2 a_opacity; +varying lowp float opacity; +#else +uniform lowp float u_opacity; +#endif + + +#ifndef HAS_UNIFORM_u_offset +uniform lowp float u_offset_t; +attribute lowp vec2 a_offset; +#else +uniform lowp float u_offset; +#endif + + +#ifndef HAS_UNIFORM_u_gapwidth +uniform lowp float u_gapwidth_t; +attribute mediump vec2 a_gapwidth; +#else +uniform mediump float u_gapwidth; +#endif + + +#ifndef HAS_UNIFORM_u_width +uniform lowp float u_width_t; +attribute mediump vec2 a_width; +#else +uniform mediump float u_width; +#endif + + +#ifndef HAS_UNIFORM_u_pattern_from +uniform lowp float u_pattern_from_t; +attribute lowp vec4 a_pattern_from; +varying lowp vec4 pattern_from; +#else +uniform lowp vec4 u_pattern_from; +#endif + + +#ifndef HAS_UNIFORM_u_pattern_to +uniform lowp float u_pattern_to_t; +attribute lowp vec4 a_pattern_to; +varying lowp vec4 pattern_to; +#else +uniform lowp vec4 u_pattern_to; +#endif + + +void main() { + +#ifndef HAS_UNIFORM_u_blur + blur = unpack_mix_vec2(a_blur, u_blur_t); +#else + lowp float blur = u_blur; +#endif + + +#ifndef HAS_UNIFORM_u_opacity + opacity = unpack_mix_vec2(a_opacity, u_opacity_t); +#else + lowp float opacity = u_opacity; +#endif + + +#ifndef HAS_UNIFORM_u_offset + lowp float offset = unpack_mix_vec2(a_offset, u_offset_t); +#else + lowp float offset = u_offset; +#endif + + +#ifndef HAS_UNIFORM_u_gapwidth + mediump float gapwidth = unpack_mix_vec2(a_gapwidth, u_gapwidth_t); +#else + mediump float gapwidth = u_gapwidth; +#endif + + +#ifndef HAS_UNIFORM_u_width + mediump float width = unpack_mix_vec2(a_width, u_width_t); +#else + mediump float width = u_width; +#endif + + +#ifndef HAS_UNIFORM_u_pattern_from + pattern_from = a_pattern_from; +#else + mediump vec4 pattern_from = u_pattern_from; +#endif + + +#ifndef HAS_UNIFORM_u_pattern_to + pattern_to = a_pattern_to; +#else + mediump vec4 pattern_to = u_pattern_to; +#endif + + + // the distance over which the line edge fades out. + // Retina devices need a smaller distance to avoid aliasing. + float ANTIALIASING = 1.0 / u_device_pixel_ratio / 2.0; + + vec2 a_extrude = a_data.xy - 128.0; + float a_direction = mod(a_data.z, 4.0) - 1.0; + float a_linesofar = (floor(a_data.z / 4.0) + a_data.w * 64.0) * LINE_DISTANCE_SCALE; + // float tileRatio = u_scale.y; + vec2 pos = floor(a_pos_normal * 0.5); + + // x is 1 if it's a round cap, 0 otherwise + // y is 1 if the normal points up, and -1 if it points down + // We store these in the least significant bit of a_pos_normal + mediump vec2 normal = a_pos_normal - 2.0 * pos; + normal.y = normal.y * 2.0 - 1.0; + v_normal = normal; + + // these transformations used to be applied in the JS and native code bases. + // moved them into the shader for clarity and simplicity. + gapwidth = gapwidth / 2.0; + float halfwidth = width / 2.0; + offset = -1.0 * offset; + + float inset = gapwidth + (gapwidth > 0.0 ? ANTIALIASING : 0.0); + float outset = gapwidth + halfwidth * (gapwidth > 0.0 ? 2.0 : 1.0) + (halfwidth == 0.0 ? 0.0 : ANTIALIASING); + + // Scale the extrusion vector down to a normal and then up by the line width + // of this vertex. + mediump vec2 dist = outset * a_extrude * scale; + + // Calculate the offset when drawing a line that is to the side of the actual line. + // We do this by creating a vector that points towards the extrude, but rotate + // it when we're drawing round end points (a_direction = -1 or 1) since their + // extrude vector points in another direction. + mediump float u = 0.5 * a_direction; + mediump float t = 1.0 - abs(u); + mediump vec2 offset2 = offset * a_extrude * scale * normal.y * mat2(t, -u, u, t); + + vec4 projected_extrude = u_matrix * vec4(dist / u_ratio, 0.0, 0.0); + gl_Position = u_matrix * vec4(pos + offset2 / u_ratio, 0.0, 1.0) + projected_extrude; + + // calculate how much the perspective view squishes or stretches the extrude + float extrude_length_without_perspective = length(dist); + float extrude_length_with_perspective = length(projected_extrude.xy / gl_Position.w * u_units_to_pixels); + v_gamma_scale = extrude_length_without_perspective / extrude_length_with_perspective; + + v_linesofar = a_linesofar; + v_width2 = vec2(outset, inset); +} + +*/ + +// Uncompressed source of line_pattern.fragment.glsl: +/* +uniform lowp float u_device_pixel_ratio; +uniform vec2 u_texsize; +uniform float u_fade; +uniform mediump vec4 u_scale; + +uniform sampler2D u_image; + +varying vec2 v_normal; +varying vec2 v_width2; +varying float v_linesofar; +varying float v_gamma_scale; + + +#ifndef HAS_UNIFORM_u_pattern_from +varying lowp vec4 pattern_from; +#else +uniform lowp vec4 u_pattern_from; +#endif + + +#ifndef HAS_UNIFORM_u_pattern_to +varying lowp vec4 pattern_to; +#else +uniform lowp vec4 u_pattern_to; +#endif + + +#ifndef HAS_UNIFORM_u_blur +varying lowp float blur; +#else +uniform lowp float u_blur; +#endif + + +#ifndef HAS_UNIFORM_u_opacity +varying lowp float opacity; +#else +uniform lowp float u_opacity; +#endif + + +void main() { + +#ifdef HAS_UNIFORM_u_pattern_from + mediump vec4 pattern_from = u_pattern_from; +#endif + + +#ifdef HAS_UNIFORM_u_pattern_to + mediump vec4 pattern_to = u_pattern_to; +#endif + + + +#ifdef HAS_UNIFORM_u_blur + lowp float blur = u_blur; +#endif + + +#ifdef HAS_UNIFORM_u_opacity + lowp float opacity = u_opacity; +#endif + + + vec2 pattern_tl_a = pattern_from.xy; + vec2 pattern_br_a = pattern_from.zw; + vec2 pattern_tl_b = pattern_to.xy; + vec2 pattern_br_b = pattern_to.zw; + + float pixelRatio = u_scale.x; + float tileZoomRatio = u_scale.y; + float fromScale = u_scale.z; + float toScale = u_scale.w; + + vec2 display_size_a = vec2((pattern_br_a.x - pattern_tl_a.x) / pixelRatio, (pattern_br_a.y - pattern_tl_a.y) / pixelRatio); + vec2 display_size_b = vec2((pattern_br_b.x - pattern_tl_b.x) / pixelRatio, (pattern_br_b.y - pattern_tl_b.y) / pixelRatio); + + vec2 pattern_size_a = vec2(display_size_a.x * fromScale / tileZoomRatio, display_size_a.y); + vec2 pattern_size_b = vec2(display_size_b.x * toScale / tileZoomRatio, display_size_b.y); + + // Calculate the distance of the pixel from the line in pixels. + float dist = length(v_normal) * v_width2.s; + + // Calculate the antialiasing fade factor. This is either when fading in + // the line in case of an offset line (v_width2.t) or when fading out + // (v_width2.s) + float blur2 = (blur + 1.0 / u_device_pixel_ratio) * v_gamma_scale; + float alpha = clamp(min(dist - (v_width2.t - blur2), v_width2.s - dist) / blur2, 0.0, 1.0); + + float x_a = mod(v_linesofar / pattern_size_a.x, 1.0); + float x_b = mod(v_linesofar / pattern_size_b.x, 1.0); + + // v_normal.y is 0 at the midpoint of the line, -1 at the lower edge, 1 at the upper edge + // we clamp the line width outset to be between 0 and half the pattern height plus padding (2.0) + // to ensure we don't sample outside the designated symbol on the sprite sheet. + // 0.5 is added to shift the component to be bounded between 0 and 1 for interpolation of + // the texture coordinate + float y_a = 0.5 + (v_normal.y * clamp(v_width2.s, 0.0, (pattern_size_a.y + 2.0) / 2.0) / pattern_size_a.y); + float y_b = 0.5 + (v_normal.y * clamp(v_width2.s, 0.0, (pattern_size_b.y + 2.0) / 2.0) / pattern_size_b.y); + vec2 pos_a = mix(pattern_tl_a / u_texsize, pattern_br_a / u_texsize, vec2(x_a, y_a)); + vec2 pos_b = mix(pattern_tl_b / u_texsize, pattern_br_b / u_texsize, vec2(x_b, y_b)); + + vec4 color = mix(texture2D(u_image, pos_a), texture2D(u_image, pos_b), u_fade); + + gl_FragColor = color * alpha * opacity; + +#ifdef OVERDRAW_INSPECTOR + gl_FragColor = vec4(1.0); +#endif +} + +*/ + diff --git a/platform/gfx/gl/src/mbgl/programs/gl/line_sdf.cpp b/platform/gfx/gl/src/mbgl/programs/gl/line_sdf.cpp new file mode 100644 index 0000000000..493cc76d01 --- /dev/null +++ b/platform/gfx/gl/src/mbgl/programs/gl/line_sdf.cpp @@ -0,0 +1,338 @@ +// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. + +#include <mbgl/programs/line_sdf_program.hpp> +#include <mbgl/programs/gl/preludes.hpp> +#include <mbgl/programs/gl/shader_source.hpp> +#include <mbgl/gl/program.hpp> + +namespace mbgl { +namespace programs { +namespace gl { + +template <typename> +struct ShaderSource; + +template <> +struct ShaderSource<LineSDFProgram> { + static constexpr const char* name = "line_sdf"; + static constexpr const uint8_t hash[8] = { 0x25, 0x94, 0x7f, 0xad, 0x84, 0xfe, 0x96, 0xad }; + static constexpr const auto vertexOffset = 43595; + static constexpr const auto fragmentOffset = 47282; +}; + +constexpr const char* ShaderSource<LineSDFProgram>::name; +constexpr const uint8_t ShaderSource<LineSDFProgram>::hash[8]; + +} // namespace gl +} // namespace programs + +namespace gfx { + +template <> +std::unique_ptr<gfx::Program<LineSDFProgram>> +Backend::Create<gfx::Backend::Type::OpenGL>(const ProgramParameters& programParameters) { + return std::make_unique<gl::Program<LineSDFProgram>>(programParameters); +} + +} // namespace gfx +} // namespace mbgl + +// Uncompressed source of line_sdf.vertex.glsl: +/* +// floor(127 / 2) == 63.0 +// the maximum allowed miter limit is 2.0 at the moment. the extrude normal is +// stored in a byte (-128..127). we scale regular normals up to length 63, but +// there are also "special" normals that have a bigger length (of up to 126 in +// this case). +// #define scale 63.0 +#define scale 0.015873016 + +// We scale the distance before adding it to the buffers so that we can store +// long distances for long segments. Use this value to unscale the distance. +#define LINE_DISTANCE_SCALE 2.0 + +attribute vec2 a_pos_normal; +attribute vec4 a_data; + +uniform mat4 u_matrix; +uniform mediump float u_ratio; +uniform lowp float u_device_pixel_ratio; +uniform vec2 u_patternscale_a; +uniform float u_tex_y_a; +uniform vec2 u_patternscale_b; +uniform float u_tex_y_b; +uniform vec2 u_units_to_pixels; + +varying vec2 v_normal; +varying vec2 v_width2; +varying vec2 v_tex_a; +varying vec2 v_tex_b; +varying float v_gamma_scale; + + +#ifndef HAS_UNIFORM_u_color +uniform lowp float u_color_t; +attribute highp vec4 a_color; +varying highp vec4 color; +#else +uniform highp vec4 u_color; +#endif + + +#ifndef HAS_UNIFORM_u_blur +uniform lowp float u_blur_t; +attribute lowp vec2 a_blur; +varying lowp float blur; +#else +uniform lowp float u_blur; +#endif + + +#ifndef HAS_UNIFORM_u_opacity +uniform lowp float u_opacity_t; +attribute lowp vec2 a_opacity; +varying lowp float opacity; +#else +uniform lowp float u_opacity; +#endif + + +#ifndef HAS_UNIFORM_u_gapwidth +uniform lowp float u_gapwidth_t; +attribute mediump vec2 a_gapwidth; +#else +uniform mediump float u_gapwidth; +#endif + + +#ifndef HAS_UNIFORM_u_offset +uniform lowp float u_offset_t; +attribute lowp vec2 a_offset; +#else +uniform lowp float u_offset; +#endif + + +#ifndef HAS_UNIFORM_u_width +uniform lowp float u_width_t; +attribute mediump vec2 a_width; +varying mediump float width; +#else +uniform mediump float u_width; +#endif + + +#ifndef HAS_UNIFORM_u_floorwidth +uniform lowp float u_floorwidth_t; +attribute lowp vec2 a_floorwidth; +varying lowp float floorwidth; +#else +uniform lowp float u_floorwidth; +#endif + + +void main() { + +#ifndef HAS_UNIFORM_u_color + color = unpack_mix_color(a_color, u_color_t); +#else + highp vec4 color = u_color; +#endif + + +#ifndef HAS_UNIFORM_u_blur + blur = unpack_mix_vec2(a_blur, u_blur_t); +#else + lowp float blur = u_blur; +#endif + + +#ifndef HAS_UNIFORM_u_opacity + opacity = unpack_mix_vec2(a_opacity, u_opacity_t); +#else + lowp float opacity = u_opacity; +#endif + + +#ifndef HAS_UNIFORM_u_gapwidth + mediump float gapwidth = unpack_mix_vec2(a_gapwidth, u_gapwidth_t); +#else + mediump float gapwidth = u_gapwidth; +#endif + + +#ifndef HAS_UNIFORM_u_offset + lowp float offset = unpack_mix_vec2(a_offset, u_offset_t); +#else + lowp float offset = u_offset; +#endif + + +#ifndef HAS_UNIFORM_u_width + width = unpack_mix_vec2(a_width, u_width_t); +#else + mediump float width = u_width; +#endif + + +#ifndef HAS_UNIFORM_u_floorwidth + floorwidth = unpack_mix_vec2(a_floorwidth, u_floorwidth_t); +#else + lowp float floorwidth = u_floorwidth; +#endif + + + // the distance over which the line edge fades out. + // Retina devices need a smaller distance to avoid aliasing. + float ANTIALIASING = 1.0 / u_device_pixel_ratio / 2.0; + + vec2 a_extrude = a_data.xy - 128.0; + float a_direction = mod(a_data.z, 4.0) - 1.0; + float a_linesofar = (floor(a_data.z / 4.0) + a_data.w * 64.0) * LINE_DISTANCE_SCALE; + + vec2 pos = floor(a_pos_normal * 0.5); + + // x is 1 if it's a round cap, 0 otherwise + // y is 1 if the normal points up, and -1 if it points down + // We store these in the least significant bit of a_pos_normal + mediump vec2 normal = a_pos_normal - 2.0 * pos; + normal.y = normal.y * 2.0 - 1.0; + v_normal = normal; + + // these transformations used to be applied in the JS and native code bases. + // moved them into the shader for clarity and simplicity. + gapwidth = gapwidth / 2.0; + float halfwidth = width / 2.0; + offset = -1.0 * offset; + + float inset = gapwidth + (gapwidth > 0.0 ? ANTIALIASING : 0.0); + float outset = gapwidth + halfwidth * (gapwidth > 0.0 ? 2.0 : 1.0) + (halfwidth == 0.0 ? 0.0 : ANTIALIASING); + + // Scale the extrusion vector down to a normal and then up by the line width + // of this vertex. + mediump vec2 dist =outset * a_extrude * scale; + + // Calculate the offset when drawing a line that is to the side of the actual line. + // We do this by creating a vector that points towards the extrude, but rotate + // it when we're drawing round end points (a_direction = -1 or 1) since their + // extrude vector points in another direction. + mediump float u = 0.5 * a_direction; + mediump float t = 1.0 - abs(u); + mediump vec2 offset2 = offset * a_extrude * scale * normal.y * mat2(t, -u, u, t); + + vec4 projected_extrude = u_matrix * vec4(dist / u_ratio, 0.0, 0.0); + gl_Position = u_matrix * vec4(pos + offset2 / u_ratio, 0.0, 1.0) + projected_extrude; + + // calculate how much the perspective view squishes or stretches the extrude + float extrude_length_without_perspective = length(dist); + float extrude_length_with_perspective = length(projected_extrude.xy / gl_Position.w * u_units_to_pixels); + v_gamma_scale = extrude_length_without_perspective / extrude_length_with_perspective; + + v_tex_a = vec2(a_linesofar * u_patternscale_a.x / floorwidth, normal.y * u_patternscale_a.y + u_tex_y_a); + v_tex_b = vec2(a_linesofar * u_patternscale_b.x / floorwidth, normal.y * u_patternscale_b.y + u_tex_y_b); + + v_width2 = vec2(outset, inset); +} + +*/ + +// Uncompressed source of line_sdf.fragment.glsl: +/* + +uniform lowp float u_device_pixel_ratio; +uniform sampler2D u_image; +uniform float u_sdfgamma; +uniform float u_mix; + +varying vec2 v_normal; +varying vec2 v_width2; +varying vec2 v_tex_a; +varying vec2 v_tex_b; +varying float v_gamma_scale; + + +#ifndef HAS_UNIFORM_u_color +varying highp vec4 color; +#else +uniform highp vec4 u_color; +#endif + + +#ifndef HAS_UNIFORM_u_blur +varying lowp float blur; +#else +uniform lowp float u_blur; +#endif + + +#ifndef HAS_UNIFORM_u_opacity +varying lowp float opacity; +#else +uniform lowp float u_opacity; +#endif + + +#ifndef HAS_UNIFORM_u_width +varying mediump float width; +#else +uniform mediump float u_width; +#endif + + +#ifndef HAS_UNIFORM_u_floorwidth +varying lowp float floorwidth; +#else +uniform lowp float u_floorwidth; +#endif + + +void main() { + +#ifdef HAS_UNIFORM_u_color + highp vec4 color = u_color; +#endif + + +#ifdef HAS_UNIFORM_u_blur + lowp float blur = u_blur; +#endif + + +#ifdef HAS_UNIFORM_u_opacity + lowp float opacity = u_opacity; +#endif + + +#ifdef HAS_UNIFORM_u_width + mediump float width = u_width; +#endif + + +#ifdef HAS_UNIFORM_u_floorwidth + lowp float floorwidth = u_floorwidth; +#endif + + + // Calculate the distance of the pixel from the line in pixels. + float dist = length(v_normal) * v_width2.s; + + // Calculate the antialiasing fade factor. This is either when fading in + // the line in case of an offset line (v_width2.t) or when fading out + // (v_width2.s) + float blur2 = (blur + 1.0 / u_device_pixel_ratio) * v_gamma_scale; + float alpha = clamp(min(dist - (v_width2.t - blur2), v_width2.s - dist) / blur2, 0.0, 1.0); + + float sdfdist_a = texture2D(u_image, v_tex_a).a; + float sdfdist_b = texture2D(u_image, v_tex_b).a; + float sdfdist = mix(sdfdist_a, sdfdist_b, u_mix); + alpha *= smoothstep(0.5 - u_sdfgamma / floorwidth, 0.5 + u_sdfgamma / floorwidth, sdfdist); + + gl_FragColor = color * (alpha * opacity); + +#ifdef OVERDRAW_INSPECTOR + gl_FragColor = vec4(1.0); +#endif +} + +*/ + diff --git a/platform/gfx/gl/src/mbgl/programs/gl/preludes.hpp b/platform/gfx/gl/src/mbgl/programs/gl/preludes.hpp new file mode 100644 index 0000000000..e796f1655b --- /dev/null +++ b/platform/gfx/gl/src/mbgl/programs/gl/preludes.hpp @@ -0,0 +1,17 @@ +// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. + +#pragma once + +#include <cstdint> + +namespace mbgl { +namespace programs { +namespace gl { + +constexpr const uint8_t preludeHash[8] = { 0x24, 0x91, 0x82, 0x37, 0x02, 0xad, 0x98, 0x0a }; +constexpr const auto vertexPreludeOffset = 0; +constexpr const auto fragmentPreludeOffset = 1252; + +} // namespace gl +} // namespace programs +} // namespace mbgl diff --git a/platform/gfx/gl/src/mbgl/programs/gl/raster.cpp b/platform/gfx/gl/src/mbgl/programs/gl/raster.cpp new file mode 100644 index 0000000000..ce46b1f299 --- /dev/null +++ b/platform/gfx/gl/src/mbgl/programs/gl/raster.cpp @@ -0,0 +1,122 @@ +// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. + +#include <mbgl/programs/raster_program.hpp> +#include <mbgl/programs/gl/preludes.hpp> +#include <mbgl/programs/gl/shader_source.hpp> +#include <mbgl/gl/program.hpp> + +namespace mbgl { +namespace programs { +namespace gl { + +template <typename> +struct ShaderSource; + +template <> +struct ShaderSource<RasterProgram> { + static constexpr const char* name = "raster"; + static constexpr const uint8_t hash[8] = { 0x40, 0x3d, 0x6c, 0xf4, 0xd0, 0x41, 0x51, 0x0e }; + static constexpr const auto vertexOffset = 48827; + static constexpr const auto fragmentOffset = 49176; +}; + +constexpr const char* ShaderSource<RasterProgram>::name; +constexpr const uint8_t ShaderSource<RasterProgram>::hash[8]; + +} // namespace gl +} // namespace programs + +namespace gfx { + +template <> +std::unique_ptr<gfx::Program<RasterProgram>> +Backend::Create<gfx::Backend::Type::OpenGL>(const ProgramParameters& programParameters) { + return std::make_unique<gl::Program<RasterProgram>>(programParameters); +} + +} // namespace gfx +} // namespace mbgl + +// Uncompressed source of raster.vertex.glsl: +/* +uniform mat4 u_matrix; +uniform vec2 u_tl_parent; +uniform float u_scale_parent; +uniform float u_buffer_scale; + +attribute vec2 a_pos; +attribute vec2 a_texture_pos; + +varying vec2 v_pos0; +varying vec2 v_pos1; + +void main() { + gl_Position = u_matrix * vec4(a_pos, 0, 1); + // We are using Int16 for texture position coordinates to give us enough precision for + // fractional coordinates. We use 8192 to scale the texture coordinates in the buffer + // as an arbitrarily high number to preserve adequate precision when rendering. + // This is also the same value as the EXTENT we are using for our tile buffer pos coordinates, + // so math for modifying either is consistent. + v_pos0 = (((a_texture_pos / 8192.0) - 0.5) / u_buffer_scale ) + 0.5; + v_pos1 = (v_pos0 * u_scale_parent) + u_tl_parent; +} + +*/ + +// Uncompressed source of raster.fragment.glsl: +/* +uniform float u_fade_t; +uniform float u_opacity; +uniform sampler2D u_image0; +uniform sampler2D u_image1; +varying vec2 v_pos0; +varying vec2 v_pos1; + +uniform float u_brightness_low; +uniform float u_brightness_high; + +uniform float u_saturation_factor; +uniform float u_contrast_factor; +uniform vec3 u_spin_weights; + +void main() { + + // read and cross-fade colors from the main and parent tiles + vec4 color0 = texture2D(u_image0, v_pos0); + vec4 color1 = texture2D(u_image1, v_pos1); + if (color0.a > 0.0) { + color0.rgb = color0.rgb / color0.a; + } + if (color1.a > 0.0) { + color1.rgb = color1.rgb / color1.a; + } + vec4 color = mix(color0, color1, u_fade_t); + color.a *= u_opacity; + vec3 rgb = color.rgb; + + // spin + rgb = vec3( + dot(rgb, u_spin_weights.xyz), + dot(rgb, u_spin_weights.zxy), + dot(rgb, u_spin_weights.yzx)); + + // saturation + float average = (color.r + color.g + color.b) / 3.0; + rgb += (average - rgb) * u_saturation_factor; + + // contrast + rgb = (rgb - 0.5) * u_contrast_factor + 0.5; + + // brightness + vec3 u_high_vec = vec3(u_brightness_low, u_brightness_low, u_brightness_low); + vec3 u_low_vec = vec3(u_brightness_high, u_brightness_high, u_brightness_high); + + gl_FragColor = vec4(mix(u_high_vec, u_low_vec, rgb) * color.a, color.a); + +#ifdef OVERDRAW_INSPECTOR + gl_FragColor = vec4(1.0); +#endif +} + +*/ + diff --git a/platform/gfx/gl/src/mbgl/programs/gl/shader_source.cpp b/platform/gfx/gl/src/mbgl/programs/gl/shader_source.cpp new file mode 100644 index 0000000000..6e61578b5e --- /dev/null +++ b/platform/gfx/gl/src/mbgl/programs/gl/shader_source.cpp @@ -0,0 +1,471 @@ +// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. + +#include <mbgl/programs/gl/shader_source.hpp> +#include <mbgl/util/compression.hpp> + +#include <cstdint> + +namespace mbgl { +namespace programs { +namespace gl { + +constexpr const uint8_t compressedShaderSource[] = { + 0x78, 0xda, 0xed, 0x3d, 0xfd, 0x6f, 0xe3, 0x36, 0xb2, 0xf7, 0x73, 0xfe, 0x0a, 0x17, 0x05, 0x0e, + 0x92, 0x2c, 0x5b, 0xb6, 0x93, 0xec, 0x47, 0x75, 0x7a, 0xc5, 0xa2, 0xbb, 0xed, 0x0b, 0xd0, 0xee, + 0x2e, 0x36, 0xed, 0xbd, 0xc3, 0x15, 0x0b, 0x43, 0xb2, 0x65, 0x47, 0xef, 0x6c, 0xcb, 0x4f, 0x56, + 0x12, 0x3b, 0x87, 0xfc, 0xef, 0x8f, 0x33, 0xfc, 0x10, 0x49, 0x51, 0xf2, 0x47, 0x62, 0x27, 0x9b, + 0x33, 0x8a, 0x6e, 0x2c, 0x72, 0x38, 0x1c, 0x92, 0xc3, 0xe1, 0xcc, 0x90, 0x1c, 0x7e, 0x9f, 0x8c, + 0x86, 0xf1, 0xa8, 0xf1, 0xcb, 0xaf, 0xfd, 0x0f, 0x97, 0x27, 0xf3, 0x2c, 0x1e, 0x24, 0x8b, 0x24, + 0x9d, 0x35, 0xae, 0x92, 0xf1, 0xd5, 0xbc, 0x31, 0x9a, 0xa4, 0x61, 0xee, 0x9f, 0x7c, 0x1f, 0x4f, + 0x16, 0xf1, 0xc9, 0xf7, 0xc9, 0xa8, 0xf1, 0x1d, 0x81, 0x4d, 0x66, 0xf1, 0xd0, 0x9a, 0xa4, 0xb7, + 0x73, 0xfb, 0xe4, 0x7b, 0xfa, 0xd9, 0x80, 0x2f, 0x02, 0x35, 0x1b, 0x26, 0x23, 0x15, 0x6c, 0x1a, + 0x0f, 0x93, 0xeb, 0xa9, 0x04, 0xc9, 0x12, 0x8c, 0xc0, 0x58, 0x67, 0x01, 0x8a, 0x9f, 0x02, 0x90, + 0xfe, 0xb9, 0x89, 0x07, 0xbd, 0xc6, 0xf5, 0x6c, 0x1e, 0x0e, 0xfe, 0xd5, 0x47, 0xe2, 0xac, 0x41, + 0x3a, 0x5b, 0xe4, 0x94, 0xd0, 0x06, 0x24, 0xc7, 0xc3, 0xbf, 0x87, 0x93, 0xeb, 0xd8, 0x6e, 0xfc, + 0x3b, 0x99, 0xf1, 0x94, 0x8b, 0x59, 0x8e, 0x89, 0x01, 0x49, 0xb2, 0x64, 0x20, 0x1f, 0x60, 0x6e, + 0x3a, 0x81, 0x0a, 0xe6, 0xf5, 0xce, 0x5f, 0xf9, 0x59, 0x9c, 0x5f, 0x67, 0xb3, 0x06, 0x54, 0x68, + 0xdd, 0x74, 0x5c, 0x15, 0xa2, 0x75, 0xd3, 0x71, 0x08, 0x90, 0xed, 0xdf, 0xcb, 0x04, 0xa5, 0xe4, + 0xdf, 0x24, 0x5f, 0x19, 0x48, 0xfa, 0x44, 0x73, 0x18, 0x51, 0xe4, 0x7f, 0x96, 0x20, 0x11, 0xc4, + 0x41, 0xbc, 0x9e, 0x52, 0x35, 0x6d, 0x64, 0x51, 0xc2, 0xf6, 0xba, 0xbd, 0xd7, 0xed, 0x8e, 0x3b, + 0x4d, 0x87, 0x6a, 0x41, 0xb7, 0xd7, 0xee, 0xd8, 0x94, 0xa0, 0xb3, 0xc6, 0x30, 0x1e, 0xa4, 0xc3, + 0xb8, 0x3f, 0x48, 0x27, 0x69, 0xc6, 0xc8, 0x41, 0x42, 0xe3, 0x19, 0xa4, 0x0f, 0x7f, 0x82, 0x74, + 0x42, 0x4c, 0x51, 0xd1, 0x99, 0xa5, 0x74, 0xaa, 0x0c, 0xf7, 0x67, 0xe7, 0x2b, 0x21, 0xea, 0xfc, + 0x9c, 0x54, 0x5a, 0x0d, 0xd3, 0xe5, 0x30, 0x27, 0x84, 0x04, 0xda, 0x72, 0x06, 0x3c, 0x4d, 0x96, + 0x7d, 0x6c, 0x89, 0x44, 0x86, 0x34, 0x04, 0xae, 0xdc, 0x59, 0x79, 0x41, 0x13, 0x29, 0x26, 0x8f, + 0x14, 0x21, 0xc2, 0x95, 0x3f, 0xbb, 0x5f, 0xdd, 0x9c, 0x37, 0x56, 0xaa, 0x48, 0x6b, 0xf0, 0x19, + 0xab, 0x09, 0x69, 0x5c, 0x94, 0xaa, 0x42, 0x88, 0x69, 0x32, 0xc3, 0xec, 0x40, 0xe9, 0x33, 0xa4, + 0x58, 0x2e, 0x5c, 0x10, 0xc0, 0xbe, 0x49, 0x8b, 0x6d, 0x9f, 0x62, 0x08, 0x97, 0x1b, 0x61, 0xe8, + 0x69, 0x18, 0x4e, 0x01, 0x83, 0xd4, 0x5c, 0x4e, 0x89, 0xcb, 0x11, 0xf2, 0x26, 0xf6, 0x1a, 0xe3, + 0x38, 0xef, 0xcf, 0xc3, 0x3c, 0x8f, 0xb3, 0x59, 0x7f, 0x9e, 0x2e, 0x94, 0xbe, 0x4c, 0x96, 0xf1, + 0x84, 0xd4, 0x99, 0x66, 0xc3, 0xfe, 0xf5, 0x7c, 0x1e, 0x67, 0x6e, 0x45, 0x26, 0x99, 0xa3, 0x5a, + 0x26, 0x43, 0xb8, 0x48, 0xee, 0xb4, 0x61, 0x48, 0x26, 0x71, 0xff, 0x7a, 0x96, 0xe4, 0x8b, 0x7e, + 0x9e, 0xf6, 0x11, 0xc7, 0x42, 0x29, 0x98, 0x2e, 0x68, 0xef, 0xf5, 0x1a, 0xe9, 0x68, 0xb4, 0x88, + 0xf3, 0x00, 0xb8, 0x91, 0xff, 0x5f, 0x26, 0x48, 0xae, 0xc8, 0x86, 0x79, 0xd3, 0xee, 0x98, 0xd2, + 0x9a, 0x65, 0x6a, 0x15, 0x28, 0xde, 0x57, 0x96, 0x89, 0x3e, 0x87, 0x10, 0xd5, 0xa4, 0xd4, 0xd8, + 0x9e, 0x5c, 0xcc, 0xbf, 0x3f, 0xf9, 0xcb, 0xf7, 0x66, 0x19, 0xc7, 0x64, 0xd1, 0xf3, 0x93, 0x72, + 0x7f, 0x21, 0xf4, 0x67, 0x49, 0x74, 0x9d, 0xc7, 0xb4, 0xc3, 0x43, 0x18, 0x74, 0x9f, 0xb4, 0x78, + 0x94, 0x66, 0x53, 0xc2, 0x6f, 0x39, 0x61, 0xfa, 0x3e, 0xf9, 0x93, 0x25, 0x4b, 0xff, 0x26, 0x4d, + 0x86, 0x24, 0x29, 0x99, 0x59, 0x64, 0x4c, 0xc6, 0x93, 0xfe, 0xe7, 0x74, 0x91, 0xe4, 0xa4, 0x75, + 0x01, 0x87, 0x70, 0x70, 0x7a, 0x23, 0x0a, 0xb7, 0xe3, 0x76, 0x6d, 0xe8, 0x10, 0x8e, 0x8a, 0xce, + 0x1f, 0xca, 0xb1, 0x02, 0x3f, 0x9b, 0xbe, 0x5c, 0x9c, 0x95, 0x6a, 0xf8, 0x39, 0x0b, 0xc7, 0x94, + 0xe1, 0x59, 0x49, 0xa7, 0x80, 0x3d, 0x61, 0x5d, 0xfd, 0xe9, 0xef, 0x1f, 0xbe, 0xbc, 0xff, 0xf2, + 0xee, 0x7f, 0xfa, 0x17, 0x1f, 0x2f, 0x3f, 0x7f, 0xf8, 0xe9, 0xf7, 0x4f, 0x5f, 0x4e, 0x94, 0x92, + 0x48, 0x53, 0x97, 0x48, 0x2c, 0x9f, 0xb7, 0x59, 0xa2, 0x4a, 0x6d, 0xa0, 0x44, 0x2b, 0x91, 0xb4, + 0x7d, 0x79, 0x6c, 0xfb, 0x61, 0x6d, 0x6e, 0x54, 0xca, 0xd5, 0x59, 0xb3, 0x0e, 0x00, 0x39, 0xb0, + 0xd4, 0x29, 0x8b, 0x41, 0x38, 0x91, 0xeb, 0x55, 0xd3, 0xa3, 0x52, 0xba, 0x89, 0x57, 0x7d, 0xe3, + 0xf0, 0xde, 0x84, 0xd9, 0x2a, 0x99, 0x8d, 0x69, 0xd2, 0x0d, 0x24, 0x91, 0x6a, 0x0c, 0x89, 0xd1, + 0x0e, 0x43, 0xce, 0xd0, 0x05, 0xba, 0x1c, 0x31, 0x74, 0x89, 0x6b, 0xe8, 0x05, 0x57, 0xb4, 0xdb, + 0xd1, 0x07, 0xc0, 0x35, 0x37, 0xd1, 0xc5, 0xca, 0x79, 0xc5, 0xd1, 0x83, 0x2b, 0x8e, 0xf4, 0x8a, + 0xa3, 0x35, 0x15, 0xab, 0x4c, 0x2e, 0xb3, 0x46, 0x3e, 0xa9, 0x66, 0x9b, 0x28, 0xab, 0xce, 0x23, + 0xe5, 0xa2, 0x9a, 0x72, 0xa5, 0xbc, 0x3c, 0x5e, 0xa2, 0xfc, 0xd1, 0x39, 0x62, 0x2a, 0xf1, 0xb4, + 0x3e, 0xd5, 0x78, 0xfa, 0x22, 0x9c, 0xce, 0x27, 0x71, 0xd6, 0x7b, 0x4f, 0xf2, 0x92, 0x69, 0x38, + 0x8e, 0x77, 0xe5, 0x0e, 0xcc, 0x41, 0x0c, 0xd8, 0xab, 0x28, 0xa8, 0x59, 0x69, 0x17, 0xa7, 0x1f, + 0x17, 0xe8, 0x01, 0xac, 0x40, 0x6a, 0x27, 0x79, 0xa2, 0x0d, 0xae, 0xda, 0x43, 0x52, 0x46, 0x81, + 0x9a, 0x2d, 0x86, 0x28, 0x10, 0xba, 0x01, 0xc9, 0x27, 0xb2, 0x3a, 0xee, 0xbd, 0xb7, 0x58, 0x03, + 0x5c, 0xca, 0x0e, 0x2a, 0x39, 0x84, 0x31, 0x0a, 0x82, 0x22, 0x95, 0xa0, 0x5e, 0x99, 0xa2, 0xa8, + 0x8a, 0xa2, 0xc8, 0x48, 0x51, 0x3f, 0x92, 0x69, 0xea, 0x99, 0x69, 0xea, 0xd9, 0xbe, 0x22, 0x98, + 0xa0, 0x52, 0xda, 0x06, 0x97, 0x16, 0x73, 0x71, 0xc4, 0xec, 0xc3, 0xc8, 0xb8, 0x28, 0x4d, 0x27, + 0x42, 0x98, 0xdc, 0x26, 0xf9, 0x15, 0x01, 0x98, 0xeb, 0xb9, 0xf3, 0x24, 0x1f, 0x5c, 0x95, 0x73, + 0x19, 0xdb, 0x91, 0x46, 0x66, 0xd7, 0x44, 0x0b, 0x41, 0x1c, 0x22, 0x13, 0x96, 0x2e, 0xc1, 0x6d, + 0xc3, 0xf8, 0x26, 0x19, 0xc4, 0x6c, 0xb6, 0x65, 0x21, 0x11, 0x1d, 0x02, 0x4e, 0x52, 0xfb, 0x61, + 0x5d, 0x08, 0xa7, 0x71, 0x16, 0xc2, 0xe4, 0x1a, 0xc4, 0x33, 0xd2, 0xd9, 0xfd, 0x61, 0xb2, 0xc8, + 0xc3, 0xd9, 0x20, 0x5e, 0x2b, 0xc1, 0x4e, 0x09, 0x3b, 0x0e, 0xc3, 0x3c, 0xc4, 0xce, 0x9a, 0x41, + 0x6f, 0xfd, 0xf7, 0xbb, 0xcb, 0xfe, 0x1f, 0x1f, 0x2f, 0x7e, 0xfe, 0xf4, 0xe5, 0xb7, 0x3e, 0x5b, + 0x37, 0x4e, 0x8c, 0xd4, 0x61, 0x56, 0x3f, 0x97, 0xaa, 0xa0, 0x44, 0xe1, 0x50, 0x86, 0x6c, 0xad, + 0xe2, 0x55, 0x49, 0x59, 0x34, 0x83, 0xad, 0xe2, 0x6a, 0x7b, 0x94, 0x65, 0x4e, 0x5a, 0x94, 0x0d, + 0x84, 0x65, 0x21, 0x59, 0xb9, 0x17, 0x66, 0xca, 0x68, 0x9e, 0x42, 0x1a, 0x57, 0x21, 0x58, 0x2f, + 0x50, 0x08, 0x41, 0x9d, 0xa2, 0x60, 0x34, 0x58, 0xa6, 0x46, 0xa1, 0x0a, 0xc3, 0x2b, 0x59, 0x43, + 0x65, 0x34, 0xb9, 0xae, 0xe8, 0x3d, 0xc8, 0x51, 0x28, 0xc4, 0x5c, 0x46, 0x1e, 0x64, 0x0a, 0xe2, + 0xa4, 0x62, 0x98, 0xae, 0xd1, 0x55, 0xc2, 0xba, 0x86, 0x24, 0x36, 0x3b, 0xcc, 0xe5, 0x59, 0x66, + 0x25, 0x61, 0x42, 0xd5, 0x28, 0xd3, 0x56, 0xcc, 0xba, 0x6a, 0xf2, 0x24, 0x98, 0x1a, 0x0a, 0x17, + 0x79, 0x96, 0xfe, 0x2b, 0xae, 0x63, 0x3d, 0x19, 0xa2, 0x9a, 0x03, 0x65, 0x28, 0x13, 0x23, 0x2a, + 0xf9, 0x75, 0xfc, 0xa8, 0x03, 0xae, 0xa7, 0xfd, 0x36, 0x19, 0xe6, 0x57, 0xb5, 0xb4, 0x23, 0x44, + 0x1d, 0x8b, 0xca, 0x70, 0x15, 0x8c, 0xaa, 0x80, 0xac, 0x61, 0x57, 0x1d, 0x76, 0x7d, 0x1b, 0x6a, + 0x19, 0x45, 0x85, 0xa9, 0xe4, 0x17, 0x15, 0xcc, 0xc4, 0x36, 0x1a, 0x44, 0x1d, 0xf7, 0x94, 0x41, + 0xa9, 0xab, 0x41, 0xac, 0xa3, 0xf0, 0x8b, 0xac, 0xa5, 0xb5, 0xa2, 0x6c, 0x40, 0x15, 0x62, 0xdd, + 0x14, 0x65, 0xf2, 0xca, 0x15, 0x62, 0xcd, 0xe6, 0xa4, 0xe8, 0x92, 0x2b, 0xd8, 0x4a, 0x3e, 0xd1, + 0x3f, 0x81, 0x6e, 0x63, 0x73, 0x09, 0xe4, 0x16, 0xc2, 0x4a, 0x54, 0x68, 0x12, 0x46, 0xc1, 0x36, + 0xf2, 0x06, 0xfe, 0x31, 0xd4, 0x08, 0xc9, 0x2e, 0x17, 0x3c, 0xa2, 0x36, 0x4d, 0xba, 0x04, 0x5b, + 0xc9, 0x10, 0xf6, 0xd7, 0x50, 0x19, 0xcb, 0x71, 0x25, 0x91, 0x62, 0xaa, 0x52, 0x20, 0xd8, 0x45, + 0x34, 0xc8, 0x1f, 0xa6, 0x11, 0x95, 0xf3, 0x5d, 0x5d, 0x68, 0x98, 0xc6, 0x57, 0x45, 0xb8, 0xf3, + 0xb4, 0x97, 0x3f, 0x0c, 0x5d, 0x23, 0x67, 0xbb, 0xba, 0x3c, 0xa8, 0xe0, 0x02, 0x15, 0xe5, 0x03, + 0x26, 0xb3, 0xfa, 0x59, 0x4d, 0x5d, 0x31, 0x7e, 0xfa, 0x4c, 0x37, 0x0d, 0xa3, 0x8e, 0xb5, 0x72, + 0xaa, 0xa2, 0x6f, 0x8b, 0x2a, 0x3e, 0x01, 0x56, 0x08, 0x6a, 0x25, 0xb5, 0x7f, 0xc0, 0x2d, 0xe6, + 0x90, 0x7f, 0x5a, 0x85, 0x76, 0x39, 0x48, 0xb2, 0x01, 0xd1, 0xaf, 0xa8, 0x4e, 0x13, 0x90, 0xaa, + 0x70, 0x58, 0x09, 0xb0, 0xd3, 0x69, 0x9f, 0xdb, 0x3e, 0x31, 0xd6, 0x2d, 0x5d, 0xcb, 0xe2, 0xaa, + 0xf4, 0x20, 0xcd, 0x66, 0x44, 0x0f, 0x9a, 0x73, 0x8b, 0x4b, 0x41, 0xc5, 0x4a, 0xaa, 0xda, 0x1b, + 0x29, 0xa9, 0x15, 0x6a, 0x06, 0x8c, 0x54, 0xc7, 0xa2, 0x93, 0xaf, 0x29, 0xf7, 0x3b, 0x68, 0x9a, + 0xaa, 0x0e, 0x77, 0xdf, 0x80, 0x7e, 0x61, 0xee, 0xaa, 0x79, 0x96, 0xfe, 0x6f, 0x3c, 0xc8, 0xe3, + 0x21, 0x27, 0x5f, 0xb5, 0xf9, 0x14, 0x7a, 0xa8, 0xed, 0xf7, 0xb0, 0xda, 0x1d, 0x4b, 0xaf, 0xb1, + 0x7d, 0xeb, 0xd5, 0x68, 0x86, 0xc4, 0xf2, 0xaa, 0xb6, 0x48, 0x35, 0x52, 0x98, 0x3b, 0x82, 0x35, + 0xaf, 0xa6, 0x58, 0xb9, 0x51, 0x15, 0x3d, 0x2d, 0xe1, 0x68, 0x2f, 0x57, 0xdb, 0x36, 0xb5, 0x4e, + 0xe1, 0x35, 0x50, 0xb9, 0x43, 0x0d, 0x72, 0xe9, 0x5b, 0xff, 0xfe, 0x5e, 0xe2, 0xf5, 0x70, 0x96, + 0x27, 0xe1, 0x24, 0x09, 0x17, 0x28, 0x2e, 0x09, 0xb3, 0x7a, 0x26, 0x45, 0xdd, 0x33, 0xd6, 0xe3, + 0x53, 0x65, 0x1b, 0x58, 0xff, 0xd4, 0x62, 0x35, 0xb6, 0x97, 0x2e, 0xff, 0xb5, 0x72, 0x15, 0xe4, + 0x68, 0x1c, 0x6f, 0xad, 0xab, 0xef, 0x5b, 0xe3, 0x3e, 0x8c, 0xce, 0xbc, 0x67, 0xe5, 0xf7, 0x70, + 0xfa, 0xeb, 0x53, 0xe8, 0x9d, 0x4f, 0xa9, 0x2d, 0xee, 0x59, 0xc5, 0x63, 0xea, 0x5d, 0x15, 0xf3, + 0x6f, 0xa2, 0xac, 0x55, 0x72, 0xf6, 0xc6, 0x8a, 0x57, 0x05, 0xcf, 0xae, 0x57, 0xa5, 0xaa, 0x19, + 0x72, 0x53, 0x9d, 0x68, 0x0d, 0xb7, 0x6d, 0xaf, 0xcc, 0xac, 0x61, 0xa5, 0x9d, 0xd4, 0x90, 0xb5, + 0x4c, 0xf2, 0x60, 0xd5, 0x01, 0xe5, 0x20, 0x91, 0xeb, 0x3e, 0x45, 0xc2, 0x85, 0xf7, 0x24, 0x9e, + 0x8d, 0x09, 0x65, 0xf4, 0x0f, 0x17, 0xb0, 0xb6, 0x5f, 0x29, 0xbd, 0x19, 0x9e, 0x3b, 0x5f, 0xcb, + 0x24, 0x6b, 0x28, 0xe6, 0xb7, 0xa6, 0xe1, 0xd2, 0x42, 0xbd, 0x59, 0x13, 0xcc, 0xca, 0x48, 0xf5, + 0xf3, 0x60, 0x31, 0x4d, 0xd3, 0xfc, 0x6a, 0x91, 0xc7, 0x73, 0xab, 0xd3, 0xee, 0xb8, 0x3a, 0x22, + 0x57, 0x25, 0x90, 0xaa, 0x38, 0x14, 0x07, 0x53, 0x47, 0x03, 0xb9, 0x2f, 0x1b, 0x7f, 0x6b, 0x10, + 0x2c, 0xdd, 0xc6, 0x8f, 0xf0, 0xa7, 0xf1, 0x43, 0x43, 0xc2, 0x5e, 0xc2, 0x0c, 0xd5, 0x69, 0xd8, + 0x29, 0xc3, 0x9a, 0x57, 0x20, 0xcd, 0x8b, 0x26, 0x5a, 0xe0, 0x08, 0x7f, 0x9a, 0xc3, 0x55, 0x3f, + 0x99, 0x63, 0x1c, 0x4d, 0x2d, 0x94, 0x94, 0xe8, 0x07, 0xf8, 0xd8, 0xf6, 0xbd, 0x7b, 0x52, 0xbd, + 0x21, 0x52, 0x90, 0xb3, 0xd6, 0xd5, 0xc7, 0x45, 0x93, 0xd9, 0x5f, 0x57, 0xe5, 0x18, 0xe6, 0xe9, + 0x09, 0xd1, 0x4e, 0x66, 0x0b, 0xc8, 0xd9, 0x64, 0x2f, 0x81, 0xd5, 0x51, 0xb5, 0xc0, 0xdf, 0xc6, + 0x64, 0x7a, 0xe7, 0x66, 0xc9, 0x49, 0xf3, 0xcc, 0xce, 0x10, 0xa8, 0x8d, 0xe6, 0x6b, 0x6e, 0x10, + 0x5a, 0x98, 0x65, 0x19, 0x57, 0x22, 0x15, 0xfd, 0x21, 0x7c, 0x72, 0xdb, 0xa9, 0x10, 0x74, 0xb7, + 0x53, 0xa6, 0xf5, 0x9f, 0x1f, 0xbe, 0x7c, 0x42, 0xb5, 0x0c, 0xb7, 0xb9, 0xbd, 0xee, 0xab, 0x76, + 0xc7, 0x17, 0x9b, 0x78, 0xbf, 0xbc, 0xfb, 0xe3, 0xf2, 0xb2, 0xff, 0xd3, 0xa7, 0x0f, 0x3f, 0x93, + 0xa9, 0x75, 0xfa, 0xf6, 0xcd, 0xdb, 0xb3, 0x5e, 0xef, 0x4d, 0xe7, 0xac, 0xd3, 0x3d, 0x3b, 0xed, + 0xbd, 0xde, 0xd8, 0x93, 0xc0, 0xc6, 0x81, 0xfe, 0x31, 0xd8, 0x50, 0x34, 0xc3, 0x2d, 0x06, 0x45, + 0x33, 0x36, 0xe5, 0x6e, 0x0f, 0xb6, 0xeb, 0x5b, 0xf3, 0x1a, 0xf5, 0xe8, 0xde, 0x05, 0x76, 0x5a, + 0x02, 0x79, 0x7d, 0xd8, 0xdf, 0xc8, 0x62, 0xa3, 0x08, 0x2f, 0x83, 0xc5, 0xff, 0x65, 0xb9, 0xd5, + 0x22, 0xc9, 0xce, 0x24, 0x1d, 0x5b, 0x30, 0x1a, 0x1e, 0x6d, 0xa0, 0x27, 0xcd, 0x06, 0xaf, 0x18, + 0x08, 0xdb, 0xf6, 0x4e, 0xc9, 0x10, 0x09, 0xe6, 0x0f, 0x2e, 0x1d, 0xbd, 0x62, 0x5f, 0x13, 0xfe, + 0x5c, 0x97, 0xa7, 0x44, 0x97, 0xec, 0x30, 0x6a, 0x7f, 0xa5, 0x0b, 0x3a, 0xcb, 0x75, 0xb3, 0xb1, + 0xc9, 0x80, 0xa9, 0x94, 0x30, 0x8a, 0x12, 0x98, 0x99, 0x92, 0x5c, 0x50, 0x67, 0x42, 0x31, 0xa3, + 0x77, 0x9a, 0xbc, 0x8f, 0x35, 0x01, 0xb7, 0x64, 0xe8, 0x4a, 0xbd, 0x89, 0x91, 0xb5, 0x09, 0x63, + 0xd2, 0xdc, 0x61, 0xd0, 0x22, 0xdd, 0xe8, 0x90, 0x31, 0xc3, 0xff, 0x87, 0x69, 0x6e, 0x89, 0xb6, + 0xbb, 0xe2, 0x17, 0xe7, 0x87, 0x9b, 0x70, 0x12, 0x50, 0x34, 0x8e, 0xd4, 0x75, 0x4e, 0x41, 0xb6, + 0x13, 0x2f, 0xe7, 0xd6, 0x50, 0x5b, 0x96, 0x70, 0xe0, 0x48, 0x51, 0xd8, 0x69, 0xe2, 0xff, 0xdb, + 0x07, 0xd8, 0xb3, 0xbe, 0x4d, 0xb3, 0xc9, 0x70, 0xd3, 0x5d, 0xdf, 0xad, 0xd6, 0x24, 0x87, 0x21, + 0x97, 0xb6, 0x79, 0xdb, 0xcb, 0x20, 0xa4, 0x7f, 0xd9, 0xf7, 0x0a, 0xc4, 0x56, 0x8b, 0xa6, 0xad, + 0x64, 0x06, 0x2c, 0xef, 0x32, 0x9a, 0x72, 0xe8, 0x9a, 0x9c, 0x91, 0x94, 0xea, 0x13, 0x02, 0x6b, + 0x1a, 0xc1, 0x8e, 0x95, 0x18, 0x76, 0xe0, 0x10, 0xd8, 0x6e, 0x67, 0xd2, 0x46, 0x9d, 0x02, 0x55, + 0x54, 0xee, 0xa2, 0x94, 0xc8, 0x5d, 0x98, 0x6b, 0xda, 0xb0, 0x3e, 0xe8, 0x10, 0x42, 0x67, 0x13, + 0xe5, 0xa1, 0x94, 0x18, 0xce, 0x06, 0x57, 0x69, 0x66, 0xce, 0xe3, 0x13, 0xb6, 0x8c, 0x69, 0x12, + 0x0e, 0x62, 0x03, 0x1f, 0x2c, 0xae, 0x92, 0x51, 0xee, 0x6f, 0xc4, 0x49, 0xf5, 0xda, 0x42, 0xb5, + 0xfb, 0x82, 0x8f, 0x10, 0x9b, 0x3d, 0x9c, 0x14, 0x3d, 0x79, 0x96, 0xe6, 0x7f, 0x2c, 0x20, 0x5d, + 0xdb, 0x43, 0x96, 0xfc, 0x4e, 0x9f, 0x53, 0x32, 0xdd, 0x4a, 0xac, 0x58, 0xf4, 0x07, 0xe5, 0x44, + 0x79, 0xde, 0x17, 0x54, 0x31, 0x28, 0x4e, 0x55, 0xa0, 0x22, 0x6d, 0xdf, 0xaa, 0xc5, 0xd2, 0xc9, + 0x04, 0xcf, 0xe9, 0xf4, 0xe7, 0x71, 0xb6, 0x98, 0x13, 0xb8, 0xe4, 0x26, 0xa6, 0x5e, 0x90, 0x60, + 0x30, 0x21, 0x1c, 0x41, 0x86, 0xee, 0xbc, 0x09, 0x32, 0xc3, 0xaa, 0x69, 0xb9, 0x57, 0x59, 0xbb, + 0x8d, 0x3a, 0xee, 0x19, 0x0c, 0xff, 0x5a, 0xc5, 0x8f, 0x8b, 0x0a, 0xdd, 0xfb, 0x63, 0x89, 0xd1, + 0x6e, 0xb2, 0x61, 0x5c, 0xe3, 0xf3, 0x71, 0x6a, 0x5a, 0xe5, 0xf3, 0x61, 0x09, 0x38, 0xab, 0xe0, + 0x14, 0x66, 0x63, 0x52, 0x24, 0xae, 0x64, 0xff, 0xcd, 0x2e, 0x03, 0xca, 0xac, 0x92, 0xc9, 0xfc, + 0x2a, 0x0c, 0x48, 0xff, 0xf9, 0x46, 0x29, 0x87, 0x8d, 0xe6, 0x0d, 0x77, 0x10, 0x18, 0xbd, 0x6e, + 0xbc, 0xaa, 0xc6, 0x7f, 0x35, 0x60, 0x2a, 0x9a, 0x14, 0x60, 0xa9, 0x24, 0x4e, 0x57, 0x56, 0xfa, + 0x9e, 0x16, 0x67, 0x24, 0x19, 0xcb, 0x3b, 0x41, 0xbb, 0xeb, 0xdf, 0x1f, 0x64, 0x16, 0x3e, 0xab, + 0xe9, 0xa6, 0xa5, 0x6b, 0xdb, 0xc8, 0x9a, 0x22, 0x60, 0x4e, 0xe6, 0x4a, 0xca, 0x71, 0xe6, 0x1a, + 0x67, 0xae, 0x4c, 0xdf, 0x3c, 0x1c, 0x0e, 0x49, 0x07, 0xf6, 0x47, 0xe1, 0x20, 0x4f, 0xc1, 0xd7, + 0xda, 0x2b, 0x4d, 0x6c, 0xc1, 0x3f, 0xa5, 0xe9, 0xac, 0x16, 0xde, 0xc7, 0xec, 0xe6, 0xe3, 0x1f, + 0x84, 0xd1, 0xa2, 0x10, 0x30, 0xed, 0x95, 0x2d, 0x29, 0xb3, 0x05, 0x7d, 0x2a, 0x3d, 0xbe, 0xc6, + 0x0f, 0xc1, 0x16, 0x3e, 0xee, 0x5a, 0xea, 0x25, 0xb5, 0x41, 0xac, 0xfe, 0x37, 0x04, 0x0a, 0x3d, + 0xf0, 0xbc, 0xee, 0xe7, 0xc1, 0xf5, 0xba, 0x78, 0x93, 0x54, 0x8b, 0xad, 0x85, 0xdb, 0x60, 0x57, + 0xa9, 0x36, 0x60, 0xe2, 0xac, 0xc7, 0x8f, 0x43, 0x2b, 0x04, 0x6b, 0x1e, 0x25, 0xad, 0x39, 0x76, + 0xad, 0xfb, 0xa9, 0xd0, 0x85, 0x1d, 0x13, 0x4e, 0xdf, 0xe0, 0x52, 0xeb, 0x12, 0x8b, 0xd5, 0x08, + 0xec, 0x19, 0x46, 0x51, 0xb1, 0xe0, 0xf8, 0xa8, 0xd4, 0x55, 0xc5, 0xf9, 0x07, 0x58, 0x2a, 0x1e, + 0x8e, 0x63, 0xe4, 0x5b, 0xa3, 0xef, 0xa8, 0xd6, 0xc1, 0xd5, 0x52, 0x36, 0x30, 0xa1, 0xa7, 0x5b, + 0x3a, 0xe6, 0x4a, 0x2f, 0x13, 0x75, 0x3f, 0xde, 0x1f, 0xee, 0xe0, 0xac, 0x61, 0x97, 0x63, 0xed, + 0x31, 0xd9, 0x2d, 0xe9, 0xfb, 0xd6, 0x4e, 0x4e, 0x3d, 0xa7, 0x03, 0x40, 0x25, 0x03, 0xf5, 0xc9, + 0xcf, 0x6d, 0x1c, 0xe0, 0x68, 0xc3, 0xa6, 0x3c, 0xfc, 0x24, 0xbb, 0x7c, 0x8f, 0xbc, 0x43, 0xb6, + 0xe7, 0x9d, 0x9b, 0xad, 0xb6, 0x4f, 0x0c, 0xb6, 0xe8, 0xa3, 0x1c, 0x15, 0xdd, 0x42, 0x56, 0x18, + 0xfd, 0x0d, 0x06, 0xab, 0xbc, 0x6a, 0x70, 0xae, 0xf3, 0x49, 0x32, 0xab, 0x3d, 0x1a, 0xa7, 0x80, + 0x54, 0xcb, 0x18, 0x05, 0xcc, 0x24, 0x6b, 0x54, 0x80, 0x3a, 0xae, 0x2a, 0x41, 0xbe, 0x20, 0xd9, + 0xa3, 0x76, 0xb8, 0xf2, 0x65, 0x92, 0x45, 0x0a, 0x80, 0x5b, 0x1a, 0x0c, 0x93, 0x6c, 0xd2, 0x70, + 0xee, 0xd4, 0x9b, 0x4f, 0x2d, 0xab, 0x90, 0x67, 0x03, 0x4b, 0xd5, 0xcd, 0x3d, 0x45, 0xe3, 0x6e, + 0xc2, 0xa4, 0xf1, 0xc0, 0x2b, 0xcc, 0xb9, 0x5e, 0x3d, 0xdb, 0xb0, 0x15, 0xe3, 0x1f, 0x9c, 0x5d, + 0x0f, 0x27, 0x0c, 0xd5, 0x86, 0xee, 0xc2, 0x27, 0x0f, 0x14, 0x92, 0x85, 0xaa, 0x58, 0xe8, 0xb1, + 0x64, 0x60, 0x5a, 0x42, 0x0c, 0xa6, 0x19, 0x31, 0x88, 0x56, 0x5c, 0x43, 0xa4, 0xda, 0x3b, 0xf8, + 0x2d, 0xb5, 0x2d, 0x50, 0xd0, 0xbe, 0x01, 0x8b, 0xae, 0x0a, 0xca, 0x64, 0x3b, 0x16, 0x16, 0xe7, + 0x52, 0xf8, 0x70, 0x1e, 0xde, 0xc7, 0xbb, 0x6e, 0xc4, 0x4f, 0x6a, 0xa0, 0x75, 0xf3, 0xd0, 0xeb, + 0x42, 0x9b, 0x4f, 0x87, 0x67, 0x7f, 0x86, 0x9b, 0x5f, 0xfa, 0x18, 0x65, 0xe9, 0xd4, 0x8c, 0x47, + 0x86, 0x30, 0xd2, 0x0a, 0xcb, 0x94, 0x0c, 0xa4, 0x12, 0xcc, 0x6e, 0x8d, 0x4a, 0xd9, 0x26, 0xa2, + 0xd9, 0xf0, 0xe8, 0x70, 0x1b, 0x10, 0x9e, 0xa7, 0xf5, 0x64, 0x13, 0x4b, 0x67, 0x1d, 0xd1, 0x79, + 0x5a, 0x43, 0x32, 0xc9, 0xdc, 0x80, 0x60, 0x0a, 0xb5, 0xf9, 0x72, 0xf5, 0x54, 0xe7, 0x72, 0x95, + 0xe1, 0x96, 0x3f, 0x82, 0xb0, 0x6f, 0x1a, 0x24, 0x69, 0xeb, 0x57, 0x1d, 0xc5, 0x60, 0xd7, 0xc1, + 0x2a, 0x7e, 0x06, 0x61, 0xbf, 0xdc, 0xc9, 0xc6, 0x0a, 0x09, 0xac, 0xb9, 0xab, 0xe5, 0x5b, 0xb7, + 0x70, 0xc3, 0x2a, 0x90, 0x69, 0x82, 0x63, 0x27, 0x0a, 0x04, 0x5c, 0xb5, 0x52, 0x21, 0xee, 0x6e, + 0x7d, 0x1d, 0x47, 0x14, 0x14, 0x15, 0x99, 0x30, 0x28, 0xf9, 0xa4, 0x3c, 0xf3, 0x80, 0x81, 0xe0, + 0xf9, 0x82, 0x0e, 0x39, 0x26, 0x64, 0xda, 0x4b, 0xbf, 0xb8, 0xfc, 0xab, 0xe6, 0xf0, 0xd3, 0x30, + 0x40, 0xc2, 0x25, 0x73, 0x2a, 0xd1, 0x1c, 0x7e, 0xc0, 0x25, 0x4f, 0xd5, 0xf4, 0x5b, 0x7f, 0xb3, + 0xf5, 0x1d, 0x68, 0x25, 0xc2, 0x7c, 0x3e, 0x09, 0x57, 0xec, 0x3a, 0x21, 0xdd, 0x0b, 0xb6, 0xe4, + 0x2e, 0x68, 0x2f, 0x5b, 0x72, 0x9f, 0xb5, 0x97, 0xb6, 0x57, 0x90, 0xef, 0xaa, 0xa0, 0x2b, 0x15, + 0x74, 0x25, 0x83, 0x9a, 0xea, 0x8b, 0xca, 0xf5, 0x45, 0x6a, 0x7d, 0x51, 0x4d, 0x7d, 0x91, 0x5a, + 0x5f, 0x54, 0xaa, 0xef, 0x81, 0xb7, 0x2e, 0x45, 0x87, 0x3b, 0x6a, 0x27, 0xb9, 0x62, 0x8c, 0x1e, + 0xeb, 0x9a, 0x25, 0x1b, 0x40, 0xb5, 0x9e, 0xa8, 0xa2, 0x9e, 0x1d, 0x34, 0xb2, 0x35, 0x57, 0x23, + 0xab, 0x37, 0x22, 0xb9, 0x78, 0x1c, 0x85, 0xc3, 0x78, 0xaf, 0x4b, 0xde, 0xe1, 0x56, 0xad, 0x43, + 0x2f, 0x37, 0xfb, 0x5c, 0x2b, 0xf6, 0x71, 0xf0, 0x50, 0xe9, 0xac, 0x5d, 0x04, 0x7a, 0x6d, 0x6f, + 0x7c, 0x73, 0x02, 0x7b, 0xbb, 0x1b, 0xbc, 0x15, 0xf7, 0x77, 0x9f, 0xe8, 0xf6, 0x6e, 0xc5, 0xdd, + 0xdd, 0x47, 0xbb, 0xb9, 0xbb, 0x67, 0xa3, 0xc2, 0x74, 0x17, 0x18, 0x04, 0x11, 0x73, 0xfd, 0x3b, + 0x07, 0x0c, 0x7a, 0xf0, 0x3c, 0x2c, 0x89, 0xa3, 0xd9, 0x70, 0x34, 0x1b, 0x8e, 0x66, 0xc3, 0xd1, + 0x6c, 0xa8, 0x30, 0x1b, 0xfe, 0x99, 0xa6, 0xd3, 0x87, 0x9b, 0x0e, 0x2f, 0xdd, 0x2a, 0x38, 0x48, + 0xc0, 0x96, 0x5a, 0xd3, 0x41, 0x8c, 0xd3, 0x01, 0xcc, 0x87, 0x52, 0x5d, 0xeb, 0xad, 0x01, 0x45, + 0xe7, 0x7f, 0x8c, 0x88, 0x28, 0x47, 0xd5, 0xff, 0xa8, 0xfa, 0x1f, 0x55, 0xff, 0x97, 0xa5, 0xfa, + 0x6f, 0xa8, 0xa8, 0x1f, 0x46, 0x45, 0x3f, 0x25, 0xa9, 0x13, 0x38, 0x8c, 0xae, 0x06, 0x52, 0xe3, + 0x53, 0x4a, 0x64, 0xcb, 0x1b, 0xb8, 0x8a, 0x2c, 0xc1, 0xdc, 0xe2, 0x06, 0x80, 0x2e, 0x09, 0x6f, + 0xe2, 0x2c, 0x4f, 0x88, 0x84, 0xed, 0x8f, 0xe1, 0x1c, 0x4d, 0x3c, 0xcb, 0xfd, 0x5a, 0x89, 0xb4, + 0xfe, 0xf0, 0x24, 0xe8, 0x85, 0x33, 0x52, 0x9e, 0xa0, 0x8c, 0x95, 0x8d, 0xe2, 0x33, 0x22, 0x34, + 0xf9, 0xd6, 0x8f, 0xf9, 0x16, 0x6d, 0x58, 0x79, 0x4d, 0x96, 0xe4, 0x54, 0xdf, 0x13, 0x82, 0xdc, + 0xfa, 0x9b, 0x08, 0x1c, 0xa2, 0x46, 0xb4, 0x5d, 0xd5, 0x5c, 0x54, 0xba, 0x5a, 0x73, 0x51, 0xe9, + 0x6a, 0x83, 0xcb, 0x10, 0x57, 0x9b, 0xdc, 0x98, 0x79, 0xe8, 0x01, 0x9c, 0xcd, 0x4f, 0x52, 0x6c, + 0xa2, 0x63, 0xe3, 0x78, 0xc8, 0xad, 0x80, 0x04, 0x53, 0x94, 0x0e, 0x92, 0xec, 0xf2, 0x41, 0x32, + 0xde, 0x1b, 0xa2, 0x05, 0xb7, 0x18, 0x06, 0xb9, 0xf0, 0x55, 0xd5, 0x9d, 0xa5, 0x2b, 0x7e, 0x67, + 0xe9, 0xaa, 0xee, 0xce, 0x12, 0x2f, 0xbe, 0xcd, 0x08, 0x94, 0x4f, 0x76, 0x3c, 0xe2, 0x21, 0x1e, + 0x9c, 0xb5, 0x74, 0x86, 0x04, 0xd2, 0x54, 0x21, 0x52, 0xfb, 0xce, 0xc7, 0x8e, 0x82, 0x1b, 0x9c, + 0xe0, 0x3a, 0x80, 0x0f, 0xdb, 0x67, 0xf4, 0xf3, 0x44, 0xfa, 0xc9, 0xdd, 0x0e, 0x34, 0x3c, 0x26, + 0xc5, 0xd1, 0x5e, 0xe2, 0xf5, 0xa6, 0xb5, 0x4a, 0x60, 0x8e, 0x07, 0x09, 0x3b, 0x8d, 0x1f, 0x59, + 0xd7, 0x34, 0x7e, 0xc0, 0xf1, 0x01, 0xd5, 0x50, 0xba, 0xdf, 0x79, 0x83, 0x41, 0x6d, 0xf1, 0x67, + 0x3b, 0x73, 0x3a, 0xed, 0x5e, 0xb7, 0xf7, 0xaa, 0x49, 0x3f, 0xc7, 0xe4, 0xf3, 0x75, 0xf7, 0xbc, + 0xc7, 0x3e, 0x23, 0xf2, 0xd9, 0x79, 0xdd, 0xeb, 0xf9, 0x6c, 0x7a, 0xab, 0x47, 0x1a, 0xc5, 0x29, + 0x59, 0xca, 0xa8, 0xd3, 0x08, 0x64, 0x0c, 0xca, 0x24, 0x01, 0x77, 0xea, 0x16, 0xff, 0x20, 0x28, + 0xa2, 0x69, 0x06, 0x32, 0xb0, 0xf0, 0xc7, 0x64, 0x70, 0x74, 0x34, 0x9d, 0x91, 0xbe, 0xa3, 0xc7, + 0x7d, 0xe1, 0x32, 0x0f, 0x6d, 0xbf, 0xd7, 0x7d, 0x75, 0xfa, 0xe6, 0x0c, 0x42, 0xc9, 0x0a, 0x89, + 0x68, 0x17, 0xd5, 0xcb, 0x25, 0x41, 0xa6, 0x83, 0x24, 0x6e, 0xe9, 0xd2, 0xd1, 0x86, 0xf8, 0xa8, + 0x34, 0xab, 0xe8, 0x84, 0x66, 0x19, 0x0a, 0x30, 0xba, 0x12, 0x46, 0x1a, 0x34, 0x82, 0x0d, 0xc3, + 0xaa, 0xf1, 0x5d, 0x00, 0x37, 0x3f, 0x1a, 0xff, 0x96, 0x20, 0x9c, 0x80, 0xd7, 0x58, 0x12, 0xb8, + 0x76, 0xd3, 0x32, 0xa4, 0x3a, 0xb4, 0x79, 0x56, 0xde, 0x44, 0x36, 0x70, 0xe6, 0xe9, 0xad, 0x45, + 0xc7, 0xcb, 0xeb, 0x9e, 0x77, 0xd8, 0x39, 0x51, 0x17, 0x5a, 0x42, 0x06, 0x83, 0x7c, 0xbc, 0x7d, + 0xe3, 0x9a, 0x5b, 0x04, 0xb4, 0x62, 0xf0, 0xde, 0x3e, 0x1b, 0xcc, 0x26, 0xeb, 0x39, 0x3e, 0xb6, + 0x32, 0x95, 0xf2, 0x5a, 0xd3, 0xce, 0x18, 0x7a, 0xa8, 0xeb, 0x54, 0xc6, 0xce, 0xb2, 0x6d, 0x36, + 0xb0, 0x0c, 0xf1, 0x58, 0x45, 0x3c, 0xae, 0x46, 0x3c, 0xae, 0x47, 0x3c, 0xd6, 0x10, 0x47, 0x2a, + 0xe2, 0xa8, 0x1a, 0x71, 0x54, 0x8f, 0x38, 0x52, 0x11, 0x3b, 0x92, 0xee, 0xa8, 0x1e, 0xed, 0x28, + 0x96, 0xaa, 0x9a, 0xfb, 0xb8, 0xd2, 0x62, 0xf6, 0x6c, 0x3d, 0x74, 0xda, 0x0a, 0xc6, 0x8e, 0xe1, + 0x1a, 0xfd, 0x77, 0x0f, 0x54, 0x0c, 0xf6, 0xa8, 0xb2, 0x3c, 0x40, 0xe7, 0xd8, 0x7c, 0x2f, 0x07, + 0x86, 0x9c, 0xd5, 0x3b, 0x7e, 0x04, 0x05, 0x45, 0x09, 0x8d, 0x07, 0xcb, 0x9e, 0x29, 0x3a, 0x88, + 0x41, 0x6f, 0x29, 0x61, 0x7d, 0x5c, 0xb5, 0x45, 0x26, 0xeb, 0x4a, 0xbd, 0x5e, 0x2d, 0x15, 0x35, + 0xeb, 0x33, 0x06, 0xdc, 0x47, 0xd7, 0xe8, 0x33, 0x74, 0x8d, 0x22, 0x97, 0x6e, 0xa5, 0xaa, 0x69, + 0x3c, 0xb9, 0x9d, 0xa6, 0xb6, 0xbd, 0x76, 0x56, 0xe2, 0xb4, 0x60, 0x17, 0x7e, 0x3a, 0xfa, 0x5e, + 0xbf, 0x9d, 0x23, 0x1b, 0x75, 0x2a, 0x2f, 0xbb, 0x8f, 0x32, 0x1c, 0xc7, 0xe2, 0x06, 0x98, 0x0c, + 0xf2, 0xf2, 0x9d, 0xb6, 0x8f, 0xa1, 0xf3, 0xd3, 0x9c, 0xbb, 0xa0, 0x42, 0xb7, 0x5f, 0x6b, 0x13, + 0xdc, 0x89, 0x33, 0x33, 0xe0, 0xf2, 0xe1, 0xb8, 0x03, 0xd8, 0xd0, 0x6c, 0xfc, 0xf5, 0xaf, 0x0d, + 0xae, 0xd9, 0x06, 0xa0, 0xd8, 0x4a, 0x09, 0x77, 0x04, 0x82, 0x2a, 0xdd, 0x27, 0x3f, 0xd2, 0x75, + 0xf9, 0xe4, 0x07, 0xfa, 0xb6, 0x84, 0x3c, 0x9e, 0xee, 0x9d, 0xa3, 0x69, 0x20, 0x07, 0x39, 0xbf, + 0x72, 0x98, 0xd3, 0x2b, 0xac, 0x16, 0xae, 0x3a, 0x54, 0x18, 0x3f, 0x1b, 0x5a, 0x2f, 0xa7, 0x8f, + 0x61, 0xbd, 0xc0, 0x05, 0xc8, 0x97, 0x62, 0xb2, 0xf0, 0x6e, 0x6d, 0x67, 0x63, 0x61, 0x05, 0x54, + 0x69, 0xff, 0x88, 0x19, 0xc3, 0xd4, 0x41, 0x53, 0x5c, 0xf6, 0xeb, 0xd4, 0x2e, 0xd9, 0x01, 0x2c, + 0x0f, 0x6b, 0x91, 0x86, 0x4e, 0x33, 0x07, 0x0e, 0xbd, 0x93, 0xb0, 0x8b, 0x2e, 0xba, 0x5f, 0xa5, + 0xf2, 0x50, 0x9a, 0xe1, 0xcb, 0xde, 0xba, 0xc0, 0x81, 0x5a, 0xaf, 0x61, 0x55, 0x8e, 0xc2, 0x66, + 0xda, 0xd2, 0x71, 0xc3, 0xe3, 0xb8, 0xe1, 0xb1, 0xf3, 0x86, 0x07, 0x7b, 0xac, 0x68, 0xc9, 0x9e, + 0x0f, 0xaa, 0xde, 0xf3, 0x28, 0x6d, 0x8d, 0xb0, 0x12, 0x8e, 0x26, 0xaf, 0xf6, 0xeb, 0x0f, 0x19, + 0x26, 0x53, 0x58, 0x29, 0xd2, 0x99, 0xbf, 0x59, 0x28, 0x07, 0xd6, 0xec, 0xc7, 0x88, 0x89, 0x23, + 0xc7, 0x31, 0xa0, 0x11, 0x9e, 0xe6, 0x8b, 0x64, 0x42, 0x60, 0x59, 0x50, 0x55, 0x41, 0x19, 0xbb, + 0x29, 0x8d, 0x7a, 0xb0, 0x25, 0x65, 0x10, 0xb5, 0x11, 0x14, 0x36, 0x4f, 0x49, 0xe2, 0x67, 0x5f, + 0x15, 0x52, 0xbd, 0x37, 0xdd, 0xb7, 0x18, 0xae, 0x0a, 0x91, 0x34, 0x59, 0x45, 0x35, 0x4f, 0x0e, + 0x69, 0xcf, 0xaa, 0x61, 0x97, 0x6e, 0xb3, 0x30, 0x55, 0x77, 0xb3, 0xbe, 0xe6, 0xdd, 0xa5, 0x44, + 0x52, 0x94, 0xde, 0x1e, 0x09, 0x97, 0x98, 0x4e, 0xbf, 0x89, 0xbe, 0xf5, 0x61, 0x12, 0xdf, 0x80, + 0x8a, 0x34, 0xb3, 0x58, 0x78, 0x63, 0xc2, 0x91, 0x2e, 0x93, 0x81, 0x49, 0xb8, 0xe0, 0x31, 0x24, + 0x30, 0xba, 0x6c, 0x99, 0x33, 0xe9, 0x74, 0x72, 0x30, 0x22, 0x9a, 0x78, 0x9d, 0x09, 0x43, 0x1f, + 0x66, 0x4d, 0xfc, 0x33, 0x66, 0x2f, 0x3b, 0xe1, 0x47, 0x44, 0x3f, 0xe8, 0xbf, 0xb6, 0x47, 0x14, + 0x52, 0xa2, 0x3d, 0x94, 0x1e, 0x2b, 0xa9, 0x1f, 0x2c, 0x54, 0x46, 0x25, 0xa2, 0xa1, 0x4f, 0x9a, + 0xa8, 0xcc, 0xb6, 0x58, 0x41, 0xa2, 0x6d, 0x8b, 0x9f, 0x2b, 0xd4, 0xce, 0xb8, 0x66, 0x17, 0x55, + 0x96, 0xed, 0x54, 0x15, 0x19, 0x54, 0x16, 0x59, 0x5b, 0xdb, 0x70, 0x13, 0x4a, 0x3b, 0x4a, 0x91, + 0xd8, 0x50, 0x44, 0xce, 0x1f, 0x6d, 0x40, 0x8d, 0x8a, 0x71, 0xbc, 0x09, 0x11, 0x66, 0xfa, 0xaf, + 0x6a, 0x7a, 0xcb, 0x5c, 0x22, 0xd9, 0x80, 0x3c, 0x73, 0xc9, 0x78, 0x19, 0x8e, 0xc7, 0x31, 0x06, + 0x9a, 0x80, 0x19, 0x0d, 0x2c, 0xda, 0xf8, 0x5b, 0xa3, 0x87, 0x36, 0x52, 0xa7, 0x7d, 0x46, 0x0c, + 0x24, 0x91, 0x78, 0xd6, 0x3e, 0xc7, 0xc4, 0xd3, 0x73, 0x92, 0x4a, 0xfe, 0x30, 0x4b, 0x30, 0xce, + 0x92, 0x1b, 0x66, 0x00, 0x0e, 0x9a, 0x23, 0xf2, 0x5f, 0x62, 0xb7, 0xac, 0xb0, 0x39, 0x24, 0xff, + 0x8d, 0x6d, 0xd7, 0x1a, 0x37, 0xaf, 0xc8, 0x7f, 0x34, 0x2d, 0x22, 0xff, 0x0d, 0x6c, 0xdb, 0x6b, + 0x80, 0xea, 0x4b, 0xea, 0x70, 0x2d, 0x8a, 0xbc, 0x25, 0xa6, 0x07, 0x04, 0x56, 0x28, 0x08, 0x6a, + 0x76, 0xdf, 0xb6, 0x09, 0xcb, 0xf6, 0x5a, 0x14, 0x4c, 0x8f, 0x3d, 0x85, 0xea, 0x2e, 0x0a, 0x1f, + 0x24, 0xa2, 0xbd, 0x84, 0xb3, 0xef, 0x10, 0xdc, 0xc4, 0xa5, 0xdf, 0x2b, 0xf1, 0xcd, 0x03, 0x8e, + 0x15, 0x16, 0xc3, 0x1e, 0xc4, 0xf0, 0x13, 0x49, 0x5b, 0x2a, 0x1c, 0x4d, 0xb2, 0xb1, 0x3e, 0xe0, + 0xd8, 0x7a, 0x09, 0x37, 0x21, 0x15, 0x86, 0x33, 0xe9, 0x4a, 0x00, 0x4f, 0x47, 0xed, 0x4a, 0xf7, + 0x92, 0x5f, 0x85, 0xc3, 0xf4, 0x56, 0x4f, 0x05, 0xa1, 0x6b, 0x04, 0x0f, 0x07, 0x10, 0x02, 0xa5, + 0x08, 0xe3, 0xf8, 0xf9, 0xa2, 0x71, 0xda, 0xee, 0x9e, 0x75, 0xcf, 0xdf, 0xf6, 0x5e, 0x9d, 0x9f, + 0x9e, 0xbf, 0x79, 0xfb, 0xfa, 0xed, 0xe9, 0x89, 0x21, 0xa2, 0x0e, 0x58, 0xa0, 0x95, 0xc1, 0xcc, + 0x64, 0x8e, 0xb4, 0xe8, 0x6b, 0x78, 0xc4, 0x32, 0x82, 0x80, 0x86, 0xb6, 0x1c, 0xd1, 0x10, 0x57, + 0x8c, 0x9f, 0x69, 0x04, 0x9a, 0x01, 0x31, 0x76, 0xc1, 0x3e, 0x0b, 0x67, 0x0b, 0xcb, 0x2a, 0x9a, + 0xfc, 0x67, 0xe7, 0x6b, 0x4b, 0xfa, 0xea, 0x7e, 0xb5, 0x1d, 0x34, 0xf6, 0x58, 0x58, 0x37, 0xbb, + 0xa9, 0x66, 0x0a, 0xcc, 0x93, 0x74, 0x1e, 0x07, 0x44, 0xe2, 0xce, 0x08, 0x74, 0xef, 0xdc, 0x61, + 0x47, 0xa3, 0x91, 0x22, 0xdb, 0x93, 0xea, 0x15, 0xe7, 0xa2, 0x31, 0xd6, 0x4b, 0xc0, 0xf8, 0x97, + 0x9a, 0x99, 0x64, 0x92, 0x21, 0x06, 0xc6, 0xc4, 0x6e, 0x8b, 0xe5, 0xda, 0x64, 0xda, 0x7d, 0xbe, + 0xc0, 0xfb, 0x1d, 0x3c, 0x4f, 0xb8, 0x33, 0xc0, 0x11, 0xf1, 0x83, 0xdc, 0x46, 0x61, 0x2e, 0x06, + 0x6c, 0xbc, 0x84, 0xcb, 0x2a, 0xbc, 0x4b, 0xa6, 0xd7, 0x18, 0xec, 0x97, 0xa6, 0xaf, 0x9a, 0x9f, + 0x2f, 0x7c, 0x49, 0xf7, 0xee, 0xb6, 0xdf, 0xbc, 0x3e, 0x6f, 0x15, 0x81, 0xfd, 0xba, 0xed, 0xd7, + 0xe7, 0x2c, 0x9f, 0x4c, 0x52, 0xfa, 0x98, 0x27, 0x04, 0x10, 0x12, 0xa5, 0x68, 0x64, 0xc7, 0x4b, + 0x6c, 0xba, 0x28, 0x86, 0x4d, 0x01, 0x79, 0x41, 0xc6, 0x81, 0x4c, 0x76, 0x74, 0xac, 0x62, 0xef, + 0xd0, 0x91, 0xf0, 0x8a, 0x54, 0x8e, 0x94, 0x66, 0xd8, 0x0e, 0xff, 0x86, 0x28, 0xb9, 0x50, 0x80, + 0x93, 0x8d, 0x0c, 0x83, 0xe3, 0x25, 0x55, 0xc8, 0xf7, 0x4d, 0x31, 0x93, 0xed, 0xaf, 0xe2, 0x40, + 0xd1, 0x14, 0x08, 0x09, 0x46, 0x7f, 0x31, 0xe3, 0xbb, 0x68, 0x56, 0xaf, 0xec, 0x7f, 0x00, 0x16, + 0xa6, 0x21, 0x54, 0x40, 0xe1, 0xb4, 0xe8, 0xd8, 0x34, 0x59, 0x7f, 0xd9, 0xde, 0xe7, 0x0b, 0x94, + 0x25, 0x05, 0x37, 0xd1, 0xa0, 0xcc, 0x50, 0x88, 0xd5, 0x4c, 0x9f, 0xcd, 0xa2, 0x33, 0xc1, 0x95, + 0x98, 0xdf, 0x45, 0x20, 0xa2, 0xaa, 0x10, 0x4e, 0x96, 0x89, 0xaf, 0x27, 0x4a, 0x91, 0x43, 0x72, + 0x0b, 0x29, 0x2b, 0x4a, 0x15, 0xb7, 0x43, 0xbb, 0x29, 0x7d, 0x3e, 0x4c, 0xb8, 0x89, 0x29, 0x89, + 0x94, 0x62, 0xd8, 0xe2, 0xf3, 0x37, 0xaf, 0x4f, 0x3b, 0xdd, 0x57, 0x27, 0x26, 0x09, 0xc7, 0x7c, + 0x91, 0xe5, 0x0d, 0x27, 0x8c, 0x6b, 0x5f, 0xaf, 0xb0, 0x96, 0x23, 0xc1, 0xca, 0x0f, 0x62, 0x31, + 0x69, 0xa3, 0xbf, 0xe0, 0xb7, 0xe9, 0xbb, 0x5a, 0x9a, 0x7c, 0x63, 0x64, 0x6a, 0xa9, 0x18, 0xf1, + 0xa6, 0x57, 0x8a, 0x87, 0x34, 0x0e, 0xa7, 0xd3, 0x90, 0x07, 0x38, 0x32, 0x84, 0xf7, 0x04, 0x7d, + 0x7e, 0x16, 0x2f, 0xd2, 0x51, 0x98, 0x7d, 0x73, 0xc1, 0x62, 0x8e, 0x0f, 0x58, 0xed, 0x70, 0x96, + 0x74, 0x1c, 0xce, 0x6b, 0x1e, 0x80, 0xe2, 0xb9, 0x75, 0xb1, 0x90, 0x39, 0xcc, 0xba, 0x68, 0xc8, + 0x32, 0x5c, 0x5d, 0x97, 0xe1, 0x7b, 0xab, 0x15, 0x4d, 0xc2, 0xbc, 0xea, 0x0e, 0xc3, 0xec, 0xfa, + 0x4e, 0x11, 0x20, 0x35, 0x24, 0xd4, 0x74, 0xc8, 0xda, 0xde, 0xd8, 0xa8, 0x2b, 0xd4, 0x7e, 0x78, + 0x7e, 0x81, 0x85, 0x5e, 0xfa, 0xd3, 0x4c, 0x82, 0xe9, 0xd5, 0x81, 0xe1, 0xc9, 0x06, 0x42, 0x78, + 0x96, 0x2b, 0xcf, 0x89, 0x8a, 0x40, 0xd5, 0x05, 0x9a, 0x2d, 0x79, 0x5e, 0x6e, 0x11, 0x7d, 0x03, + 0xd9, 0xd0, 0x23, 0x98, 0xe1, 0x16, 0x73, 0xc1, 0xd8, 0x1f, 0xac, 0xf4, 0x36, 0xec, 0xae, 0xb6, + 0xa1, 0xaa, 0x1f, 0x78, 0x27, 0xd4, 0xf7, 0x00, 0x6f, 0xbe, 0xda, 0x76, 0x9a, 0xf7, 0xee, 0xe3, + 0xef, 0x17, 0xef, 0x7e, 0xbd, 0x78, 0x77, 0x79, 0xf1, 0xf1, 0x97, 0xea, 0x27, 0x69, 0x40, 0xc9, + 0x57, 0x83, 0x6e, 0x06, 0x21, 0x7f, 0x48, 0xa1, 0xd5, 0xed, 0xbd, 0x21, 0xd9, 0x4c, 0x7b, 0xea, + 0x8b, 0x6d, 0x81, 0x80, 0x86, 0xfb, 0xa6, 0xcf, 0x24, 0x60, 0x28, 0x47, 0xd0, 0x66, 0x7c, 0x69, + 0x49, 0x0b, 0x44, 0x84, 0x6d, 0x0a, 0x04, 0xfe, 0x02, 0xbb, 0xc9, 0xbe, 0x6e, 0x9d, 0x57, 0x67, + 0x2c, 0x4a, 0x78, 0xe1, 0x13, 0x94, 0x22, 0x72, 0xb3, 0x85, 0x96, 0xbe, 0xe7, 0xa4, 0xcc, 0x7a, + 0xb1, 0xc1, 0x59, 0x40, 0x61, 0x50, 0x71, 0xb0, 0x3c, 0xc4, 0x0e, 0x1a, 0xff, 0xc1, 0xa3, 0x90, + 0xfb, 0x7c, 0xe5, 0x66, 0x39, 0xbe, 0x60, 0x1b, 0xfe, 0x03, 0x3b, 0x81, 0x19, 0xce, 0xe1, 0x64, + 0x44, 0x33, 0x8b, 0x1c, 0x36, 0xc8, 0x80, 0xcb, 0x61, 0xe3, 0xcc, 0x35, 0x64, 0x48, 0xe7, 0x58, + 0x9a, 0x16, 0xff, 0x25, 0x74, 0x6a, 0x79, 0x08, 0xd0, 0xe2, 0x15, 0x8a, 0x62, 0x7a, 0x9d, 0x2b, + 0x65, 0x45, 0xbd, 0x4e, 0x19, 0x4b, 0x0f, 0xdf, 0x7b, 0x00, 0x25, 0xab, 0x69, 0x15, 0xf4, 0x31, + 0x3d, 0x9f, 0x3e, 0x06, 0x21, 0x57, 0xa4, 0xf5, 0x19, 0x5e, 0xb0, 0xa4, 0xd5, 0x39, 0x45, 0xe0, + 0x49, 0xaa, 0x98, 0x68, 0xe2, 0x12, 0x95, 0x72, 0x69, 0x9c, 0xb5, 0xfc, 0x9c, 0x86, 0xa2, 0x26, + 0xca, 0xed, 0xb5, 0x56, 0x07, 0xed, 0x95, 0x5e, 0x40, 0xff, 0xea, 0xd5, 0x38, 0x62, 0x44, 0x88, + 0xf2, 0x06, 0x51, 0xa0, 0x5b, 0xd7, 0xee, 0x35, 0x3c, 0x8f, 0xae, 0xbd, 0x89, 0xc5, 0xf9, 0x4f, + 0xb5, 0x53, 0x81, 0x7e, 0x8f, 0x29, 0x76, 0x7c, 0xcb, 0xaf, 0xee, 0x08, 0x66, 0xf1, 0x94, 0x78, + 0x4f, 0x29, 0x86, 0xfd, 0x57, 0xaa, 0xcc, 0x18, 0xac, 0x11, 0x1f, 0xa5, 0x22, 0x5d, 0x26, 0x47, + 0xd2, 0xe4, 0x77, 0x54, 0xe9, 0x4d, 0xd3, 0xca, 0x52, 0xa6, 0x22, 0xa5, 0x4a, 0x4b, 0xd7, 0xee, + 0x9d, 0x92, 0x8e, 0x0a, 0x46, 0xb9, 0xa4, 0x42, 0x06, 0xeb, 0x09, 0xf4, 0xd6, 0x50, 0xe3, 0x73, + 0x55, 0x95, 0x7a, 0x5a, 0x28, 0x47, 0xb8, 0xc8, 0xc2, 0xca, 0xbd, 0x9e, 0x2d, 0x95, 0x62, 0x4d, + 0xfd, 0x35, 0xab, 0xca, 0x26, 0xa5, 0xf8, 0x69, 0xde, 0xab, 0xfa, 0x86, 0xde, 0x91, 0xda, 0x73, + 0x94, 0xbc, 0xc3, 0xbc, 0x4e, 0x64, 0xba, 0xe4, 0x4d, 0x99, 0xc3, 0x76, 0x38, 0xf3, 0xb4, 0x17, + 0x7e, 0x41, 0x42, 0x2f, 0xc0, 0xb7, 0x75, 0x9a, 0x55, 0x0b, 0x16, 0x14, 0x93, 0xd9, 0x48, 0xbe, + 0x1c, 0x4e, 0x6d, 0xe1, 0x29, 0xe9, 0x31, 0xa8, 0xb0, 0x65, 0x89, 0x0a, 0xf2, 0x16, 0xa2, 0xb6, + 0xdd, 0xa2, 0x4a, 0x0c, 0x4f, 0x6a, 0x7b, 0x98, 0x5e, 0x61, 0x30, 0xef, 0x21, 0x1c, 0x95, 0xb0, + 0x8c, 0x7f, 0x7b, 0xf7, 0x8f, 0xfe, 0xaf, 0x17, 0x1f, 0x3f, 0xf4, 0xdf, 0x5f, 0x5c, 0xfe, 0xfe, + 0xee, 0xe3, 0x4f, 0x1f, 0x1a, 0xa7, 0xbd, 0xd7, 0xaf, 0x5e, 0xb7, 0x3b, 0xcf, 0xc6, 0x76, 0xde, + 0xf4, 0xd1, 0xe9, 0x0a, 0x1b, 0x7b, 0xff, 0xb6, 0x33, 0x11, 0xab, 0xe3, 0x2c, 0x5e, 0x54, 0x06, + 0x07, 0x39, 0x5a, 0xa9, 0x47, 0x2b, 0xf5, 0xa5, 0x5a, 0xa9, 0x47, 0xbb, 0xf1, 0x68, 0x37, 0xbe, + 0x30, 0xbb, 0x91, 0x8b, 0xf3, 0x4d, 0x4d, 0x47, 0xaf, 0xb4, 0x84, 0x1e, 0x8d, 0xc9, 0xa3, 0x31, + 0x79, 0x34, 0x26, 0xbf, 0x29, 0x63, 0x72, 0xe3, 0xbd, 0xe5, 0x9d, 0xcd, 0xcc, 0x07, 0xea, 0x8f, + 0x2f, 0xc6, 0x54, 0x3c, 0x9a, 0x7b, 0x06, 0x73, 0xaf, 0xe2, 0xdd, 0x32, 0x76, 0x20, 0x00, 0x38, + 0x5b, 0x65, 0x95, 0xea, 0xf7, 0xcb, 0xf6, 0x63, 0x25, 0x96, 0x6d, 0x40, 0x9e, 0xa3, 0x2c, 0x7c, + 0xfd, 0xcb, 0x9f, 0xde, 0xfd, 0xfa, 0x01, 0x44, 0xfb, 0xa3, 0xdb, 0x88, 0x6b, 0x76, 0x50, 0x1f, + 0x66, 0x42, 0x3e, 0xc4, 0x46, 0x2c, 0x76, 0x4f, 0x77, 0x70, 0x32, 0x1d, 0x4d, 0xc3, 0x1d, 0x4c, + 0xc3, 0x67, 0x60, 0x89, 0x3d, 0x3b, 0xeb, 0xf4, 0xc0, 0xa6, 0xe1, 0xf1, 0x12, 0xe8, 0x33, 0xba, + 0x04, 0xfa, 0xc2, 0x4d, 0xf0, 0xa7, 0x35, 0x79, 0x9f, 0x9b, 0x03, 0xe0, 0x50, 0x26, 0xf8, 0x7f, + 0xc2, 0xb5, 0xdc, 0x27, 0x72, 0x33, 0x70, 0xb8, 0xed, 0x36, 0xa9, 0x0d, 0x8a, 0xd6, 0xd1, 0xcf, + 0x70, 0xf4, 0x33, 0x1c, 0xfd, 0x0c, 0x87, 0xf2, 0x33, 0x14, 0xd3, 0x35, 0x94, 0x95, 0xfe, 0xc7, + 0xf5, 0x3f, 0x6c, 0x73, 0x05, 0x55, 0x91, 0x75, 0x7a, 0x6c, 0x97, 0xb5, 0x8e, 0x8c, 0xc3, 0x19, + 0x39, 0x2f, 0xe5, 0x06, 0xe8, 0x7f, 0x82, 0x77, 0xe6, 0x19, 0x5d, 0x25, 0x7d, 0x42, 0xef, 0xd1, + 0x31, 0x56, 0xf2, 0xcb, 0x7a, 0x41, 0x45, 0xee, 0x6a, 0xb9, 0x7d, 0x6a, 0x9b, 0xdb, 0x4b, 0x47, + 0xf4, 0x9a, 0xa7, 0x46, 0x1d, 0xd6, 0x00, 0x57, 0x26, 0x9c, 0x91, 0x01, 0x27, 0xa1, 0xda, 0x61, + 0xfd, 0x5d, 0x87, 0x11, 0x28, 0xf6, 0xbf, 0x31, 0x97, 0x25, 0xc5, 0xb6, 0x24, 0x5d, 0x49, 0xaf, + 0x34, 0x8b, 0x25, 0xc2, 0x53, 0x7b, 0xba, 0xbd, 0x54, 0xe1, 0xa3, 0x7a, 0xf8, 0x48, 0x85, 0x5f, + 0xf5, 0xf1, 0xf5, 0xe5, 0xa6, 0xe8, 0x0b, 0xa2, 0x07, 0xb1, 0xcb, 0x72, 0x82, 0x3e, 0xa4, 0xc9, + 0xd2, 0x6a, 0x5d, 0x35, 0x7b, 0xec, 0x05, 0x19, 0x5b, 0x27, 0x68, 0x55, 0x20, 0x8f, 0x76, 0x41, + 0x1e, 0x55, 0x23, 0x8f, 0x0a, 0xd6, 0xc0, 0x98, 0x27, 0xdb, 0x5f, 0x30, 0x47, 0x1e, 0x22, 0xbd, + 0xea, 0x92, 0x96, 0xdb, 0x12, 0xae, 0x68, 0x87, 0xeb, 0xe1, 0x0c, 0x57, 0x44, 0x70, 0x45, 0xb6, + 0xe2, 0x64, 0x06, 0x5c, 0xc6, 0x2b, 0xe2, 0xa4, 0x52, 0xd7, 0x9c, 0x11, 0xd9, 0xe6, 0xab, 0xe1, + 0xd4, 0xed, 0xfc, 0x88, 0x4f, 0x59, 0x3c, 0x23, 0xa7, 0xf3, 0xa3, 0x1e, 0x4c, 0x62, 0x83, 0x44, + 0x9f, 0xbe, 0x0e, 0x4b, 0xaa, 0x1d, 0xe9, 0xf5, 0xfe, 0x4a, 0x4a, 0x37, 0x95, 0x8a, 0x2a, 0x4a, + 0x45, 0xfb, 0x38, 0x04, 0xc5, 0x52, 0xa1, 0x86, 0xd0, 0x94, 0x18, 0xed, 0x7e, 0xaa, 0xf2, 0x78, + 0x95, 0xe8, 0x78, 0x48, 0xeb, 0x78, 0x48, 0xab, 0xca, 0x13, 0xcf, 0x87, 0xcc, 0xe0, 0xa6, 0x7b, + 0x0c, 0x2f, 0x3d, 0xfa, 0x8a, 0x6a, 0xa8, 0x2c, 0xf2, 0x2b, 0xfb, 0xaa, 0x00, 0x31, 0xf1, 0x97, + 0x94, 0x5b, 0xd7, 0x9b, 0x2a, 0xd8, 0xf1, 0x5e, 0xd4, 0xf1, 0x7c, 0xdb, 0x33, 0x39, 0xdf, 0x76, + 0x38, 0x77, 0xba, 0x34, 0x15, 0x8b, 0x9f, 0x86, 0x9a, 0x8b, 0x4c, 0x57, 0x9d, 0x9f, 0xa6, 0x26, + 0xcb, 0x98, 0x4c, 0x93, 0xec, 0xe8, 0xf5, 0x3e, 0x7a, 0xbd, 0x8f, 0x5e, 0xef, 0xa3, 0xd7, 0x7b, + 0x33, 0xaf, 0x37, 0xaa, 0xff, 0x01, 0x93, 0x43, 0x62, 0xee, 0x3a, 0xba, 0x39, 0xd3, 0x5e, 0x7a, + 0x92, 0x90, 0x12, 0x83, 0x57, 0x02, 0x5b, 0x35, 0x85, 0xa5, 0x63, 0x33, 0xec, 0xd1, 0x5a, 0xec, + 0xd1, 0x66, 0xd8, 0x23, 0x09, 0x3b, 0x84, 0x43, 0xdb, 0xf7, 0xc9, 0x40, 0xdd, 0x16, 0x5b, 0x0c, + 0x47, 0xd8, 0xfd, 0xe5, 0x78, 0x59, 0xc4, 0xa4, 0x7c, 0x66, 0x16, 0xd8, 0xf1, 0x5e, 0x5b, 0xbd, + 0x0e, 0x70, 0x38, 0x1d, 0x7c, 0xbf, 0x0a, 0xf4, 0xb7, 0x78, 0x55, 0xcf, 0x88, 0xa1, 0xe6, 0xdc, + 0x43, 0xb9, 0xc7, 0x6b, 0x3b, 0x7c, 0x6b, 0x55, 0xe9, 0x1b, 0x73, 0xc9, 0x12, 0x31, 0x04, 0xb9, + 0xfd, 0xd0, 0x18, 0x5b, 0x0a, 0x85, 0x89, 0xdd, 0x0e, 0x35, 0xe0, 0xa8, 0x12, 0x38, 0x2a, 0x01, + 0xa3, 0xf7, 0x50, 0xd4, 0xe2, 0x0a, 0x14, 0x2e, 0x4a, 0x3a, 0xdb, 0xa7, 0xbe, 0xc0, 0x40, 0x79, + 0x1d, 0xf7, 0xbc, 0x55, 0xc8, 0x47, 0x59, 0x96, 0xd3, 0x08, 0xc6, 0xa6, 0x1c, 0x86, 0x76, 0xff, + 0x87, 0x5c, 0x37, 0x3a, 0x77, 0x9a, 0x4f, 0xc8, 0x5a, 0x93, 0xc9, 0x4f, 0x63, 0x08, 0xa9, 0x8f, + 0x6b, 0x4f, 0x45, 0x66, 0x74, 0x3d, 0x1a, 0xc5, 0x59, 0xdd, 0xb3, 0xb9, 0x5b, 0x06, 0x55, 0xeb, + 0x18, 0xd2, 0xba, 0xbb, 0x46, 0x5a, 0xeb, 0x04, 0x96, 0x65, 0x8e, 0x44, 0xd9, 0x02, 0x3d, 0xda, + 0x53, 0xe9, 0x6f, 0xd8, 0x10, 0x33, 0x8a, 0x96, 0xec, 0x06, 0x34, 0x30, 0x1f, 0x3c, 0xcf, 0x2e, + 0x77, 0x00, 0x04, 0x13, 0x2b, 0xba, 0x4a, 0xea, 0x5c, 0x79, 0x03, 0xbb, 0x5f, 0xee, 0x27, 0xfd, + 0x69, 0x91, 0xd2, 0x62, 0xdb, 0xa9, 0xce, 0xea, 0x6e, 0xdc, 0x4d, 0xa5, 0xd1, 0xc9, 0x20, 0xa2, + 0x15, 0x51, 0x3a, 0x16, 0x10, 0x02, 0xbc, 0x2e, 0x1b, 0xc4, 0x65, 0x79, 0xe4, 0x43, 0xd2, 0x6d, + 0x18, 0xdc, 0x4f, 0x7f, 0x6d, 0xa5, 0x70, 0x69, 0xce, 0xf2, 0x2c, 0x5c, 0x98, 0x5e, 0x63, 0x81, + 0xa7, 0x51, 0x16, 0xf3, 0x64, 0xd6, 0xbf, 0xc5, 0x00, 0xbf, 0x5a, 0xb4, 0xbc, 0x42, 0x30, 0x77, + 0xca, 0x13, 0xb3, 0x43, 0x43, 0xc4, 0x75, 0xd6, 0x44, 0xa0, 0xed, 0x52, 0xb0, 0x2e, 0x0d, 0xff, + 0x4d, 0x91, 0xb5, 0x43, 0x6a, 0x21, 0x90, 0x2a, 0x58, 0x42, 0x36, 0x8e, 0x82, 0xe2, 0xa7, 0xc7, + 0xc1, 0xfc, 0x7b, 0x51, 0xa8, 0xab, 0x17, 0xea, 0x16, 0x85, 0xba, 0x45, 0xa1, 0x2e, 0x14, 0xd2, + 0xb6, 0x18, 0x28, 0x36, 0x97, 0x05, 0x98, 0xe5, 0xa3, 0xcf, 0x5e, 0x7d, 0x6a, 0x87, 0x72, 0x18, + 0x6e, 0xec, 0x12, 0x81, 0x17, 0xd0, 0xfa, 0xf0, 0x85, 0xe1, 0xbb, 0x21, 0x74, 0x3a, 0xf9, 0x70, + 0xd5, 0x1e, 0x83, 0x27, 0x05, 0x6c, 0xb7, 0x22, 0xef, 0x6e, 0xb9, 0xaa, 0xcc, 0x5b, 0xdd, 0x2d, + 0x45, 0x94, 0xbb, 0xf0, 0x26, 0x26, 0xd2, 0x21, 0x0e, 0xf8, 0x13, 0x49, 0xfc, 0xdd, 0x2b, 0xfe, + 0xe0, 0x95, 0xed, 0x9d, 0x42, 0x50, 0x52, 0x08, 0x49, 0x6e, 0x31, 0xd8, 0x16, 0xf9, 0x82, 0x60, + 0x6c, 0xe5, 0xe1, 0x07, 0x82, 0xa1, 0x42, 0x9c, 0x3d, 0x4e, 0x69, 0xf8, 0xe9, 0xf4, 0xa1, 0x43, + 0x0f, 0x0c, 0x05, 0xd6, 0x3d, 0x6d, 0xa0, 0xce, 0x8a, 0xee, 0xda, 0x04, 0x9b, 0x23, 0x22, 0xbf, + 0x2b, 0xf0, 0x40, 0x15, 0xee, 0x06, 0x29, 0x9a, 0x84, 0x45, 0x49, 0x41, 0xa3, 0xbf, 0x71, 0x22, + 0x5d, 0x51, 0x8d, 0x8b, 0x6d, 0x67, 0xc3, 0xe7, 0xf2, 0x80, 0x6d, 0x0f, 0x93, 0xbf, 0xa4, 0x97, + 0x16, 0x39, 0x9b, 0x32, 0x9f, 0x2f, 0x82, 0x52, 0xe8, 0xc4, 0xf2, 0xce, 0x0d, 0x58, 0xf2, 0xcc, + 0xa8, 0x36, 0xef, 0xea, 0x28, 0xa9, 0xa7, 0x50, 0x42, 0x98, 0x53, 0xaa, 0xcc, 0xe5, 0x4e, 0x09, + 0x64, 0x4c, 0x5d, 0x08, 0x45, 0x69, 0x3a, 0x01, 0x21, 0xb3, 0xa0, 0x7b, 0x7b, 0x10, 0xb6, 0xb3, + 0x8f, 0xc4, 0x86, 0x92, 0xa4, 0xd7, 0x80, 0x46, 0x71, 0x88, 0xb2, 0xb4, 0x04, 0xa7, 0x3e, 0x11, + 0x88, 0xb0, 0x75, 0x99, 0x15, 0x59, 0x83, 0x70, 0x4a, 0x78, 0x10, 0x4c, 0x3e, 0x08, 0xa1, 0x47, + 0x24, 0x33, 0x7f, 0x78, 0xa1, 0x02, 0x7e, 0x9e, 0xe4, 0x83, 0x2b, 0x9d, 0xd6, 0x2c, 0xcd, 0xc3, + 0x3c, 0xee, 0x2f, 0x56, 0xd3, 0x28, 0x9d, 0x54, 0x14, 0xa4, 0x01, 0x03, 0x35, 0x13, 0x48, 0x11, + 0xe2, 0x83, 0x2b, 0x25, 0x9e, 0x66, 0xc5, 0x06, 0x1a, 0x4d, 0x9d, 0x84, 0x11, 0xd1, 0x80, 0xe6, + 0x93, 0x70, 0x16, 0x57, 0x40, 0xd0, 0x20, 0xd6, 0x5a, 0x5e, 0xd1, 0xb7, 0x20, 0xdc, 0xf4, 0x64, + 0x6c, 0x1b, 0x35, 0x59, 0xa7, 0xe1, 0xbc, 0xea, 0x04, 0x55, 0xd9, 0x6c, 0x2a, 0x19, 0x4d, 0xca, + 0xe0, 0x7f, 0x03, 0x7b, 0x31, 0xcf, 0xe4, 0xd1, 0xf4, 0x42, 0x89, 0x09, 0xe4, 0x29, 0x29, 0xce, + 0xb6, 0x70, 0x0f, 0xad, 0x9a, 0xcb, 0x4f, 0xc6, 0xa0, 0xda, 0x51, 0x38, 0x13, 0x79, 0x22, 0x8c, + 0x19, 0x4f, 0x25, 0xa0, 0x32, 0x53, 0x2e, 0xe2, 0xf1, 0x14, 0xe2, 0x46, 0x12, 0xb6, 0x9b, 0xc4, + 0x41, 0x4b, 0x9b, 0xd4, 0x7f, 0xf6, 0xbe, 0x72, 0x2d, 0x15, 0x86, 0x1d, 0x56, 0xaf, 0xef, 0x2a, + 0xe6, 0x2e, 0xbc, 0x6a, 0xf2, 0x5d, 0xf5, 0x94, 0x25, 0x9d, 0x8a, 0x54, 0x80, 0x0c, 0xa4, 0x04, + 0xfd, 0xd9, 0xf9, 0xea, 0xb2, 0x5f, 0xdd, 0xaf, 0x2e, 0x9f, 0xbd, 0xb6, 0x87, 0x21, 0xa8, 0xfd, + 0xfb, 0x06, 0xf4, 0x59, 0x03, 0x6a, 0x7c, 0x58, 0x85, 0xa2, 0xb2, 0x32, 0xe2, 0xba, 0xa6, 0xac, + 0x47, 0xcc, 0x44, 0x0a, 0xc3, 0xa7, 0xa6, 0xa9, 0xfe, 0xb4, 0xcf, 0x69, 0x32, 0xcb, 0xd7, 0x45, + 0x43, 0x67, 0x41, 0xad, 0x85, 0x28, 0x22, 0xf2, 0xe7, 0x2a, 0x2d, 0x44, 0x51, 0xa0, 0x62, 0x6b, + 0xab, 0xa3, 0xc8, 0xa1, 0xa8, 0x68, 0x09, 0xf4, 0x69, 0xdc, 0xf8, 0xf1, 0xa4, 0x12, 0xb1, 0x57, + 0x23, 0xff, 0x1a, 0x3f, 0x9c, 0xd4, 0xe4, 0x7a, 0x95, 0x38, 0x15, 0xda, 0x24, 0xcf, 0x17, 0x23, + 0x8f, 0xda, 0x64, 0x60, 0xa4, 0x80, 0x9b, 0x53, 0xa5, 0x1d, 0xed, 0x2e, 0x70, 0x52, 0xfb, 0xd0, + 0x93, 0x4e, 0x50, 0x2a, 0xcd, 0x4f, 0x62, 0x11, 0x2d, 0x80, 0x9f, 0xb8, 0x62, 0xa2, 0xac, 0xf1, + 0x23, 0x72, 0xa9, 0xd7, 0x3b, 0x43, 0x4f, 0x2c, 0x8e, 0x84, 0xc2, 0xea, 0x28, 0x9a, 0xa9, 0xa0, + 0x06, 0x35, 0x9e, 0xd4, 0xe4, 0x53, 0xfe, 0x52, 0x64, 0x37, 0x57, 0x14, 0xe9, 0xd4, 0xfa, 0xbc, + 0x76, 0x10, 0x69, 0x18, 0xed, 0x2e, 0x46, 0xf7, 0x16, 0xaf, 0x00, 0x85, 0xfa, 0x78, 0x2d, 0x57, + 0x5e, 0x69, 0x04, 0x11, 0x32, 0x0a, 0x4c, 0x15, 0x01, 0xbc, 0x31, 0xfd, 0xd6, 0xd7, 0x9b, 0x81, + 0xa1, 0x80, 0x2d, 0x38, 0xad, 0x85, 0x47, 0xc2, 0xd4, 0x55, 0xc6, 0x85, 0x03, 0x5f, 0x70, 0xaa, + 0xcc, 0xbf, 0x97, 0xbb, 0x02, 0x67, 0x3b, 0xe1, 0xd5, 0x59, 0x80, 0x11, 0x67, 0x65, 0x19, 0xd0, + 0xd4, 0xf0, 0xab, 0xfc, 0x49, 0x0b, 0x0e, 0x88, 0x74, 0xc2, 0x38, 0xbb, 0xf5, 0x05, 0xc1, 0xc9, + 0xdc, 0xe0, 0x9f, 0xac, 0xe3, 0x02, 0xf4, 0x3c, 0x0b, 0x34, 0x2e, 0xfa, 0xf2, 0x05, 0x39, 0xae, + 0xfe, 0x6b, 0xc0, 0x82, 0x36, 0xcb, 0xde, 0x69, 0x90, 0x8d, 0xa6, 0xd5, 0x4f, 0x8c, 0x89, 0x0c, + 0x49, 0x3a, 0x52, 0x89, 0xff, 0x23, 0x19, 0x71, 0xf2, 0xea, 0xc8, 0x3c, 0xd6, 0x5a, 0x49, 0x4f, + 0x4d, 0xb8, 0x6d, 0x6a, 0x8d, 0x71, 0xc4, 0x86, 0x99, 0x77, 0x0a, 0xbb, 0x1f, 0x82, 0x29, 0xa5, + 0x38, 0xe2, 0x37, 0x4c, 0x24, 0x93, 0x7f, 0x3d, 0x69, 0x01, 0x85, 0xa1, 0x97, 0x97, 0x48, 0xbe, + 0x96, 0xb0, 0x4f, 0x4b, 0xd5, 0x9e, 0x44, 0x94, 0xf9, 0x42, 0x47, 0x08, 0xe4, 0x7c, 0x22, 0x41, + 0xd1, 0x9a, 0x80, 0x78, 0xca, 0x8a, 0x26, 0xd1, 0xf8, 0xa1, 0xa5, 0x6a, 0x16, 0xea, 0xc2, 0x2c, + 0x5e, 0xc8, 0x02, 0x07, 0x09, 0xc4, 0x40, 0x57, 0x90, 0x76, 0xbe, 0x36, 0xa5, 0xa2, 0xb6, 0x5d, + 0x15, 0x2e, 0x9c, 0x19, 0x49, 0x8f, 0xad, 0x15, 0x1c, 0xee, 0x7c, 0xee, 0x56, 0x8e, 0x34, 0x09, + 0x88, 0xba, 0x98, 0x18, 0x80, 0xa3, 0xb5, 0x4e, 0xd1, 0xd1, 0x65, 0x3b, 0x92, 0xfd, 0xa6, 0x9e, + 0x20, 0x9b, 0x1e, 0xf2, 0x3a, 0x2a, 0xfb, 0xfb, 0x53, 0xf6, 0x9f, 0x8d, 0x12, 0xbd, 0x4f, 0x2b, + 0x62, 0x5b, 0x8b, 0xa6, 0xce, 0xea, 0xa8, 0x57, 0xf6, 0x81, 0x3d, 0x14, 0x4f, 0xd0, 0x29, 0x4b, + 0xec, 0x56, 0x4d, 0xe8, 0x51, 0x32, 0x99, 0xd4, 0x9d, 0x51, 0x2b, 0xf2, 0xab, 0x0f, 0xaa, 0x15, + 0x30, 0xa6, 0xd3, 0x6a, 0x52, 0x6e, 0xdd, 0x56, 0x8b, 0x0a, 0x56, 0xf7, 0x80, 0x57, 0x38, 0x49, + 0xeb, 0x28, 0x2e, 0xf2, 0xab, 0x29, 0x2e, 0x60, 0x4c, 0x14, 0x4b, 0xb9, 0x75, 0x14, 0xab, 0x60, + 0xdf, 0xf4, 0xb1, 0x36, 0x6c, 0x4a, 0xcd, 0x09, 0xa9, 0x22, 0xbf, 0xfa, 0xc5, 0x5d, 0x01, 0x62, + 0x7c, 0x75, 0xb7, 0xc8, 0xad, 0x7d, 0x5f, 0x4d, 0x01, 0x5b, 0x47, 0x70, 0xf5, 0x09, 0x46, 0x91, + 0x5d, 0x4f, 0x6e, 0xd5, 0x59, 0xc6, 0x22, 0x73, 0x2d, 0xb1, 0xca, 0x4e, 0xd0, 0x26, 0x76, 0xaa, + 0x34, 0xe1, 0x8a, 0x9f, 0xa6, 0x73, 0x5d, 0x45, 0xae, 0xab, 0x4e, 0x43, 0xd3, 0x09, 0x2f, 0x19, + 0xd5, 0x4e, 0x53, 0xa9, 0xf8, 0x69, 0xa2, 0xa5, 0xc8, 0x75, 0xd5, 0x09, 0x66, 0xa2, 0x45, 0x46, + 0xb5, 0xfd, 0x24, 0x39, 0xf8, 0x81, 0x30, 0x89, 0xf7, 0x8b, 0x9f, 0xa6, 0x37, 0x7f, 0x45, 0xa6, + 0xab, 0x4e, 0x08, 0xe3, 0xdb, 0xbf, 0x12, 0xa6, 0x5d, 0xb8, 0x5a, 0xfc, 0xaa, 0x22, 0x84, 0x1d, + 0xc5, 0x93, 0x18, 0xbd, 0x92, 0x0c, 0xb6, 0x67, 0x69, 0x60, 0xd7, 0xa3, 0x3f, 0xe3, 0xe8, 0xcf, + 0x38, 0xfa, 0x33, 0x8e, 0xfe, 0x8c, 0xa3, 0x3f, 0xe3, 0x65, 0xf8, 0x33, 0xf8, 0x19, 0xe4, 0xe2, + 0x44, 0x9c, 0x72, 0x80, 0x8e, 0x32, 0xc1, 0xb3, 0x72, 0x79, 0x14, 0xef, 0x5d, 0x65, 0xf3, 0x74, + 0x12, 0x42, 0xeb, 0x1f, 0xe0, 0x03, 0x61, 0x06, 0x10, 0x3d, 0xff, 0x46, 0xda, 0xd6, 0x5e, 0xc2, + 0xd5, 0x2e, 0xbc, 0xa1, 0x46, 0xad, 0x20, 0xba, 0x69, 0x28, 0x75, 0x90, 0x4b, 0x5f, 0x15, 0xad, + 0xaa, 0x1f, 0xdd, 0x2a, 0xfc, 0x0e, 0xd6, 0xe5, 0xfb, 0x9f, 0xfb, 0x9f, 0xff, 0xd1, 0x78, 0xd3, + 0xee, 0x9c, 0x94, 0x4d, 0x4d, 0x58, 0x5d, 0xfd, 0x3a, 0x07, 0x8c, 0xd9, 0x18, 0x94, 0x8f, 0xc6, + 0x6c, 0x7b, 0x3e, 0x4f, 0xb3, 0x73, 0x1f, 0xd3, 0x14, 0x3c, 0xac, 0x19, 0x77, 0x40, 0x13, 0xec, + 0x50, 0x56, 0xd4, 0x41, 0x4d, 0xa0, 0x7d, 0x5a, 0x30, 0xb5, 0x6c, 0xb2, 0x9d, 0x01, 0x52, 0x6f, + 0x7f, 0x6c, 0x65, 0x3f, 0xec, 0xe3, 0xbc, 0x9d, 0x34, 0x7a, 0xdb, 0x29, 0xf2, 0x75, 0x43, 0xb3, + 0xb1, 0x2e, 0x4e, 0x61, 0x3e, 0xbc, 0xff, 0xe5, 0x43, 0xff, 0x97, 0x77, 0xbf, 0xfd, 0xf6, 0x8e, + 0x68, 0x0c, 0xdd, 0xce, 0xb9, 0x67, 0x0e, 0xde, 0xc7, 0xc5, 0x38, 0x9b, 0xe5, 0xa0, 0x7d, 0x97, + 0x45, 0x3f, 0x9b, 0xed, 0xe2, 0xf6, 0x3c, 0x2a, 0x8d, 0x3c, 0x71, 0x25, 0x4b, 0x70, 0xde, 0x51, + 0x2c, 0xb3, 0x50, 0xc4, 0x37, 0x54, 0x7c, 0x8a, 0x28, 0x12, 0x74, 0xd4, 0xa4, 0xe1, 0x97, 0xa5, + 0x1d, 0x12, 0x17, 0x14, 0x4d, 0xf4, 0x2c, 0x81, 0xdf, 0x51, 0x24, 0xa1, 0xed, 0xcb, 0x27, 0x2e, + 0xaf, 0x47, 0xa3, 0xc0, 0x42, 0x7d, 0xba, 0x85, 0x37, 0x24, 0x98, 0x6e, 0x2d, 0xb4, 0x75, 0xe8, + 0x4b, 0x7e, 0x50, 0x27, 0x90, 0xd8, 0x85, 0x56, 0x67, 0x89, 0xae, 0x76, 0xba, 0xed, 0xee, 0x5b, + 0x8f, 0x0a, 0xf1, 0x66, 0x41, 0x85, 0x5d, 0x43, 0x06, 0xad, 0x1b, 0x6a, 0x2e, 0x46, 0xde, 0x2b, + 0x16, 0x5e, 0x86, 0xcc, 0xbf, 0x97, 0xc8, 0xc5, 0xe3, 0x82, 0x26, 0x8f, 0x32, 0xf8, 0x93, 0xdb, + 0x61, 0xb9, 0x43, 0x68, 0x5d, 0xc3, 0x00, 0x3f, 0x1c, 0x79, 0x3d, 0x50, 0x74, 0x21, 0xf4, 0x66, + 0x4b, 0x07, 0x0c, 0x81, 0xb4, 0x96, 0x8c, 0xc0, 0x85, 0x94, 0xa6, 0x92, 0xb2, 0xe1, 0x69, 0x42, + 0x47, 0x5d, 0xf1, 0x1e, 0xe4, 0xed, 0xfe, 0x7f, 0xa7, 0x8d, 0x81, 0x68 +}; + +const char* shaderSource() { + static std::string decompressed = util::decompress(std::string(reinterpret_cast<const char*>(compressedShaderSource), sizeof(compressedShaderSource))); + return decompressed.c_str(); +}; + +} // namespace gl +} // namespace programs +} // namespace mbgl diff --git a/platform/gfx/gl/src/mbgl/programs/gl/shader_source.hpp b/platform/gfx/gl/src/mbgl/programs/gl/shader_source.hpp new file mode 100644 index 0000000000..1a5fbddae3 --- /dev/null +++ b/platform/gfx/gl/src/mbgl/programs/gl/shader_source.hpp @@ -0,0 +1,16 @@ +// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. + +#pragma once + +namespace mbgl { +namespace programs { +namespace gl { + +const char* shaderSource(); + +template <typename> +struct ShaderSource; + +} // namespace gl +} // namespace programs +} // namespace mbgl diff --git a/platform/gfx/gl/src/mbgl/programs/gl/shaders.cpp b/platform/gfx/gl/src/mbgl/programs/gl/shaders.cpp new file mode 100644 index 0000000000..e8c9bdfc3c --- /dev/null +++ b/platform/gfx/gl/src/mbgl/programs/gl/shaders.cpp @@ -0,0 +1,29 @@ +#include <mbgl/programs/gl/shaders.hpp> +#include <mbgl/programs/gl/shader_source.hpp> +#include <mbgl/programs/gl/preludes.hpp> +#include <mbgl/programs/program_parameters.hpp> +#include <mbgl/util/string.hpp> + +#include <cassert> + +namespace mbgl { +namespace programs { +namespace gl { + +std::string programIdentifier(const std::string& defines1, + const std::string& defines2, + const uint8_t hash1[8], + const uint8_t hash2[8]) { + std::string result; + result.reserve(8 + 8 + (sizeof(size_t) * 2) * 2 + 2); + result.append(util::toHex(static_cast<uint64_t>(std::hash<std::string>()(defines1)))); + result.append(util::toHex(static_cast<uint64_t>(std::hash<std::string>()(defines2)))); + result.append(hash1, hash2 + 8); + result.append(hash2, hash2 + 8); + result.append("v3"); + return result; +} + +} // namespace gl +} // namespace programs +} // namespace mbgl diff --git a/platform/gfx/gl/src/mbgl/programs/gl/shaders.hpp b/platform/gfx/gl/src/mbgl/programs/gl/shaders.hpp new file mode 100644 index 0000000000..46a87f4af8 --- /dev/null +++ b/platform/gfx/gl/src/mbgl/programs/gl/shaders.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include <string> + +namespace mbgl { + +class ProgramParameters; + +namespace programs { +namespace gl { + +std::string programIdentifier(const std::string& defines1, + const std::string& defines2, + const uint8_t hash1[8], + const uint8_t hash2[8]); + +} // namespace gl +} // namespace programs +} // namespace mbgl diff --git a/platform/gfx/gl/src/mbgl/programs/gl/symbol_icon.cpp b/platform/gfx/gl/src/mbgl/programs/gl/symbol_icon.cpp new file mode 100644 index 0000000000..b7f54b590b --- /dev/null +++ b/platform/gfx/gl/src/mbgl/programs/gl/symbol_icon.cpp @@ -0,0 +1,181 @@ +// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. + +#include <mbgl/programs/symbol_icon_program.hpp> +#include <mbgl/programs/gl/preludes.hpp> +#include <mbgl/programs/gl/shader_source.hpp> +#include <mbgl/gl/program.hpp> + +namespace mbgl { +namespace programs { +namespace gl { + +template <typename> +struct ShaderSource; + +template <> +struct ShaderSource<SymbolIconProgram> { + static constexpr const char* name = "symbol_icon"; + static constexpr const uint8_t hash[8] = { 0xf3, 0x81, 0x62, 0xe8, 0x24, 0x49, 0xc6, 0x8f }; + static constexpr const auto vertexOffset = 50235; + static constexpr const auto fragmentOffset = 52883; +}; + +constexpr const char* ShaderSource<SymbolIconProgram>::name; +constexpr const uint8_t ShaderSource<SymbolIconProgram>::hash[8]; + +} // namespace gl +} // namespace programs + +namespace gfx { + +template <> +std::unique_ptr<gfx::Program<SymbolIconProgram>> +Backend::Create<gfx::Backend::Type::OpenGL>(const ProgramParameters& programParameters) { + return std::make_unique<gl::Program<SymbolIconProgram>>(programParameters); +} + +} // namespace gfx +} // namespace mbgl + +// Uncompressed source of symbol_icon.vertex.glsl: +/* +const float PI = 3.141592653589793; + +attribute vec4 a_pos_offset; +attribute vec4 a_data; +attribute vec3 a_projected_pos; +attribute float a_fade_opacity; + +uniform bool u_is_size_zoom_constant; +uniform bool u_is_size_feature_constant; +uniform highp float u_size_t; // used to interpolate between zoom stops when size is a composite function +uniform highp float u_size; // used when size is both zoom and feature constant +uniform highp float u_camera_to_center_distance; +uniform highp float u_pitch; +uniform bool u_rotate_symbol; +uniform highp float u_aspect_ratio; +uniform float u_fade_change; + +uniform mat4 u_matrix; +uniform mat4 u_label_plane_matrix; +uniform mat4 u_coord_matrix; + +uniform bool u_is_text; +uniform bool u_pitch_with_map; + +uniform vec2 u_texsize; + +varying vec2 v_tex; +varying float v_fade_opacity; + + +#ifndef HAS_UNIFORM_u_opacity +uniform lowp float u_opacity_t; +attribute lowp vec2 a_opacity; +varying lowp float opacity; +#else +uniform lowp float u_opacity; +#endif + + +void main() { + +#ifndef HAS_UNIFORM_u_opacity + opacity = unpack_mix_vec2(a_opacity, u_opacity_t); +#else + lowp float opacity = u_opacity; +#endif + + + vec2 a_pos = a_pos_offset.xy; + vec2 a_offset = a_pos_offset.zw; + + vec2 a_tex = a_data.xy; + vec2 a_size = a_data.zw; + + highp float segment_angle = -a_projected_pos[2]; + + float size; + if (!u_is_size_zoom_constant && !u_is_size_feature_constant) { + size = mix(a_size[0], a_size[1], u_size_t) / 256.0; + } else if (u_is_size_zoom_constant && !u_is_size_feature_constant) { + size = a_size[0] / 256.0; + } else if (!u_is_size_zoom_constant && u_is_size_feature_constant) { + size = u_size; + } else { + size = u_size; + } + + vec4 projectedPoint = u_matrix * vec4(a_pos, 0, 1); + highp float camera_to_anchor_distance = projectedPoint.w; + // See comments in symbol_sdf.vertex + highp float distance_ratio = u_pitch_with_map ? + camera_to_anchor_distance / u_camera_to_center_distance : + u_camera_to_center_distance / camera_to_anchor_distance; + highp float perspective_ratio = clamp( + 0.5 + 0.5 * distance_ratio, + 0.0, // Prevents oversized near-field symbols in pitched/overzoomed tiles + 4.0); + + size *= perspective_ratio; + + float fontScale = u_is_text ? size / 24.0 : size; + + highp float symbol_rotation = 0.0; + if (u_rotate_symbol) { + // See comments in symbol_sdf.vertex + vec4 offsetProjectedPoint = u_matrix * vec4(a_pos + vec2(1, 0), 0, 1); + + vec2 a = projectedPoint.xy / projectedPoint.w; + vec2 b = offsetProjectedPoint.xy / offsetProjectedPoint.w; + + symbol_rotation = atan((b.y - a.y) / u_aspect_ratio, b.x - a.x); + } + + highp float angle_sin = sin(segment_angle + symbol_rotation); + highp float angle_cos = cos(segment_angle + symbol_rotation); + mat2 rotation_matrix = mat2(angle_cos, -1.0 * angle_sin, angle_sin, angle_cos); + + vec4 projected_pos = u_label_plane_matrix * vec4(a_projected_pos.xy, 0.0, 1.0); + gl_Position = u_coord_matrix * vec4(projected_pos.xy / projected_pos.w + rotation_matrix * (a_offset / 32.0 * fontScale), 0.0, 1.0); + + v_tex = a_tex / u_texsize; + vec2 fade_opacity = unpack_opacity(a_fade_opacity); + float fade_change = fade_opacity[1] > 0.5 ? u_fade_change : -u_fade_change; + v_fade_opacity = max(0.0, min(1.0, fade_opacity[0] + fade_change)); +} + +*/ + +// Uncompressed source of symbol_icon.fragment.glsl: +/* +uniform sampler2D u_texture; + +varying vec2 v_tex; +varying float v_fade_opacity; + + +#ifndef HAS_UNIFORM_u_opacity +varying lowp float opacity; +#else +uniform lowp float u_opacity; +#endif + + +void main() { + +#ifdef HAS_UNIFORM_u_opacity + lowp float opacity = u_opacity; +#endif + + + lowp float alpha = opacity * v_fade_opacity; + gl_FragColor = texture2D(u_texture, v_tex) * alpha; + +#ifdef OVERDRAW_INSPECTOR + gl_FragColor = vec4(1.0); +#endif +} + +*/ + diff --git a/platform/gfx/gl/src/mbgl/programs/gl/symbol_sdf_icon.cpp b/platform/gfx/gl/src/mbgl/programs/gl/symbol_sdf_icon.cpp new file mode 100644 index 0000000000..76228062c6 --- /dev/null +++ b/platform/gfx/gl/src/mbgl/programs/gl/symbol_sdf_icon.cpp @@ -0,0 +1,335 @@ +// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. + +#include <mbgl/programs/symbol_sdf_icon_program.hpp> +#include <mbgl/programs/gl/preludes.hpp> +#include <mbgl/programs/gl/shader_source.hpp> +#include <mbgl/gl/program.hpp> + +namespace mbgl { +namespace programs { +namespace gl { + +template <typename> +struct ShaderSource; + +template <> +struct ShaderSource<SymbolSDFIconProgram> { + static constexpr const char* name = "symbol_sdf_icon"; + static constexpr const uint8_t hash[8] = { 0x4b, 0x0b, 0x5f, 0x6b, 0xa9, 0xec, 0x84, 0x19 }; + static constexpr const auto vertexOffset = 53288; + static constexpr const auto fragmentOffset = 57322; +}; + +constexpr const char* ShaderSource<SymbolSDFIconProgram>::name; +constexpr const uint8_t ShaderSource<SymbolSDFIconProgram>::hash[8]; + +} // namespace gl +} // namespace programs + +namespace gfx { + +template <> +std::unique_ptr<gfx::Program<SymbolSDFIconProgram>> +Backend::Create<gfx::Backend::Type::OpenGL>(const ProgramParameters& programParameters) { + return std::make_unique<gl::Program<SymbolSDFIconProgram>>(programParameters); +} + +} // namespace gfx +} // namespace mbgl + +// Uncompressed source of symbol_sdf_icon.vertex.glsl: +/* +const float PI = 3.141592653589793; + +attribute vec4 a_pos_offset; +attribute vec4 a_data; +attribute vec3 a_projected_pos; +attribute float a_fade_opacity; + +// contents of a_size vary based on the type of property value +// used for {text,icon}-size. +// For constants, a_size is disabled. +// For source functions, we bind only one value per vertex: the value of {text,icon}-size evaluated for the current feature. +// For composite functions: +// [ text-size(lowerZoomStop, feature), +// text-size(upperZoomStop, feature) ] +uniform bool u_is_size_zoom_constant; +uniform bool u_is_size_feature_constant; +uniform highp float u_size_t; // used to interpolate between zoom stops when size is a composite function +uniform highp float u_size; // used when size is both zoom and feature constant +uniform mat4 u_matrix; +uniform mat4 u_label_plane_matrix; +uniform mat4 u_coord_matrix; +uniform bool u_is_text; +uniform bool u_pitch_with_map; +uniform highp float u_pitch; +uniform bool u_rotate_symbol; +uniform highp float u_aspect_ratio; +uniform highp float u_camera_to_center_distance; +uniform float u_fade_change; +uniform vec2 u_texsize; + +varying vec2 v_data0; +varying vec3 v_data1; + + +#ifndef HAS_UNIFORM_u_fill_color +uniform lowp float u_fill_color_t; +attribute highp vec4 a_fill_color; +varying highp vec4 fill_color; +#else +uniform highp vec4 u_fill_color; +#endif + + +#ifndef HAS_UNIFORM_u_halo_color +uniform lowp float u_halo_color_t; +attribute highp vec4 a_halo_color; +varying highp vec4 halo_color; +#else +uniform highp vec4 u_halo_color; +#endif + + +#ifndef HAS_UNIFORM_u_opacity +uniform lowp float u_opacity_t; +attribute lowp vec2 a_opacity; +varying lowp float opacity; +#else +uniform lowp float u_opacity; +#endif + + +#ifndef HAS_UNIFORM_u_halo_width +uniform lowp float u_halo_width_t; +attribute lowp vec2 a_halo_width; +varying lowp float halo_width; +#else +uniform lowp float u_halo_width; +#endif + + +#ifndef HAS_UNIFORM_u_halo_blur +uniform lowp float u_halo_blur_t; +attribute lowp vec2 a_halo_blur; +varying lowp float halo_blur; +#else +uniform lowp float u_halo_blur; +#endif + + +void main() { + +#ifndef HAS_UNIFORM_u_fill_color + fill_color = unpack_mix_color(a_fill_color, u_fill_color_t); +#else + highp vec4 fill_color = u_fill_color; +#endif + + +#ifndef HAS_UNIFORM_u_halo_color + halo_color = unpack_mix_color(a_halo_color, u_halo_color_t); +#else + highp vec4 halo_color = u_halo_color; +#endif + + +#ifndef HAS_UNIFORM_u_opacity + opacity = unpack_mix_vec2(a_opacity, u_opacity_t); +#else + lowp float opacity = u_opacity; +#endif + + +#ifndef HAS_UNIFORM_u_halo_width + halo_width = unpack_mix_vec2(a_halo_width, u_halo_width_t); +#else + lowp float halo_width = u_halo_width; +#endif + + +#ifndef HAS_UNIFORM_u_halo_blur + halo_blur = unpack_mix_vec2(a_halo_blur, u_halo_blur_t); +#else + lowp float halo_blur = u_halo_blur; +#endif + + + vec2 a_pos = a_pos_offset.xy; + vec2 a_offset = a_pos_offset.zw; + + vec2 a_tex = a_data.xy; + vec2 a_size = a_data.zw; + + highp float segment_angle = -a_projected_pos[2]; + float size; + + if (!u_is_size_zoom_constant && !u_is_size_feature_constant) { + size = mix(a_size[0], a_size[1], u_size_t) / 256.0; + } else if (u_is_size_zoom_constant && !u_is_size_feature_constant) { + size = a_size[0] / 256.0; + } else if (!u_is_size_zoom_constant && u_is_size_feature_constant) { + size = u_size; + } else { + size = u_size; + } + + vec4 projectedPoint = u_matrix * vec4(a_pos, 0, 1); + highp float camera_to_anchor_distance = projectedPoint.w; + // If the label is pitched with the map, layout is done in pitched space, + // which makes labels in the distance smaller relative to viewport space. + // We counteract part of that effect by multiplying by the perspective ratio. + // If the label isn't pitched with the map, we do layout in viewport space, + // which makes labels in the distance larger relative to the features around + // them. We counteract part of that effect by dividing by the perspective ratio. + highp float distance_ratio = u_pitch_with_map ? + camera_to_anchor_distance / u_camera_to_center_distance : + u_camera_to_center_distance / camera_to_anchor_distance; + highp float perspective_ratio = clamp( + 0.5 + 0.5 * distance_ratio, + 0.0, // Prevents oversized near-field symbols in pitched/overzoomed tiles + 4.0); + + size *= perspective_ratio; + + float fontScale = u_is_text ? size / 24.0 : size; + + highp float symbol_rotation = 0.0; + if (u_rotate_symbol) { + // Point labels with 'rotation-alignment: map' are horizontal with respect to tile units + // To figure out that angle in projected space, we draw a short horizontal line in tile + // space, project it, and measure its angle in projected space. + vec4 offsetProjectedPoint = u_matrix * vec4(a_pos + vec2(1, 0), 0, 1); + + vec2 a = projectedPoint.xy / projectedPoint.w; + vec2 b = offsetProjectedPoint.xy / offsetProjectedPoint.w; + + symbol_rotation = atan((b.y - a.y) / u_aspect_ratio, b.x - a.x); + } + + highp float angle_sin = sin(segment_angle + symbol_rotation); + highp float angle_cos = cos(segment_angle + symbol_rotation); + mat2 rotation_matrix = mat2(angle_cos, -1.0 * angle_sin, angle_sin, angle_cos); + + vec4 projected_pos = u_label_plane_matrix * vec4(a_projected_pos.xy, 0.0, 1.0); + gl_Position = u_coord_matrix * vec4(projected_pos.xy / projected_pos.w + rotation_matrix * (a_offset / 32.0 * fontScale), 0.0, 1.0); + float gamma_scale = gl_Position.w; + + vec2 tex = a_tex / u_texsize; + vec2 fade_opacity = unpack_opacity(a_fade_opacity); + float fade_change = fade_opacity[1] > 0.5 ? u_fade_change : -u_fade_change; + float interpolated_fade_opacity = max(0.0, min(1.0, fade_opacity[0] + fade_change)); + + v_data0 = vec2(tex.x, tex.y); + v_data1 = vec3(gamma_scale, size, interpolated_fade_opacity); +} + +*/ + +// Uncompressed source of symbol_sdf_icon.fragment.glsl: +/* +#define SDF_PX 8.0 + +uniform bool u_is_halo; +uniform sampler2D u_texture; +uniform highp float u_gamma_scale; +uniform lowp float u_device_pixel_ratio; +uniform bool u_is_text; + +varying vec2 v_data0; +varying vec3 v_data1; + + +#ifndef HAS_UNIFORM_u_fill_color +varying highp vec4 fill_color; +#else +uniform highp vec4 u_fill_color; +#endif + + +#ifndef HAS_UNIFORM_u_halo_color +varying highp vec4 halo_color; +#else +uniform highp vec4 u_halo_color; +#endif + + +#ifndef HAS_UNIFORM_u_opacity +varying lowp float opacity; +#else +uniform lowp float u_opacity; +#endif + + +#ifndef HAS_UNIFORM_u_halo_width +varying lowp float halo_width; +#else +uniform lowp float u_halo_width; +#endif + + +#ifndef HAS_UNIFORM_u_halo_blur +varying lowp float halo_blur; +#else +uniform lowp float u_halo_blur; +#endif + + +void main() { + +#ifdef HAS_UNIFORM_u_fill_color + highp vec4 fill_color = u_fill_color; +#endif + + +#ifdef HAS_UNIFORM_u_halo_color + highp vec4 halo_color = u_halo_color; +#endif + + +#ifdef HAS_UNIFORM_u_opacity + lowp float opacity = u_opacity; +#endif + + +#ifdef HAS_UNIFORM_u_halo_width + lowp float halo_width = u_halo_width; +#endif + + +#ifdef HAS_UNIFORM_u_halo_blur + lowp float halo_blur = u_halo_blur; +#endif + + + float EDGE_GAMMA = 0.105 / u_device_pixel_ratio; + + vec2 tex = v_data0.xy; + float gamma_scale = v_data1.x; + float size = v_data1.y; + float fade_opacity = v_data1[2]; + + float fontScale = u_is_text ? size / 24.0 : size; + + lowp vec4 color = fill_color; + highp float gamma = EDGE_GAMMA / (fontScale * u_gamma_scale); + lowp float buff = (256.0 - 64.0) / 256.0; + if (u_is_halo) { + color = halo_color; + gamma = (halo_blur * 1.19 / SDF_PX + EDGE_GAMMA) / (fontScale * u_gamma_scale); + buff = (6.0 - halo_width / fontScale) / SDF_PX; + } + + lowp float dist = texture2D(u_texture, tex).a; + highp float gamma_scaled = gamma * gamma_scale; + highp float alpha = smoothstep(buff - gamma_scaled, buff + gamma_scaled, dist); + + gl_FragColor = color * (alpha * opacity * fade_opacity); + +#ifdef OVERDRAW_INSPECTOR + gl_FragColor = vec4(1.0); +#endif +} + +*/ + diff --git a/platform/gfx/gl/src/mbgl/programs/gl/symbol_sdf_text.cpp b/platform/gfx/gl/src/mbgl/programs/gl/symbol_sdf_text.cpp new file mode 100644 index 0000000000..31acda6f55 --- /dev/null +++ b/platform/gfx/gl/src/mbgl/programs/gl/symbol_sdf_text.cpp @@ -0,0 +1,335 @@ +// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED. + +#include <mbgl/programs/symbol_sdf_text_program.hpp> +#include <mbgl/programs/gl/preludes.hpp> +#include <mbgl/programs/gl/shader_source.hpp> +#include <mbgl/gl/program.hpp> + +namespace mbgl { +namespace programs { +namespace gl { + +template <typename> +struct ShaderSource; + +template <> +struct ShaderSource<SymbolSDFTextProgram> { + static constexpr const char* name = "symbol_sdf_text"; + static constexpr const uint8_t hash[8] = { 0x4b, 0x0b, 0x5f, 0x6b, 0xa9, 0xec, 0x84, 0x19 }; + static constexpr const auto vertexOffset = 53288; + static constexpr const auto fragmentOffset = 57322; +}; + +constexpr const char* ShaderSource<SymbolSDFTextProgram>::name; +constexpr const uint8_t ShaderSource<SymbolSDFTextProgram>::hash[8]; + +} // namespace gl +} // namespace programs + +namespace gfx { + +template <> +std::unique_ptr<gfx::Program<SymbolSDFTextProgram>> +Backend::Create<gfx::Backend::Type::OpenGL>(const ProgramParameters& programParameters) { + return std::make_unique<gl::Program<SymbolSDFTextProgram>>(programParameters); +} + +} // namespace gfx +} // namespace mbgl + +// Uncompressed source of symbol_sdf_text.vertex.glsl: +/* +const float PI = 3.141592653589793; + +attribute vec4 a_pos_offset; +attribute vec4 a_data; +attribute vec3 a_projected_pos; +attribute float a_fade_opacity; + +// contents of a_size vary based on the type of property value +// used for {text,icon}-size. +// For constants, a_size is disabled. +// For source functions, we bind only one value per vertex: the value of {text,icon}-size evaluated for the current feature. +// For composite functions: +// [ text-size(lowerZoomStop, feature), +// text-size(upperZoomStop, feature) ] +uniform bool u_is_size_zoom_constant; +uniform bool u_is_size_feature_constant; +uniform highp float u_size_t; // used to interpolate between zoom stops when size is a composite function +uniform highp float u_size; // used when size is both zoom and feature constant +uniform mat4 u_matrix; +uniform mat4 u_label_plane_matrix; +uniform mat4 u_coord_matrix; +uniform bool u_is_text; +uniform bool u_pitch_with_map; +uniform highp float u_pitch; +uniform bool u_rotate_symbol; +uniform highp float u_aspect_ratio; +uniform highp float u_camera_to_center_distance; +uniform float u_fade_change; +uniform vec2 u_texsize; + +varying vec2 v_data0; +varying vec3 v_data1; + + +#ifndef HAS_UNIFORM_u_fill_color +uniform lowp float u_fill_color_t; +attribute highp vec4 a_fill_color; +varying highp vec4 fill_color; +#else +uniform highp vec4 u_fill_color; +#endif + + +#ifndef HAS_UNIFORM_u_halo_color +uniform lowp float u_halo_color_t; +attribute highp vec4 a_halo_color; +varying highp vec4 halo_color; +#else +uniform highp vec4 u_halo_color; +#endif + + +#ifndef HAS_UNIFORM_u_opacity +uniform lowp float u_opacity_t; +attribute lowp vec2 a_opacity; +varying lowp float opacity; +#else +uniform lowp float u_opacity; +#endif + + +#ifndef HAS_UNIFORM_u_halo_width +uniform lowp float u_halo_width_t; +attribute lowp vec2 a_halo_width; +varying lowp float halo_width; +#else +uniform lowp float u_halo_width; +#endif + + +#ifndef HAS_UNIFORM_u_halo_blur +uniform lowp float u_halo_blur_t; +attribute lowp vec2 a_halo_blur; +varying lowp float halo_blur; +#else +uniform lowp float u_halo_blur; +#endif + + +void main() { + +#ifndef HAS_UNIFORM_u_fill_color + fill_color = unpack_mix_color(a_fill_color, u_fill_color_t); +#else + highp vec4 fill_color = u_fill_color; +#endif + + +#ifndef HAS_UNIFORM_u_halo_color + halo_color = unpack_mix_color(a_halo_color, u_halo_color_t); +#else + highp vec4 halo_color = u_halo_color; +#endif + + +#ifndef HAS_UNIFORM_u_opacity + opacity = unpack_mix_vec2(a_opacity, u_opacity_t); +#else + lowp float opacity = u_opacity; +#endif + + +#ifndef HAS_UNIFORM_u_halo_width + halo_width = unpack_mix_vec2(a_halo_width, u_halo_width_t); +#else + lowp float halo_width = u_halo_width; +#endif + + +#ifndef HAS_UNIFORM_u_halo_blur + halo_blur = unpack_mix_vec2(a_halo_blur, u_halo_blur_t); +#else + lowp float halo_blur = u_halo_blur; +#endif + + + vec2 a_pos = a_pos_offset.xy; + vec2 a_offset = a_pos_offset.zw; + + vec2 a_tex = a_data.xy; + vec2 a_size = a_data.zw; + + highp float segment_angle = -a_projected_pos[2]; + float size; + + if (!u_is_size_zoom_constant && !u_is_size_feature_constant) { + size = mix(a_size[0], a_size[1], u_size_t) / 256.0; + } else if (u_is_size_zoom_constant && !u_is_size_feature_constant) { + size = a_size[0] / 256.0; + } else if (!u_is_size_zoom_constant && u_is_size_feature_constant) { + size = u_size; + } else { + size = u_size; + } + + vec4 projectedPoint = u_matrix * vec4(a_pos, 0, 1); + highp float camera_to_anchor_distance = projectedPoint.w; + // If the label is pitched with the map, layout is done in pitched space, + // which makes labels in the distance smaller relative to viewport space. + // We counteract part of that effect by multiplying by the perspective ratio. + // If the label isn't pitched with the map, we do layout in viewport space, + // which makes labels in the distance larger relative to the features around + // them. We counteract part of that effect by dividing by the perspective ratio. + highp float distance_ratio = u_pitch_with_map ? + camera_to_anchor_distance / u_camera_to_center_distance : + u_camera_to_center_distance / camera_to_anchor_distance; + highp float perspective_ratio = clamp( + 0.5 + 0.5 * distance_ratio, + 0.0, // Prevents oversized near-field symbols in pitched/overzoomed tiles + 4.0); + + size *= perspective_ratio; + + float fontScale = u_is_text ? size / 24.0 : size; + + highp float symbol_rotation = 0.0; + if (u_rotate_symbol) { + // Point labels with 'rotation-alignment: map' are horizontal with respect to tile units + // To figure out that angle in projected space, we draw a short horizontal line in tile + // space, project it, and measure its angle in projected space. + vec4 offsetProjectedPoint = u_matrix * vec4(a_pos + vec2(1, 0), 0, 1); + + vec2 a = projectedPoint.xy / projectedPoint.w; + vec2 b = offsetProjectedPoint.xy / offsetProjectedPoint.w; + + symbol_rotation = atan((b.y - a.y) / u_aspect_ratio, b.x - a.x); + } + + highp float angle_sin = sin(segment_angle + symbol_rotation); + highp float angle_cos = cos(segment_angle + symbol_rotation); + mat2 rotation_matrix = mat2(angle_cos, -1.0 * angle_sin, angle_sin, angle_cos); + + vec4 projected_pos = u_label_plane_matrix * vec4(a_projected_pos.xy, 0.0, 1.0); + gl_Position = u_coord_matrix * vec4(projected_pos.xy / projected_pos.w + rotation_matrix * (a_offset / 32.0 * fontScale), 0.0, 1.0); + float gamma_scale = gl_Position.w; + + vec2 tex = a_tex / u_texsize; + vec2 fade_opacity = unpack_opacity(a_fade_opacity); + float fade_change = fade_opacity[1] > 0.5 ? u_fade_change : -u_fade_change; + float interpolated_fade_opacity = max(0.0, min(1.0, fade_opacity[0] + fade_change)); + + v_data0 = vec2(tex.x, tex.y); + v_data1 = vec3(gamma_scale, size, interpolated_fade_opacity); +} + +*/ + +// Uncompressed source of symbol_sdf_text.fragment.glsl: +/* +#define SDF_PX 8.0 + +uniform bool u_is_halo; +uniform sampler2D u_texture; +uniform highp float u_gamma_scale; +uniform lowp float u_device_pixel_ratio; +uniform bool u_is_text; + +varying vec2 v_data0; +varying vec3 v_data1; + + +#ifndef HAS_UNIFORM_u_fill_color +varying highp vec4 fill_color; +#else +uniform highp vec4 u_fill_color; +#endif + + +#ifndef HAS_UNIFORM_u_halo_color +varying highp vec4 halo_color; +#else +uniform highp vec4 u_halo_color; +#endif + + +#ifndef HAS_UNIFORM_u_opacity +varying lowp float opacity; +#else +uniform lowp float u_opacity; +#endif + + +#ifndef HAS_UNIFORM_u_halo_width +varying lowp float halo_width; +#else +uniform lowp float u_halo_width; +#endif + + +#ifndef HAS_UNIFORM_u_halo_blur +varying lowp float halo_blur; +#else +uniform lowp float u_halo_blur; +#endif + + +void main() { + +#ifdef HAS_UNIFORM_u_fill_color + highp vec4 fill_color = u_fill_color; +#endif + + +#ifdef HAS_UNIFORM_u_halo_color + highp vec4 halo_color = u_halo_color; +#endif + + +#ifdef HAS_UNIFORM_u_opacity + lowp float opacity = u_opacity; +#endif + + +#ifdef HAS_UNIFORM_u_halo_width + lowp float halo_width = u_halo_width; +#endif + + +#ifdef HAS_UNIFORM_u_halo_blur + lowp float halo_blur = u_halo_blur; +#endif + + + float EDGE_GAMMA = 0.105 / u_device_pixel_ratio; + + vec2 tex = v_data0.xy; + float gamma_scale = v_data1.x; + float size = v_data1.y; + float fade_opacity = v_data1[2]; + + float fontScale = u_is_text ? size / 24.0 : size; + + lowp vec4 color = fill_color; + highp float gamma = EDGE_GAMMA / (fontScale * u_gamma_scale); + lowp float buff = (256.0 - 64.0) / 256.0; + if (u_is_halo) { + color = halo_color; + gamma = (halo_blur * 1.19 / SDF_PX + EDGE_GAMMA) / (fontScale * u_gamma_scale); + buff = (6.0 - halo_width / fontScale) / SDF_PX; + } + + lowp float dist = texture2D(u_texture, tex).a; + highp float gamma_scaled = gamma * gamma_scale; + highp float alpha = smoothstep(buff - gamma_scaled, buff + gamma_scaled, dist); + + gl_FragColor = color * (alpha * opacity * fade_opacity); + +#ifdef OVERDRAW_INSPECTOR + gl_FragColor = vec4(1.0); +#endif +} + +*/ + diff --git a/platform/gfx/gl/src/mbgl/renderer/layers/render_custom_layer.cpp b/platform/gfx/gl/src/mbgl/renderer/layers/render_custom_layer.cpp new file mode 100644 index 0000000000..75c21997b0 --- /dev/null +++ b/platform/gfx/gl/src/mbgl/renderer/layers/render_custom_layer.cpp @@ -0,0 +1,99 @@ +#include <mbgl/renderer/layers/render_custom_layer.hpp> +#include <mbgl/renderer/paint_parameters.hpp> +#include <mbgl/gfx/renderer_backend.hpp> +#include <mbgl/gfx/backend_scope.hpp> +#include <mbgl/renderer/bucket.hpp> +#include <mbgl/platform/gl_functions.hpp> +#include <mbgl/style/layers/custom_layer_impl.hpp> +#include <mbgl/map/transform_state.hpp> +#include <mbgl/gl/context.hpp> +#include <mbgl/gl/renderable_resource.hpp> +#include <mbgl/util/mat4.hpp> + +namespace mbgl { + +using namespace style; + +inline const CustomLayer::Impl& impl(const Immutable<style::Layer::Impl>& impl) { + return static_cast<const CustomLayer::Impl&>(*impl); +} + +RenderCustomLayer::RenderCustomLayer(Immutable<style::CustomLayer::Impl> _impl) + : RenderLayer(makeMutable<CustomLayerProperties>(std::move(_impl))), + host(impl(baseImpl).host) { + assert(gfx::BackendScope::exists()); + MBGL_CHECK_ERROR(host->initialize()); +} + +RenderCustomLayer::~RenderCustomLayer() { + assert(gfx::BackendScope::exists()); + if (contextDestroyed) { + host->contextLost(); + } else { + MBGL_CHECK_ERROR(host->deinitialize()); + } +} + +void RenderCustomLayer::evaluate(const PropertyEvaluationParameters&) { + passes = RenderPass::Translucent; + // It is fine to not update `evaluatedProperties`, as `baseImpl` should never be updated for this layer. +} + +bool RenderCustomLayer::hasTransition() const { + return false; +} +bool RenderCustomLayer::hasCrossfade() const { + return false; +} + +void RenderCustomLayer::markContextDestroyed() { + contextDestroyed = true; +} + +void RenderCustomLayer::prepare(const LayerPrepareParameters&) { +} + +void RenderCustomLayer::render(PaintParameters& paintParameters) { + if (host != impl(baseImpl).host) { + //If the context changed, deinitialize the previous one before initializing the new one. + if (host && !contextDestroyed) { + MBGL_CHECK_ERROR(host->deinitialize()); + } + host = impl(baseImpl).host; + MBGL_CHECK_ERROR(host->initialize()); + } + + // TODO: remove cast + auto& glContext = static_cast<gl::Context&>(paintParameters.context); + const TransformState& state = paintParameters.state; + + // Reset GL state to a known state so the CustomLayer always has a clean slate. + glContext.bindVertexArray = 0; + glContext.setDepthMode(paintParameters.depthModeForSublayer(0, gfx::DepthMaskType::ReadOnly)); + glContext.setStencilMode(gfx::StencilMode::disabled()); + glContext.setColorMode(paintParameters.colorModeForRenderPass()); + glContext.setCullFaceMode(gfx::CullFaceMode::disabled()); + + CustomLayerRenderParameters parameters; + + parameters.width = state.getSize().width; + parameters.height = state.getSize().height; + parameters.latitude = state.getLatLng().latitude(); + parameters.longitude = state.getLatLng().longitude(); + parameters.zoom = state.getZoom(); + parameters.bearing = -state.getBearing() * util::RAD2DEG; + parameters.pitch = state.getPitch(); + parameters.fieldOfView = state.getFieldOfView(); + mat4 projMatrix; + state.getProjMatrix(projMatrix); + parameters.projectionMatrix = projMatrix; + + MBGL_CHECK_ERROR(host->render(parameters)); + + // Reset the view back to our original one, just in case the CustomLayer changed + // the viewport or Framebuffer. + paintParameters.backend.getDefaultRenderable().getResource<gl::RenderableResource>().bind(); + glContext.setDirtyState(); +} + +} // namespace mbgl |