summaryrefslogtreecommitdiff
path: root/platform/gfx/gl
diff options
context:
space:
mode:
Diffstat (limited to 'platform/gfx/gl')
-rw-r--r--platform/gfx/gl/include/mbgl/gl/renderable_resource.hpp24
-rw-r--r--platform/gfx/gl/include/mbgl/gl/renderer_backend.hpp56
-rw-r--r--platform/gfx/gl/include/mbgl/platform/gl_functions.hpp337
-rw-r--r--platform/gfx/gl/src/mbgl/gl/attribute.cpp19
-rw-r--r--platform/gfx/gl/src/mbgl/gl/attribute.hpp115
-rw-r--r--platform/gfx/gl/src/mbgl/gl/command_encoder.cpp60
-rw-r--r--platform/gfx/gl/src/mbgl/gl/command_encoder.hpp33
-rw-r--r--platform/gfx/gl/src/mbgl/gl/context.cpp755
-rw-r--r--platform/gfx/gl/src/mbgl/gl/context.hpp235
-rw-r--r--platform/gfx/gl/src/mbgl/gl/debugging_extension.cpp55
-rw-r--r--platform/gfx/gl/src/mbgl/gl/debugging_extension.hpp122
-rw-r--r--platform/gfx/gl/src/mbgl/gl/defines.hpp179
-rw-r--r--platform/gfx/gl/src/mbgl/gl/draw_scope_resource.hpp18
-rw-r--r--platform/gfx/gl/src/mbgl/gl/enum.cpp319
-rw-r--r--platform/gfx/gl/src/mbgl/gl/enum.hpp21
-rw-r--r--platform/gfx/gl/src/mbgl/gl/extension.hpp34
-rw-r--r--platform/gfx/gl/src/mbgl/gl/framebuffer.hpp16
-rw-r--r--platform/gfx/gl/src/mbgl/gl/index_buffer_resource.hpp18
-rw-r--r--platform/gfx/gl/src/mbgl/gl/object.cpp52
-rw-r--r--platform/gfx/gl/src/mbgl/gl/object.hpp60
-rw-r--r--platform/gfx/gl/src/mbgl/gl/offscreen_texture.cpp75
-rw-r--r--platform/gfx/gl/src/mbgl/gl/offscreen_texture.hpp24
-rw-r--r--platform/gfx/gl/src/mbgl/gl/program.hpp141
-rw-r--r--platform/gfx/gl/src/mbgl/gl/render_pass.cpp28
-rw-r--r--platform/gfx/gl/src/mbgl/gl/render_pass.hpp31
-rw-r--r--platform/gfx/gl/src/mbgl/gl/renderbuffer_resource.hpp19
-rw-r--r--platform/gfx/gl/src/mbgl/gl/renderer_backend.cpp69
-rw-r--r--platform/gfx/gl/src/mbgl/gl/state.hpp70
-rw-r--r--platform/gfx/gl/src/mbgl/gl/texture.cpp54
-rw-r--r--platform/gfx/gl/src/mbgl/gl/texture.hpp49
-rw-r--r--platform/gfx/gl/src/mbgl/gl/texture_resource.hpp22
-rw-r--r--platform/gfx/gl/src/mbgl/gl/types.hpp62
-rw-r--r--platform/gfx/gl/src/mbgl/gl/uniform.cpp202
-rw-r--r--platform/gfx/gl/src/mbgl/gl/uniform.hpp95
-rw-r--r--platform/gfx/gl/src/mbgl/gl/upload_pass.cpp117
-rw-r--r--platform/gfx/gl/src/mbgl/gl/upload_pass.hpp42
-rw-r--r--platform/gfx/gl/src/mbgl/gl/value.cpp602
-rw-r--r--platform/gfx/gl/src/mbgl/gl/value.hpp357
-rw-r--r--platform/gfx/gl/src/mbgl/gl/vertex_array.cpp24
-rw-r--r--platform/gfx/gl/src/mbgl/gl/vertex_array.hpp71
-rw-r--r--platform/gfx/gl/src/mbgl/gl/vertex_array_extension.hpp38
-rw-r--r--platform/gfx/gl/src/mbgl/gl/vertex_buffer_resource.hpp18
-rw-r--r--platform/gfx/gl/src/mbgl/platform/gl_functions.cpp17
-rw-r--r--platform/gfx/gl/src/mbgl/programs/gl/background.cpp66
-rw-r--r--platform/gfx/gl/src/mbgl/programs/gl/background_pattern.cpp97
-rw-r--r--platform/gfx/gl/src/mbgl/programs/gl/circle.cpp320
-rw-r--r--platform/gfx/gl/src/mbgl/programs/gl/clipping_mask.cpp59
-rw-r--r--platform/gfx/gl/src/mbgl/programs/gl/collision_box.cpp96
-rw-r--r--platform/gfx/gl/src/mbgl/programs/gl/collision_circle.cpp119
-rw-r--r--platform/gfx/gl/src/mbgl/programs/gl/debug.cpp61
-rw-r--r--platform/gfx/gl/src/mbgl/programs/gl/fill.cpp123
-rw-r--r--platform/gfx/gl/src/mbgl/programs/gl/fill_extrusion.cpp163
-rw-r--r--platform/gfx/gl/src/mbgl/programs/gl/fill_extrusion_pattern.cpp262
-rw-r--r--platform/gfx/gl/src/mbgl/programs/gl/fill_outline.cpp131
-rw-r--r--platform/gfx/gl/src/mbgl/programs/gl/fill_outline_pattern.cpp205
-rw-r--r--platform/gfx/gl/src/mbgl/programs/gl/fill_pattern.cpp193
-rw-r--r--platform/gfx/gl/src/mbgl/programs/gl/heatmap.cpp162
-rw-r--r--platform/gfx/gl/src/mbgl/programs/gl/heatmap_texture.cpp74
-rw-r--r--platform/gfx/gl/src/mbgl/programs/gl/hillshade.cpp112
-rw-r--r--platform/gfx/gl/src/mbgl/programs/gl/hillshade_prepare.cpp136
-rw-r--r--platform/gfx/gl/src/mbgl/programs/gl/line.cpp275
-rw-r--r--platform/gfx/gl/src/mbgl/programs/gl/line_gradient.cpp257
-rw-r--r--platform/gfx/gl/src/mbgl/programs/gl/line_pattern.cpp345
-rw-r--r--platform/gfx/gl/src/mbgl/programs/gl/line_sdf.cpp338
-rw-r--r--platform/gfx/gl/src/mbgl/programs/gl/preludes.hpp17
-rw-r--r--platform/gfx/gl/src/mbgl/programs/gl/raster.cpp122
-rw-r--r--platform/gfx/gl/src/mbgl/programs/gl/shader_source.cpp471
-rw-r--r--platform/gfx/gl/src/mbgl/programs/gl/shader_source.hpp16
-rw-r--r--platform/gfx/gl/src/mbgl/programs/gl/shaders.cpp29
-rw-r--r--platform/gfx/gl/src/mbgl/programs/gl/shaders.hpp19
-rw-r--r--platform/gfx/gl/src/mbgl/programs/gl/symbol_icon.cpp181
-rw-r--r--platform/gfx/gl/src/mbgl/programs/gl/symbol_sdf_icon.cpp335
-rw-r--r--platform/gfx/gl/src/mbgl/programs/gl/symbol_sdf_text.cpp335
-rw-r--r--platform/gfx/gl/src/mbgl/renderer/layers/render_custom_layer.cpp99
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