summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMolly Lloyd <molly@mapbox.com>2017-03-01 11:28:31 -0800
committerJohn Firebaugh <john.firebaugh@gmail.com>2017-03-08 15:23:25 -0800
commit692f5e0a9f5321ee2932a976a8eb9e0a83fc3352 (patch)
treecb9ff13dc30455f1700eeb691dc155d0981c4116
parent3afae825c7b2f95e58cbcb85c59857f2253c945e (diff)
downloadqtlocation-mapboxgl-692f5e0a9f5321ee2932a976a8eb9e0a83fc3352.tar.gz
Pack min + max into one attribute :muscle:
Some devices supported by Mapbox GL provide only 8 vertex attributes; this change packs existing attributes to get us just under that limit. For properties using a composite function, pack the min and max values into a single attribute with two logical components instead of using two separate attributes and buffers. Special logic is included for color attributes, whose integer components must be packed into the available bits of floating-point attributes. (We don't have access to ivec types in GL ES 2.0.) For source functions, continue to bind just a one-component attribute even though the GLSL type is vec2 (or vec4 for colors). The type-checking done by gl::Attribute is relaxed slightly to accommodate this.
m---------mapbox-gl-js0
-rwxr-xr-xscripts/generate-shaders.js7
-rw-r--r--src/mbgl/gl/attribute.cpp2
-rw-r--r--src/mbgl/gl/attribute.hpp46
-rw-r--r--src/mbgl/programs/attributes.hpp96
-rw-r--r--src/mbgl/programs/symbol_program.hpp8
-rw-r--r--src/mbgl/shaders/circle.cpp35
-rw-r--r--src/mbgl/shaders/fill.cpp10
-rw-r--r--src/mbgl/shaders/fill_outline.cpp10
-rw-r--r--src/mbgl/shaders/fill_outline_pattern.cpp5
-rw-r--r--src/mbgl/shaders/fill_pattern.cpp5
-rw-r--r--src/mbgl/shaders/line.cpp25
-rw-r--r--src/mbgl/shaders/line_pattern.cpp20
-rw-r--r--src/mbgl/shaders/line_sdf.cpp25
-rw-r--r--src/mbgl/shaders/preludes.cpp25
-rw-r--r--src/mbgl/shaders/symbol_icon.cpp12
-rw-r--r--src/mbgl/shaders/symbol_sdf.cpp31
-rw-r--r--src/mbgl/style/paint_property_binder.hpp123
18 files changed, 238 insertions, 247 deletions
diff --git a/mapbox-gl-js b/mapbox-gl-js
-Subproject f9c5c175926278a24f1b0d958867632023773ed
+Subproject 69bb05cef27c99722f6616867032d64b5f12ee5
diff --git a/scripts/generate-shaders.js b/scripts/generate-shaders.js
index 892620cf21..cffe9d3854 100755
--- a/scripts/generate-shaders.js
+++ b/scripts/generate-shaders.js
@@ -60,9 +60,11 @@ ${fragmentPrelude}
].forEach(function (shaderName) {
function applyPragmas(source, pragmas) {
return source.replace(/#pragma mapbox: ([\w]+) ([\w]+) ([\w]+) ([\w]+)/g, (match, operation, precision, type, name) => {
+ const a_type = type === "float" ? "vec2" : "vec4";
return pragmas[operation]
.join("\n")
.replace(/\{type\}/g, type)
+ .replace(/\{a_type}/g, a_type)
.replace(/\{precision\}/g, precision)
.replace(/\{name\}/g, name);
});
@@ -73,12 +75,11 @@ ${fragmentPrelude}
return applyPragmas(source, {
define: [
"uniform lowp float a_{name}_t;",
- "attribute {precision} {type} a_{name}_min;",
- "attribute {precision} {type} a_{name}_max;",
+ "attribute {precision} {a_type} a_{name};",
"varying {precision} {type} {name};"
],
initialize: [
- "{name} = mix(a_{name}_min, a_{name}_max, a_{name}_t);"
+ "{name} = unpack_mix_{a_type}(a_{name}, a_{name}_t);"
]
});
}
diff --git a/src/mbgl/gl/attribute.cpp b/src/mbgl/gl/attribute.cpp
index 2c16dac3fc..ff313fdcd0 100644
--- a/src/mbgl/gl/attribute.cpp
+++ b/src/mbgl/gl/attribute.cpp
@@ -38,7 +38,7 @@ void VariableAttributeBinding<T, N>::bind(Context& context,
MBGL_CHECK_ERROR(glEnableVertexAttribArray(location));
MBGL_CHECK_ERROR(glVertexAttribPointer(
location,
- static_cast<GLint>(N),
+ static_cast<GLint>(attributeSize),
static_cast<GLenum>(DataTypeOf<T>),
static_cast<GLboolean>(IsNormalized<T>),
static_cast<GLsizei>(vertexSize),
diff --git a/src/mbgl/gl/attribute.hpp b/src/mbgl/gl/attribute.hpp
index 6300ebb56b..43e2c2d794 100644
--- a/src/mbgl/gl/attribute.hpp
+++ b/src/mbgl/gl/attribute.hpp
@@ -17,10 +17,12 @@ class VariableAttributeBinding {
public:
VariableAttributeBinding(BufferID vertexBuffer_,
std::size_t vertexSize_,
- std::size_t attributeOffset_)
+ std::size_t attributeOffset_,
+ std::size_t attributeSize_ = N)
: vertexBuffer(vertexBuffer_),
vertexSize(vertexSize_),
- attributeOffset(attributeOffset_)
+ attributeOffset(attributeOffset_),
+ attributeSize(attributeSize_)
{}
void bind(Context&, AttributeLocation, optional<VariableAttributeBinding<T, N>>&, std::size_t vertexOffset) const;
@@ -29,13 +31,15 @@ public:
const VariableAttributeBinding& rhs) {
return lhs.vertexBuffer == rhs.vertexBuffer
&& lhs.vertexSize == rhs.vertexSize
- && lhs.attributeOffset == rhs.attributeOffset;
+ && lhs.attributeOffset == rhs.attributeOffset
+ && lhs.attributeSize == rhs.attributeSize;
}
private:
BufferID vertexBuffer;
std::size_t vertexSize;
std::size_t attributeOffset;
+ std::size_t attributeSize;
};
template <class T, std::size_t N>
@@ -58,9 +62,16 @@ private:
std::array<T, N> value;
};
+/*
+ gl::Attribute<T,N> manages the binding of a constant value or vertex buffer to a GL program attribute.
+ - T is the underlying primitive type (exposed as Attribute<T,N>::ValueType)
+ - N is the number of components in the attribute declared in the shader (exposed as Attribute<T,N>::Dimensions)
+*/
template <class T, std::size_t N>
class Attribute {
public:
+ using ValueType = T;
+ static constexpr size_t Dimensions = N;
using Value = std::array<T, N>;
using VariableBinding = VariableAttributeBinding<T, N>;
@@ -72,6 +83,25 @@ public:
ConstantBinding,
VariableBinding>;
+ /*
+ Create a variable (i.e. data-driven) binding for this attribute. The `attributeSize`
+ parameter may be used to override the number of components available in the buffer for
+ each vertex. Thus, a buffer with only one float for each vertex can be bound to a
+ `vec2` attribute
+ */
+ template <class Vertex, class DrawMode>
+ static VariableBinding variableBinding(const VertexBuffer<Vertex, DrawMode>& buffer,
+ std::size_t attributeIndex,
+ std::size_t attributeSize = N) {
+ static_assert(std::is_standard_layout<Vertex>::value, "vertex type must use standard layout");
+ return VariableBinding {
+ buffer.buffer,
+ sizeof(Vertex),
+ Vertex::attributeOffsets[attributeIndex],
+ attributeSize
+ };
+ }
+
static void bind(Context& context,
const Location& location,
optional<VariableBinding>& oldBinding,
@@ -223,15 +253,7 @@ public:
template <class DrawMode>
static Bindings allVariableBindings(const VertexBuffer<Vertex, DrawMode>& buffer) {
- static_assert(std::is_standard_layout<Vertex>::value, "vertex type must use standard layout");
-
- return Bindings {
- typename As::VariableBinding {
- buffer.buffer,
- sizeof(Vertex),
- Vertex::attributeOffsets[Index<As>]
- }...
- };
+ return Bindings { As::variableBinding(buffer, Index<As>)... };
}
static void bind(Context& context,
diff --git a/src/mbgl/programs/attributes.hpp b/src/mbgl/programs/attributes.hpp
index bb90f2c13c..a2e0772762 100644
--- a/src/mbgl/programs/attributes.hpp
+++ b/src/mbgl/programs/attributes.hpp
@@ -13,6 +13,7 @@ namespace attributes {
MBGL_DEFINE_ATTRIBUTE(int16_t, 2, a_pos);
MBGL_DEFINE_ATTRIBUTE(int16_t, 2, a_extrude);
+MBGL_DEFINE_ATTRIBUTE(int16_t, 4, a_pos_offset);
MBGL_DEFINE_ATTRIBUTE(uint16_t, 2, a_texture_pos);
template <std::size_t N>
@@ -27,19 +28,30 @@ struct a_offset : gl::Attribute<int16_t, N> {
// Paint attributes
+/*
+ ZoomInterpolatedAttribute<Attr> is a 'compound' attribute, representing two values of the
+ the base attribute Attr. These two values are provided to the shader to allow interpolation
+ between zoom levels, without the need to repopulate vertex buffers each frame as the map is
+ being zoomed.
+*/
template <class Attr>
-struct Min : Attr {
- static auto name() {
- static const std::string name = Attr::name() + std::string("_min");
- return name.c_str();
- }
-};
+struct ZoomInterpolatedAttribute : gl::Attribute<typename Attr::ValueType, Attr::Dimensions * 2> {
+ using Value = typename gl::Attribute<typename Attr::ValueType, Attr::Dimensions * 2>::Value;
-template <class Attr>
-struct Max : Attr {
static auto name() {
- static const std::string name = Attr::name() + std::string("_max");
- return name.c_str();
+ return Attr::name();
+ }
+
+ template <class InputType>
+ static Value value(const InputType& min, const InputType& max){
+ auto minValue = Attr::value(min);
+ auto maxValue = Attr::value(max);
+ Value result = {{}};
+ for (size_t i = 0; i < Attr::Dimensions; i++) {
+ result[i] = minValue[i];
+ result[Attr::Dimensions+i] = maxValue[i];
+ }
+ return result;
}
};
@@ -51,70 +63,62 @@ struct InterpolationUniform : gl::UniformScalar<InterpolationUniform<Attr>, floa
}
};
-struct a_color : gl::Attribute<gl::Normalized<uint8_t>, 4> {
+/*
+ Encode a four-component color value into a pair of floats. Since csscolorparser
+ uses 8-bit precision for each color component, for each float we use the upper 8
+ bits for one component (e.g. (color.r * 255) * 256), and the lower 8 for another.
+
+ Also note:
+ - Colors come in as floats 0..1, so we scale by 255.
+ - Casting the scaled values to ints is important: without doing this, e.g., the
+ fractional part of the `r` component would corrupt the lower-8 bits of the encoded
+ value, which must be reserved for the `g` component.
+*/
+static std::array<float, 2> encodeColor (const Color& color) {
+ const auto v1 = static_cast<uint16_t>( static_cast<uint16_t>(color.r*255)*256 + color.g*255);
+ const auto v2 = static_cast<uint16_t>( static_cast<uint16_t>(color.b*255)*256 + color.a*255);
+ return {{ static_cast<float>(v1), static_cast<float>(v2) }};
+}
+
+struct a_color : gl::Attribute<float, 2> {
static auto name() { return "a_color"; }
static Value value(const Color& color) {
- return {{
- gl::Normalized<uint8_t>(color.r),
- gl::Normalized<uint8_t>(color.g),
- gl::Normalized<uint8_t>(color.b),
- gl::Normalized<uint8_t>(color.a)
- }};
+ return encodeColor(color);
}
};
// used in the symbol sdf shader
-struct a_fill_color : gl::Attribute<gl::Normalized<uint8_t>, 4> {
+struct a_fill_color : gl::Attribute<float, 2> {
static auto name() { return "a_fill_color"; }
static Value value(const Color& color) {
- return {{
- gl::Normalized<uint8_t>(color.r),
- gl::Normalized<uint8_t>(color.g),
- gl::Normalized<uint8_t>(color.b),
- gl::Normalized<uint8_t>(color.a)
- }};
+ return encodeColor(color);
}
};
// used in the symbol sdf shader
-struct a_halo_color : gl::Attribute<gl::Normalized<uint8_t>, 4> {
+struct a_halo_color : gl::Attribute<float, 2> {
static auto name() { return "a_halo_color"; }
- static Value value(const Color& color) {
- return {{
- gl::Normalized<uint8_t>(color.r),
- gl::Normalized<uint8_t>(color.g),
- gl::Normalized<uint8_t>(color.b),
- gl::Normalized<uint8_t>(color.a)
- }};
+ static Value value(const Color& color) {
+ return encodeColor(color);
}
};
-struct a_stroke_color : gl::Attribute<gl::Normalized<uint8_t>, 4> {
+struct a_stroke_color : gl::Attribute<float, 2> {
static auto name() { return "a_stroke_color"; }
static Value value(const Color& color) {
- return {{
- gl::Normalized<uint8_t>(color.r),
- gl::Normalized<uint8_t>(color.g),
- gl::Normalized<uint8_t>(color.b),
- gl::Normalized<uint8_t>(color.a)
- }};
+ return encodeColor(color);
}
};
-struct a_outline_color : gl::Attribute<gl::Normalized<uint8_t>, 4> {
+struct a_outline_color : gl::Attribute<float, 2> {
static auto name() { return "a_outline_color"; }
static Value value(const Color& color) {
- return {{
- gl::Normalized<uint8_t>(color.r),
- gl::Normalized<uint8_t>(color.g),
- gl::Normalized<uint8_t>(color.b),
- gl::Normalized<uint8_t>(color.a)
- }};
+ return encodeColor(color);
}
};
diff --git a/src/mbgl/programs/symbol_program.hpp b/src/mbgl/programs/symbol_program.hpp
index 0537c25a2c..fdd1aa5c3b 100644
--- a/src/mbgl/programs/symbol_program.hpp
+++ b/src/mbgl/programs/symbol_program.hpp
@@ -35,8 +35,7 @@ MBGL_DEFINE_UNIFORM_SCALAR(float, u_gamma_scale);
} // namespace uniforms
struct SymbolLayoutAttributes : gl::Attributes<
- attributes::a_pos,
- attributes::a_offset<2>,
+ attributes::a_pos_offset,
attributes::a_texture_pos,
attributes::a_data<4>>
{
@@ -49,11 +48,10 @@ struct SymbolLayoutAttributes : gl::Attributes<
float labelminzoom,
uint8_t labelangle) {
return Vertex {
+ // combining pos and offset to reduce number of vertex attributes passed to shader (8 max for some devices)
{{
static_cast<int16_t>(a.x),
- static_cast<int16_t>(a.y)
- }},
- {{
+ static_cast<int16_t>(a.y),
static_cast<int16_t>(::round(o.x * 64)), // use 1/64 pixels for placement
static_cast<int16_t>(::round(o.y * 64))
}},
diff --git a/src/mbgl/shaders/circle.cpp b/src/mbgl/shaders/circle.cpp
index 4b2bb7cecf..b479f1d40c 100644
--- a/src/mbgl/shaders/circle.cpp
+++ b/src/mbgl/shaders/circle.cpp
@@ -14,45 +14,38 @@ uniform vec2 u_extrude_scale;
attribute vec2 a_pos;
uniform lowp float a_color_t;
-attribute lowp vec4 a_color_min;
-attribute lowp vec4 a_color_max;
+attribute lowp vec4 a_color;
varying lowp vec4 color;
uniform lowp float a_radius_t;
-attribute mediump float a_radius_min;
-attribute mediump float a_radius_max;
+attribute mediump vec2 a_radius;
varying mediump float radius;
uniform lowp float a_blur_t;
-attribute lowp float a_blur_min;
-attribute lowp float a_blur_max;
+attribute lowp vec2 a_blur;
varying lowp float blur;
uniform lowp float a_opacity_t;
-attribute lowp float a_opacity_min;
-attribute lowp float a_opacity_max;
+attribute lowp vec2 a_opacity;
varying lowp float opacity;
uniform lowp float a_stroke_color_t;
-attribute lowp vec4 a_stroke_color_min;
-attribute lowp vec4 a_stroke_color_max;
+attribute lowp vec4 a_stroke_color;
varying lowp vec4 stroke_color;
uniform lowp float a_stroke_width_t;
-attribute mediump float a_stroke_width_min;
-attribute mediump float a_stroke_width_max;
+attribute mediump vec2 a_stroke_width;
varying mediump float stroke_width;
uniform lowp float a_stroke_opacity_t;
-attribute lowp float a_stroke_opacity_min;
-attribute lowp float a_stroke_opacity_max;
+attribute lowp vec2 a_stroke_opacity;
varying lowp float stroke_opacity;
varying vec2 v_extrude;
varying lowp float v_antialiasblur;
void main(void) {
- color = mix(a_color_min, a_color_max, a_color_t);
- radius = mix(a_radius_min, a_radius_max, a_radius_t);
- blur = mix(a_blur_min, a_blur_max, a_blur_t);
- opacity = mix(a_opacity_min, a_opacity_max, a_opacity_t);
- stroke_color = mix(a_stroke_color_min, a_stroke_color_max, a_stroke_color_t);
- stroke_width = mix(a_stroke_width_min, a_stroke_width_max, a_stroke_width_t);
- stroke_opacity = mix(a_stroke_opacity_min, a_stroke_opacity_max, a_stroke_opacity_t);
+ color = unpack_mix_vec4(a_color, a_color_t);
+ radius = unpack_mix_vec2(a_radius, a_radius_t);
+ blur = unpack_mix_vec2(a_blur, a_blur_t);
+ opacity = unpack_mix_vec2(a_opacity, a_opacity_t);
+ stroke_color = unpack_mix_vec4(a_stroke_color, a_stroke_color_t);
+ stroke_width = unpack_mix_vec2(a_stroke_width, a_stroke_width_t);
+ stroke_opacity = unpack_mix_vec2(a_stroke_opacity, a_stroke_opacity_t);
// unencode the extrusion vector that we snuck into the a_pos vector
v_extrude = vec2(mod(a_pos, 2.0) * 2.0 - 1.0);
diff --git a/src/mbgl/shaders/fill.cpp b/src/mbgl/shaders/fill.cpp
index d0fc3a7033..a1fba4d749 100644
--- a/src/mbgl/shaders/fill.cpp
+++ b/src/mbgl/shaders/fill.cpp
@@ -12,17 +12,15 @@ attribute vec2 a_pos;
uniform mat4 u_matrix;
uniform lowp float a_color_t;
-attribute lowp vec4 a_color_min;
-attribute lowp vec4 a_color_max;
+attribute lowp vec4 a_color;
varying lowp vec4 color;
uniform lowp float a_opacity_t;
-attribute lowp float a_opacity_min;
-attribute lowp float a_opacity_max;
+attribute lowp vec2 a_opacity;
varying lowp float opacity;
void main() {
- color = mix(a_color_min, a_color_max, a_color_t);
- opacity = mix(a_opacity_min, a_opacity_max, a_opacity_t);
+ color = unpack_mix_vec4(a_color, a_color_t);
+ opacity = unpack_mix_vec2(a_opacity, a_opacity_t);
gl_Position = u_matrix * vec4(a_pos, 0, 1);
}
diff --git a/src/mbgl/shaders/fill_outline.cpp b/src/mbgl/shaders/fill_outline.cpp
index d6f8d63715..74201b518d 100644
--- a/src/mbgl/shaders/fill_outline.cpp
+++ b/src/mbgl/shaders/fill_outline.cpp
@@ -15,17 +15,15 @@ uniform vec2 u_world;
varying vec2 v_pos;
uniform lowp float a_outline_color_t;
-attribute lowp vec4 a_outline_color_min;
-attribute lowp vec4 a_outline_color_max;
+attribute lowp vec4 a_outline_color;
varying lowp vec4 outline_color;
uniform lowp float a_opacity_t;
-attribute lowp float a_opacity_min;
-attribute lowp float a_opacity_max;
+attribute lowp vec2 a_opacity;
varying lowp float opacity;
void main() {
- outline_color = mix(a_outline_color_min, a_outline_color_max, a_outline_color_t);
- opacity = mix(a_opacity_min, a_opacity_max, a_opacity_t);
+ outline_color = unpack_mix_vec4(a_outline_color, a_outline_color_t);
+ opacity = unpack_mix_vec2(a_opacity, a_opacity_t);
gl_Position = u_matrix * vec4(a_pos, 0, 1);
v_pos = (gl_Position.xy / gl_Position.w + 1.0) / 2.0 * u_world;
diff --git a/src/mbgl/shaders/fill_outline_pattern.cpp b/src/mbgl/shaders/fill_outline_pattern.cpp
index 6e9d6ad9a1..5e38023382 100644
--- a/src/mbgl/shaders/fill_outline_pattern.cpp
+++ b/src/mbgl/shaders/fill_outline_pattern.cpp
@@ -24,12 +24,11 @@ varying vec2 v_pos_b;
varying vec2 v_pos;
uniform lowp float a_opacity_t;
-attribute lowp float a_opacity_min;
-attribute lowp float a_opacity_max;
+attribute lowp vec2 a_opacity;
varying lowp float opacity;
void main() {
- opacity = mix(a_opacity_min, a_opacity_max, a_opacity_t);
+ opacity = unpack_mix_vec2(a_opacity, a_opacity_t);
gl_Position = u_matrix * vec4(a_pos, 0, 1);
diff --git a/src/mbgl/shaders/fill_pattern.cpp b/src/mbgl/shaders/fill_pattern.cpp
index 329a292eed..0357fed40e 100644
--- a/src/mbgl/shaders/fill_pattern.cpp
+++ b/src/mbgl/shaders/fill_pattern.cpp
@@ -22,12 +22,11 @@ varying vec2 v_pos_a;
varying vec2 v_pos_b;
uniform lowp float a_opacity_t;
-attribute lowp float a_opacity_min;
-attribute lowp float a_opacity_max;
+attribute lowp vec2 a_opacity;
varying lowp float opacity;
void main() {
- opacity = mix(a_opacity_min, a_opacity_max, a_opacity_t);
+ opacity = unpack_mix_vec2(a_opacity, a_opacity_t);
gl_Position = u_matrix * vec4(a_pos, 0, 1);
diff --git a/src/mbgl/shaders/line.cpp b/src/mbgl/shaders/line.cpp
index bd3256ad3b..dc4aa774dc 100644
--- a/src/mbgl/shaders/line.cpp
+++ b/src/mbgl/shaders/line.cpp
@@ -34,32 +34,27 @@ varying vec2 v_width2;
varying float v_gamma_scale;
uniform lowp float a_color_t;
-attribute lowp vec4 a_color_min;
-attribute lowp vec4 a_color_max;
+attribute lowp vec4 a_color;
varying lowp vec4 color;
uniform lowp float a_blur_t;
-attribute lowp float a_blur_min;
-attribute lowp float a_blur_max;
+attribute lowp vec2 a_blur;
varying lowp float blur;
uniform lowp float a_opacity_t;
-attribute lowp float a_opacity_min;
-attribute lowp float a_opacity_max;
+attribute lowp vec2 a_opacity;
varying lowp float opacity;
uniform lowp float a_gapwidth_t;
-attribute mediump float a_gapwidth_min;
-attribute mediump float a_gapwidth_max;
+attribute mediump vec2 a_gapwidth;
varying mediump float gapwidth;
uniform lowp float a_offset_t;
-attribute lowp float a_offset_min;
-attribute lowp float a_offset_max;
+attribute lowp vec2 a_offset;
varying lowp float offset;
void main() {
- color = mix(a_color_min, a_color_max, a_color_t);
- blur = mix(a_blur_min, a_blur_max, a_blur_t);
- opacity = mix(a_opacity_min, a_opacity_max, a_opacity_t);
- gapwidth = mix(a_gapwidth_min, a_gapwidth_max, a_gapwidth_t);
- offset = mix(a_offset_min, a_offset_max, a_offset_t);
+ color = unpack_mix_vec4(a_color, a_color_t);
+ blur = unpack_mix_vec2(a_blur, a_blur_t);
+ opacity = unpack_mix_vec2(a_opacity, a_opacity_t);
+ gapwidth = unpack_mix_vec2(a_gapwidth, a_gapwidth_t);
+ offset = unpack_mix_vec2(a_offset, a_offset_t);
vec2 a_extrude = a_data.xy - 128.0;
float a_direction = mod(a_data.z, 4.0) - 1.0;
diff --git a/src/mbgl/shaders/line_pattern.cpp b/src/mbgl/shaders/line_pattern.cpp
index 2be98deab3..f52a8e2157 100644
--- a/src/mbgl/shaders/line_pattern.cpp
+++ b/src/mbgl/shaders/line_pattern.cpp
@@ -37,27 +37,23 @@ varying float v_linesofar;
varying float v_gamma_scale;
uniform lowp float a_blur_t;
-attribute lowp float a_blur_min;
-attribute lowp float a_blur_max;
+attribute lowp vec2 a_blur;
varying lowp float blur;
uniform lowp float a_opacity_t;
-attribute lowp float a_opacity_min;
-attribute lowp float a_opacity_max;
+attribute lowp vec2 a_opacity;
varying lowp float opacity;
uniform lowp float a_offset_t;
-attribute lowp float a_offset_min;
-attribute lowp float a_offset_max;
+attribute lowp vec2 a_offset;
varying lowp float offset;
uniform lowp float a_gapwidth_t;
-attribute mediump float a_gapwidth_min;
-attribute mediump float a_gapwidth_max;
+attribute mediump vec2 a_gapwidth;
varying mediump float gapwidth;
void main() {
- blur = mix(a_blur_min, a_blur_max, a_blur_t);
- opacity = mix(a_opacity_min, a_opacity_max, a_opacity_t);
- offset = mix(a_offset_min, a_offset_max, a_offset_t);
- gapwidth = mix(a_gapwidth_min, a_gapwidth_max, a_gapwidth_t);
+ blur = unpack_mix_vec2(a_blur, a_blur_t);
+ opacity = unpack_mix_vec2(a_opacity, a_opacity_t);
+ offset = unpack_mix_vec2(a_offset, a_offset_t);
+ gapwidth = unpack_mix_vec2(a_gapwidth, a_gapwidth_t);
vec2 a_extrude = a_data.xy - 128.0;
float a_direction = mod(a_data.z, 4.0) - 1.0;
diff --git a/src/mbgl/shaders/line_sdf.cpp b/src/mbgl/shaders/line_sdf.cpp
index 5f01cf00c0..cd0d4ac318 100644
--- a/src/mbgl/shaders/line_sdf.cpp
+++ b/src/mbgl/shaders/line_sdf.cpp
@@ -42,32 +42,27 @@ varying vec2 v_tex_b;
varying float v_gamma_scale;
uniform lowp float a_color_t;
-attribute lowp vec4 a_color_min;
-attribute lowp vec4 a_color_max;
+attribute lowp vec4 a_color;
varying lowp vec4 color;
uniform lowp float a_blur_t;
-attribute lowp float a_blur_min;
-attribute lowp float a_blur_max;
+attribute lowp vec2 a_blur;
varying lowp float blur;
uniform lowp float a_opacity_t;
-attribute lowp float a_opacity_min;
-attribute lowp float a_opacity_max;
+attribute lowp vec2 a_opacity;
varying lowp float opacity;
uniform lowp float a_gapwidth_t;
-attribute mediump float a_gapwidth_min;
-attribute mediump float a_gapwidth_max;
+attribute mediump vec2 a_gapwidth;
varying mediump float gapwidth;
uniform lowp float a_offset_t;
-attribute lowp float a_offset_min;
-attribute lowp float a_offset_max;
+attribute lowp vec2 a_offset;
varying lowp float offset;
void main() {
- color = mix(a_color_min, a_color_max, a_color_t);
- blur = mix(a_blur_min, a_blur_max, a_blur_t);
- opacity = mix(a_opacity_min, a_opacity_max, a_opacity_t);
- gapwidth = mix(a_gapwidth_min, a_gapwidth_max, a_gapwidth_t);
- offset = mix(a_offset_min, a_offset_max, a_offset_t);
+ color = unpack_mix_vec4(a_color, a_color_t);
+ blur = unpack_mix_vec2(a_blur, a_blur_t);
+ opacity = unpack_mix_vec2(a_opacity, a_opacity_t);
+ gapwidth = unpack_mix_vec2(a_gapwidth, a_gapwidth_t);
+ offset = unpack_mix_vec2(a_offset, a_offset_t);
vec2 a_extrude = a_data.xy - 128.0;
float a_direction = mod(a_data.z, 4.0) - 1.0;
diff --git a/src/mbgl/shaders/preludes.cpp b/src/mbgl/shaders/preludes.cpp
index a0e9414ceb..806e655285 100644
--- a/src/mbgl/shaders/preludes.cpp
+++ b/src/mbgl/shaders/preludes.cpp
@@ -43,6 +43,31 @@ vec4 evaluate_zoom_function_4(const vec4 value0, const vec4 value1, const vec4 v
}
}
+
+// To minimize the number of attributes needed in the mapbox-gl-native shaders,
+// we encode a 4-component color into a pair of floats (i.e. a vec2) as follows:
+// [ floor(color.r * 255) * 256 + color.g * 255,
+// floor(color.b * 255) * 256 + color.g * 255 ]
+vec4 decode_color(const vec2 encodedColor) {
+ float r = floor(encodedColor[0]/256.0)/255.0;
+ float g = (encodedColor[0] - r*256.0*255.0)/255.0;
+ float b = floor(encodedColor[1]/256.0)/255.0;
+ float a = (encodedColor[1] - b*256.0*255.0)/255.0;
+ return vec4(r, g, b, a);
+}
+
+// Unpack a pair of paint values and interpolate between them.
+float unpack_mix_vec2(const vec2 packedValue, const float t) {
+ return mix(packedValue[0], packedValue[1], t);
+}
+
+// Unpack a pair of paint values and interpolate between them.
+vec4 unpack_mix_vec4(const vec4 packedColors, const float t) {
+ vec4 minColor = decode_color(vec2(packedColors[0], packedColors[1]));
+ vec4 maxColor = decode_color(vec2(packedColors[2], packedColors[3]));
+ return mix(minColor, maxColor, t);
+}
+
// The offset depends on how many pixels are between the world origin and the edge of the tile:
// vec2 offset = mod(pixel_coord, size)
//
diff --git a/src/mbgl/shaders/symbol_icon.cpp b/src/mbgl/shaders/symbol_icon.cpp
index 5945f1f3b1..9adda0ba16 100644
--- a/src/mbgl/shaders/symbol_icon.cpp
+++ b/src/mbgl/shaders/symbol_icon.cpp
@@ -7,14 +7,13 @@ namespace shaders {
const char* symbol_icon::name = "symbol_icon";
const char* symbol_icon::vertexSource = R"MBGL_SHADER(
-attribute vec2 a_pos;
-attribute vec2 a_offset;
+
+attribute vec4 a_pos_offset;
attribute vec2 a_texture_pos;
attribute vec4 a_data;
uniform lowp float a_opacity_t;
-attribute lowp float a_opacity_min;
-attribute lowp float a_opacity_max;
+attribute lowp vec2 a_opacity;
varying lowp float opacity;
// matrix is for the vertex position.
@@ -30,7 +29,10 @@ varying vec2 v_tex;
varying vec2 v_fade_tex;
void main() {
- opacity = mix(a_opacity_min, a_opacity_max, a_opacity_t);
+ opacity = unpack_mix_vec2(a_opacity, a_opacity_t);
+
+ vec2 a_pos = a_pos_offset.xy;
+ vec2 a_offset = a_pos_offset.zw;
vec2 a_tex = a_texture_pos.xy;
mediump float a_labelminzoom = a_data[0];
diff --git a/src/mbgl/shaders/symbol_sdf.cpp b/src/mbgl/shaders/symbol_sdf.cpp
index ccb4b9cee6..76399dbb55 100644
--- a/src/mbgl/shaders/symbol_sdf.cpp
+++ b/src/mbgl/shaders/symbol_sdf.cpp
@@ -9,30 +9,24 @@ const char* symbol_sdf::name = "symbol_sdf";
const char* symbol_sdf::vertexSource = R"MBGL_SHADER(
const float PI = 3.141592653589793;
-attribute vec2 a_pos;
-attribute vec2 a_offset;
+attribute vec4 a_pos_offset;
attribute vec2 a_texture_pos;
attribute vec4 a_data;
uniform lowp float a_fill_color_t;
-attribute lowp vec4 a_fill_color_min;
-attribute lowp vec4 a_fill_color_max;
+attribute lowp vec4 a_fill_color;
varying lowp vec4 fill_color;
uniform lowp float a_halo_color_t;
-attribute lowp vec4 a_halo_color_min;
-attribute lowp vec4 a_halo_color_max;
+attribute lowp vec4 a_halo_color;
varying lowp vec4 halo_color;
uniform lowp float a_opacity_t;
-attribute lowp float a_opacity_min;
-attribute lowp float a_opacity_max;
+attribute lowp vec2 a_opacity;
varying lowp float opacity;
uniform lowp float a_halo_width_t;
-attribute lowp float a_halo_width_min;
-attribute lowp float a_halo_width_max;
+attribute lowp vec2 a_halo_width;
varying lowp float halo_width;
uniform lowp float a_halo_blur_t;
-attribute lowp float a_halo_blur_min;
-attribute lowp float a_halo_blur_max;
+attribute lowp vec2 a_halo_blur;
varying lowp float halo_blur;
// matrix is for the vertex position.
@@ -53,11 +47,14 @@ varying vec2 v_fade_tex;
varying float v_gamma_scale;
void main() {
- fill_color = mix(a_fill_color_min, a_fill_color_max, a_fill_color_t);
- halo_color = mix(a_halo_color_min, a_halo_color_max, a_halo_color_t);
- opacity = mix(a_opacity_min, a_opacity_max, a_opacity_t);
- halo_width = mix(a_halo_width_min, a_halo_width_max, a_halo_width_t);
- halo_blur = mix(a_halo_blur_min, a_halo_blur_max, a_halo_blur_t);
+ fill_color = unpack_mix_vec4(a_fill_color, a_fill_color_t);
+ halo_color = unpack_mix_vec4(a_halo_color, a_halo_color_t);
+ opacity = unpack_mix_vec2(a_opacity, a_opacity_t);
+ halo_width = unpack_mix_vec2(a_halo_width, a_halo_width_t);
+ halo_blur = unpack_mix_vec2(a_halo_blur, a_halo_blur_t);
+
+ vec2 a_pos = a_pos_offset.xy;
+ vec2 a_offset = a_pos_offset.zw;
vec2 a_tex = a_texture_pos.xy;
mediump float a_labelminzoom = a_data[0];
diff --git a/src/mbgl/style/paint_property_binder.hpp b/src/mbgl/style/paint_property_binder.hpp
index 79c7692b2f..17c99fe1d9 100644
--- a/src/mbgl/style/paint_property_binder.hpp
+++ b/src/mbgl/style/paint_property_binder.hpp
@@ -11,8 +11,11 @@ namespace style {
template <class T, class A>
class ConstantPaintPropertyBinder {
public:
- using Attribute = A;
- using AttributeValue = typename Attribute::Value;
+ using BaseAttribute = A;
+ using BaseAttributeValue = typename BaseAttribute::Value;
+ using BaseAttributeBinding = typename BaseAttribute::Binding;
+
+ using Attribute = attributes::ZoomInterpolatedAttribute<BaseAttribute>;
using AttributeBinding = typename Attribute::Binding;
ConstantPaintPropertyBinder(T constant_)
@@ -22,16 +25,13 @@ public:
void populateVertexVector(const GeometryTileFeature&, std::size_t) {}
void upload(gl::Context&) {}
- AttributeBinding minAttributeBinding(const PossiblyEvaluatedPropertyValue<T>& currentValue) const {
+ AttributeBinding attributeBinding(const PossiblyEvaluatedPropertyValue<T>& currentValue) const {
+ auto val = currentValue.constantOr(constant);
return typename Attribute::ConstantBinding {
- Attribute::value(currentValue.constantOr(constant))
+ Attribute::value(val, val)
};
}
- AttributeBinding maxAttributeBinding(const PossiblyEvaluatedPropertyValue<T>&) const {
- return AttributeBinding();
- }
-
float interpolationFactor(float) const {
return 0.0f;
}
@@ -43,12 +43,13 @@ private:
template <class T, class A>
class SourceFunctionPaintPropertyBinder {
public:
- using Attribute = A;
- using AttributeValue = typename Attribute::Value;
- using AttributeBinding = typename Attribute::Binding;
+ using BaseAttribute = A;
+ using BaseAttributeValue = typename BaseAttribute::Value;
+ using BaseAttributeBinding = typename BaseAttribute::Binding;
+ using BaseVertex = typename gl::Attributes<BaseAttribute>::Vertex;
- using Attributes = gl::Attributes<Attribute>;
- using Vertex = typename Attributes::Vertex;
+ using Attribute = attributes::ZoomInterpolatedAttribute<BaseAttribute>;
+ using AttributeBinding = typename Attribute::Binding;
SourceFunctionPaintPropertyBinder(SourceFunction<T> function_, T defaultValue_)
: function(std::move(function_)),
@@ -56,9 +57,10 @@ public:
}
void populateVertexVector(const GeometryTileFeature& feature, std::size_t length) {
- AttributeValue value = Attribute::value(function.evaluate(feature, defaultValue));
+ auto val = function.evaluate(feature, defaultValue);
+ BaseAttributeValue value = BaseAttribute::value(val);
for (std::size_t i = vertexVector.vertexSize(); i < length; ++i) {
- vertexVector.emplace_back(Vertex { value });
+ vertexVector.emplace_back(BaseVertex { value });
}
}
@@ -66,21 +68,17 @@ public:
vertexBuffer = context.createVertexBuffer(std::move(vertexVector));
}
- AttributeBinding minAttributeBinding(const PossiblyEvaluatedPropertyValue<T>& currentValue) const {
+ AttributeBinding attributeBinding(const PossiblyEvaluatedPropertyValue<T>& currentValue) const {
if (currentValue.isConstant()) {
+ auto val = *currentValue.constant();
return typename Attribute::ConstantBinding {
- Attribute::value(*currentValue.constant())
+ Attribute::value(val, val)
};
} else {
- return Attributes::allVariableBindings(*vertexBuffer)
- .template get<Attribute>();
+ return Attribute::variableBinding(*vertexBuffer, 0, BaseAttribute::Dimensions);
}
}
- AttributeBinding maxAttributeBinding(const PossiblyEvaluatedPropertyValue<T>&) const {
- return AttributeBinding();
- }
-
float interpolationFactor(float) const {
return 0.0f;
}
@@ -88,22 +86,17 @@ public:
private:
SourceFunction<T> function;
T defaultValue;
- gl::VertexVector<Vertex> vertexVector;
- optional<gl::VertexBuffer<Vertex>> vertexBuffer;
+ gl::VertexVector<BaseVertex> vertexVector;
+ optional<gl::VertexBuffer<BaseVertex>> vertexBuffer;
};
template <class T, class A>
class CompositeFunctionPaintPropertyBinder {
public:
- using Attribute = A;
+ using Attribute = attributes::ZoomInterpolatedAttribute<A>;
using AttributeValue = typename Attribute::Value;
using AttributeBinding = typename Attribute::Binding;
-
- using MinAttribute = attributes::Min<Attribute>;
- using MaxAttribute = attributes::Max<Attribute>;
-
- using Attributes = gl::Attributes<MinAttribute, MaxAttribute>;
- using Vertex = typename Attributes::Vertex;
+ using Vertex = typename gl::Attributes<Attribute>::Vertex;
CompositeFunctionPaintPropertyBinder(CompositeFunction<T> function_, float zoom, T defaultValue_)
: function(std::move(function_)),
@@ -113,10 +106,9 @@ public:
void populateVertexVector(const GeometryTileFeature& feature, std::size_t length) {
Range<T> range = function.evaluate(std::get<1>(coveringRanges), feature, defaultValue);
- AttributeValue min = Attribute::value(range.min);
- AttributeValue max = Attribute::value(range.max);
+ AttributeValue minMax = Attribute::value(range.min, range.max);
for (std::size_t i = vertexVector.vertexSize(); i < length; ++i) {
- vertexVector.emplace_back(Vertex { min, max });
+ vertexVector.emplace_back(Vertex { minMax });
}
}
@@ -124,23 +116,14 @@ public:
vertexBuffer = context.createVertexBuffer(std::move(vertexVector));
}
- AttributeBinding minAttributeBinding(const PossiblyEvaluatedPropertyValue<T>& currentValue) const {
+ AttributeBinding attributeBinding(const PossiblyEvaluatedPropertyValue<T>& currentValue) const {
if (currentValue.isConstant()) {
+ auto val = *currentValue.constant();
return typename Attribute::ConstantBinding {
- Attribute::value(*currentValue.constant())
+ Attribute::value(val, val)
};
} else {
- return Attributes::allVariableBindings(*vertexBuffer)
- .template get<MinAttribute>();
- }
- }
-
- AttributeBinding maxAttributeBinding(const PossiblyEvaluatedPropertyValue<T>& currentValue) const {
- if (currentValue.isConstant()) {
- return AttributeBinding();
- } else {
- return Attributes::allVariableBindings(*vertexBuffer)
- .template get<MaxAttribute>();
+ return Attribute::variableBinding(*vertexBuffer, 0);
}
}
@@ -161,24 +144,27 @@ template <class PaintProperty>
class PaintPropertyBinder {
public:
using Type = typename PaintProperty::Type;
- using Attribute = typename PaintProperty::Attribute;
using PropertyValue = typename PaintProperty::EvaluatedType;
+ using BaseAttribute = typename PaintProperty::Attribute;
+ using Attribute = attributes::ZoomInterpolatedAttribute<BaseAttribute>;
+ using AttributeBinding = typename Attribute::Binding;
+
using Binder = variant<
- ConstantPaintPropertyBinder<Type, Attribute>,
- SourceFunctionPaintPropertyBinder<Type, Attribute>,
- CompositeFunctionPaintPropertyBinder<Type, Attribute>>;
+ ConstantPaintPropertyBinder<Type, BaseAttribute>,
+ SourceFunctionPaintPropertyBinder<Type, BaseAttribute>,
+ CompositeFunctionPaintPropertyBinder<Type, BaseAttribute>>;
PaintPropertyBinder(const PropertyValue& value, float zoom)
: binder(value.match(
[&] (const Type& constant) -> Binder {
- return ConstantPaintPropertyBinder<Type, Attribute>(constant);
+ return ConstantPaintPropertyBinder<Type, BaseAttribute>(constant);
},
[&] (const SourceFunction<Type>& function) {
- return SourceFunctionPaintPropertyBinder<Type, Attribute>(function, PaintProperty::defaultValue());
+ return SourceFunctionPaintPropertyBinder<Type, BaseAttribute>(function, PaintProperty::defaultValue());
},
[&] (const CompositeFunction<Type>& function) {
- return CompositeFunctionPaintPropertyBinder<Type, Attribute>(function, zoom, PaintProperty::defaultValue());
+ return CompositeFunctionPaintPropertyBinder<Type, BaseAttribute>(function, zoom, PaintProperty::defaultValue());
}
)) {
}
@@ -195,19 +181,9 @@ public:
});
}
- using MinAttribute = attributes::Min<Attribute>;
- using MaxAttribute = attributes::Max<Attribute>;
- using AttributeBinding = typename Attribute::Binding;
-
- AttributeBinding minAttributeBinding(const PropertyValue& currentValue) const {
- return binder.match([&] (const auto& b) {
- return b.minAttributeBinding(currentValue);
- });
- }
-
- AttributeBinding maxAttributeBinding(const PropertyValue& currentValue) const {
+ AttributeBinding attributeBinding(const PropertyValue& currentValue) const {
return binder.match([&] (const auto& b) {
- return b.maxAttributeBinding(currentValue);
+ return b.attributeBinding(currentValue);
});
}
@@ -252,21 +228,14 @@ public:
});
}
- using MinAttributes = gl::Attributes<typename PaintPropertyBinder<Ps>::MinAttribute...>;
- using MaxAttributes = gl::Attributes<typename PaintPropertyBinder<Ps>::MaxAttribute...>;
-
- using Attributes = gl::ConcatenateAttributes<MinAttributes, MaxAttributes>;
+ using Attributes = gl::Attributes<typename PaintPropertyBinder<Ps>::Attribute...>;
using AttributeBindings = typename Attributes::Bindings;
template <class EvaluatedProperties>
AttributeBindings attributeBindings(const EvaluatedProperties& currentProperties) const {
- const typename MinAttributes::Bindings min {
- binders.template get<Ps>().minAttributeBinding(currentProperties.template get<Ps>())...
- };
- const typename MaxAttributes::Bindings max {
- binders.template get<Ps>().maxAttributeBinding(currentProperties.template get<Ps>())...
+ return typename Attributes::Bindings {
+ binders.template get<Ps>().attributeBinding(currentProperties.template get<Ps>())...
};
- return min.concat(max);
}
using Uniforms = gl::Uniforms<typename PaintPropertyBinder<Ps>::InterpolationUniform...>;