Metal permutations (#1903)

This commit is contained in:
Tim Sylvester
2023-12-04 16:15:35 -08:00
committed by GitHub
parent aa970b186e
commit d46a7c745d
45 changed files with 1043 additions and 348 deletions

View File

@@ -3,9 +3,11 @@
#include <mbgl/gfx/shader.hpp>
#include <mbgl/util/containers.hpp>
#include <iomanip>
#include <memory>
#include <mutex>
#include <shared_mutex>
#include <sstream>
#include <string>
namespace mbgl {
@@ -151,6 +153,11 @@ public:
return {};
}
protected:
std::string getShaderName(const std::string_view& name, const std::size_t key) {
return (std::ostringstream() << name << '#' << std::hex << key).str();
}
private:
mbgl::unordered_map<std::string, std::shared_ptr<gfx::Shader>> programs;
mutable std::shared_mutex programLock;

View File

@@ -354,15 +354,6 @@ public:
for (auto& kv : attrs) {
delegate(kv.first, *kv.second, overrides.get(kv.first));
}
// For OpenGL, the shader attributes are established with reflection, and we have extra
// entries when we share attributes between, e.g., fill and fill-outline drawables.
#if !defined(NDEBUG) && MLN_RENDERER_BACKEND_METAL
// Every override should match a defined attribute.
for (const auto& kv : overrides.attrs) {
const auto hit = attrs.find(kv.first);
assert(hit != attrs.end());
}
#endif
}
VertexAttributeArray& operator=(VertexAttributeArray&&);

View File

@@ -25,6 +25,9 @@ public:
explicit CommandEncoder(Context& context_);
~CommandEncoder() override;
mtl::Context& getContext() { return context; }
const mtl::Context& getContext() const { return context; }
std::unique_ptr<gfx::UploadPass> createUploadPass(const char* name, gfx::Renderable&) override;
std::unique_ptr<gfx::RenderPass> createRenderPass(const char* name, const gfx::RenderPassDescriptor&) override;

View File

@@ -125,6 +125,9 @@ public:
std::size_t size,
bool persistent);
/// Get an empty buffer to act as a placeholder
const BufferResource& getEmptyBuffer();
/// Get a reusable buffer containing the standard fixed tile vertices (+/- `util::EXTENT`)
const BufferResource& getTileVertexBuffer();
@@ -142,6 +145,7 @@ private:
RendererBackend& backend;
bool cleanupOnDestruction = true;
std::optional<BufferResource> emptyBuffer;
std::optional<BufferResource> tileVertexBuffer;
std::optional<BufferResource> tileIndexBuffer;

View File

@@ -21,6 +21,9 @@ public:
RenderPass(CommandEncoder&, const char* name, const gfx::RenderPassDescriptor&);
~RenderPass() override;
mtl::CommandEncoder& getCommandEncoder() { return commandEncoder; }
const mtl::CommandEncoder& getCommandEncoder() const { return commandEncoder; }
const MTLRenderCommandEncoderPtr& getMetalEncoder() const { return encoder; }
const gfx::RenderPassDescriptor& getDescriptor() const { return descriptor; }

View File

@@ -7,8 +7,6 @@
#include <mbgl/util/hash.hpp>
#include <mbgl/util/containers.hpp>
#include <sstream>
namespace mbgl {
namespace gl {
@@ -16,13 +14,14 @@ template <shaders::BuiltIn ShaderID>
class ShaderGroupGL final : public gfx::ShaderGroup {
public:
ShaderGroupGL(const ProgramParameters& programParameters_)
: ShaderGroup(),
: gfx::ShaderGroup(),
programParameters(programParameters_) {}
~ShaderGroupGL() noexcept override = default;
gfx::ShaderPtr getOrCreateShader(gfx::Context& context,
const mbgl::unordered_set<StringIdentity>& propertiesAsUniforms,
std::string_view firstAttribName) override {
constexpr auto& name = shaders::ShaderSource<ShaderID, gfx::Backend::Type::OpenGL>::name;
constexpr auto& vert = shaders::ShaderSource<ShaderID, gfx::Backend::Type::OpenGL>::vertex;
constexpr auto& frag = shaders::ShaderSource<ShaderID, gfx::Backend::Type::OpenGL>::fragment;
@@ -31,7 +30,7 @@ public:
// We could cache these by key here to avoid creating a string key each time, but we
// would need another mutex. We could also push string IDs down into `ShaderGroup`.
const std::string shaderName = getShaderName(key);
const std::string shaderName = getShaderName(name, key);
auto shader = get<gl::ShaderProgramGL>(shaderName);
if (shader) {
return shader;
@@ -62,16 +61,6 @@ public:
return shader;
}
protected:
std::string getShaderName(std::size_t key) {
constexpr auto& name = shaders::ShaderSource<ShaderID, gfx::Backend::Type::OpenGL>::name;
// This could be more efficient.
std::ostringstream stream;
stream << name << '#' << key;
return stream.str();
}
private:
ProgramParameters programParameters;
};

View File

@@ -13,6 +13,7 @@ struct ShaderSource<BuiltIn::BackgroundShader, gfx::Backend::Type::Metal> {
static constexpr auto name = "BackgroundShader";
static constexpr auto vertexMainFunction = "vertexMain";
static constexpr auto fragmentMainFunction = "fragmentMain";
static constexpr auto hasPermutations = false;
static const std::array<AttributeInfo, 1> attributes;
static const std::array<UniformBlockInfo, 2> uniforms;

View File

@@ -10,6 +10,7 @@ struct ShaderSource<BuiltIn::BackgroundPatternShader, gfx::Backend::Type::Metal>
static constexpr auto name = "BackgroundPatternShader";
static constexpr auto vertexMainFunction = "vertexMain";
static constexpr auto fragmentMainFunction = "fragmentMain";
static constexpr auto hasPermutations = false;
static const std::array<AttributeInfo, 1> attributes;
static const std::array<UniformBlockInfo, 2> uniforms;

View File

@@ -13,6 +13,7 @@ struct ShaderSource<BuiltIn::CircleShader, gfx::Backend::Type::Metal> {
static constexpr auto name = "CircleShader";
static constexpr auto vertexMainFunction = "vertexMain";
static constexpr auto fragmentMainFunction = "fragmentMain";
static constexpr auto hasPermutations = true;
static const std::array<AttributeInfo, 8> attributes;
static const std::array<UniformBlockInfo, 6> uniforms;
@@ -22,27 +23,56 @@ struct ShaderSource<BuiltIn::CircleShader, gfx::Backend::Type::Metal> {
struct VertexStage {
short2 position [[attribute(0)]];
#if !defined(HAS_UNIFORM_u_color)
float4 color [[attribute(1)]];
#endif
#if !defined(HAS_UNIFORM_u_radius)
float2 radius [[attribute(2)]];
#endif
#if !defined(HAS_UNIFORM_u_blur)
float2 blur [[attribute(3)]];
#endif
#if !defined(HAS_UNIFORM_u_opacity)
float2 opacity [[attribute(4)]];
#endif
#if !defined(HAS_UNIFORM_u_stroke_color)
float4 stroke_color [[attribute(5)]];
#endif
#if !defined(HAS_UNIFORM_u_stroke_width)
float2 stroke_width [[attribute(6)]];
#endif
#if !defined(HAS_UNIFORM_u_stroke_opacity)
float2 stroke_opacity [[attribute(7)]];
#endif
};
struct FragmentStage {
float4 position [[position, invariant]];
float4 color;
float radius;
half blur;
half opacity;
float4 stroke_color;
float stroke_width;
half stroke_opacity;
float2 extrude;
half antialiasblur;
#if !defined(HAS_UNIFORM_u_color)
half4 color;
#endif
#if !defined(HAS_UNIFORM_u_radius)
float radius;
#endif
#if !defined(HAS_UNIFORM_u_blur)
half blur;
#endif
#if !defined(HAS_UNIFORM_u_opacity)
half opacity;
#endif
#if !defined(HAS_UNIFORM_u_stroke_color)
half4 stroke_color;
#endif
#if !defined(HAS_UNIFORM_u_stroke_width)
half stroke_width;
#endif
#if !defined(HAS_UNIFORM_u_stroke_opacity)
half stroke_opacity;
#endif
};
struct alignas(16) CircleDrawableUBO {
@@ -98,13 +128,17 @@ FragmentStage vertex vertexMain(thread const VertexStage vertx [[stage_in]],
device const CirclePermutationUBO& permutation [[buffer(12)]],
device const ExpressionInputsUBO& expr [[buffer(13)]]) {
const auto color = colorFor(permutation.color, props.color, vertx.color, interp.color_t, expr);
#if defined(HAS_UNIFORM_u_radius)
const auto radius = props.radius;
#else
const auto radius = valueFor(permutation.radius, props.radius, vertx.radius, interp.radius_t, expr);
const auto blur = valueFor(permutation.blur, props.blur, vertx.blur, interp.blur_t, expr);
const auto opacity = valueFor(permutation.opacity, props.opacity, vertx.opacity, interp.opacity_t, expr);
const auto stroke_color = colorFor(permutation.stroke_color, props.stroke_color, vertx.stroke_color, interp.stroke_color_t, expr);
#endif
#if defined(HAS_UNIFORM_u_stroke_width)
const auto stroke_width = props.stroke_width;
#else
const auto stroke_width = valueFor(permutation.stroke_width, props.stroke_width, vertx.stroke_width, interp.stroke_width_t, expr);
const auto stroke_opacity = valueFor(permutation.stroke_opacity, props.stroke_opacity, vertx.stroke_opacity, interp.stroke_opacity_t, expr);
#endif
// unencode the extrusion vector that we snuck into the a_pos vector
const float2 extrude = glMod(float2(vertx.position), 2.0) * 2.0 - 1.0;
@@ -142,15 +176,30 @@ FragmentStage vertex vertexMain(thread const VertexStage vertx [[stage_in]],
return {
.position = position,
.color = color,
.radius = radius,
.blur = half(blur),
.opacity = half(opacity),
.stroke_color = stroke_color,
.stroke_width = stroke_width,
.stroke_opacity = half(stroke_opacity),
.extrude = extrude,
.antialiasblur = antialiasblur,
#if !defined(HAS_UNIFORM_u_color)
.color = half4(colorFor(permutation.color, props.color, vertx.color, interp.color_t, expr)),
#endif
#if !defined(HAS_UNIFORM_u_radius)
.radius = half(radius),
#endif
#if !defined(HAS_UNIFORM_u_blur)
.blur = half(valueFor(permutation.blur, props.blur, vertx.blur, interp.blur_t, expr)),
#endif
#if !defined(HAS_UNIFORM_u_opacity)
.opacity = half(valueFor(permutation.opacity, props.opacity, vertx.opacity, interp.opacity_t, expr)),
#endif
#if !defined(HAS_UNIFORM_u_stroke_color)
.stroke_color = half4(colorFor(permutation.stroke_color, props.stroke_color, vertx.stroke_color, interp.stroke_color_t, expr)),
#endif
#if !defined(HAS_UNIFORM_u_stroke_width)
.stroke_width = half(stroke_width),
#endif
#if !defined(HAS_UNIFORM_u_stroke_opacity)
.stroke_opacity = half(valueFor(permutation.stroke_opacity, props.stroke_opacity, vertx.stroke_opacity, interp.stroke_opacity_t, expr)),
#endif
};
}
@@ -162,13 +211,49 @@ half4 fragment fragmentMain(FragmentStage in [[stage_in]],
return half4(1.0);
}
const float extrude_length = length(in.extrude);
const float antialiased_blur = -max(in.blur, in.antialiasblur);
const float opacity_t = smoothstep(0.0, antialiased_blur, extrude_length - 1.0);
const float color_t = (in.stroke_width < 0.01) ? 0.0 :
smoothstep(antialiased_blur, 0.0, extrude_length - in.radius / (in.radius + in.stroke_width));
#if defined(HAS_UNIFORM_u_color)
const half4 color = half4(props.color);
#else
const half4 color = in.color;
#endif
#if defined(HAS_UNIFORM_u_radius)
const float radius = props.radius;
#else
const float radius = in.radius;
#endif
#if defined(HAS_UNIFORM_u_blur)
const half blur = props.blur;
#else
const half blur = in.blur;
#endif
#if defined(HAS_UNIFORM_u_opacity)
const half opacity = props.opacity;
#else
const half opacity = in.opacity;
#endif
#if defined(HAS_UNIFORM_u_stroke_color)
const half4 stroke_color = half4(props.stroke_color);
#else
const half4 stroke_color = in.stroke_color;
#endif
#if defined(HAS_UNIFORM_u_stroke_width)
const half stroke_width = props.stroke_width;
#else
const half stroke_width = in.stroke_width;
#endif
#if defined(HAS_UNIFORM_u_stroke_opacity)
const half stroke_opacity = props.stroke_opacity;
#else
const half stroke_opacity = in.stroke_opacity;
#endif
return half4(opacity_t * mix(in.color * in.opacity, in.stroke_color * in.stroke_opacity, color_t));
const float extrude_length = length(in.extrude);
const float antialiased_blur = -max(blur, in.antialiasblur);
const float opacity_t = smoothstep(0.0, antialiased_blur, extrude_length - 1.0);
const float color_t = (stroke_width < 0.01) ? 0.0 :
smoothstep(antialiased_blur, 0.0, extrude_length - radius / (radius + stroke_width));
return half4(opacity_t * mix(color * opacity, stroke_color * stroke_opacity, color_t));
}
)";
};

View File

@@ -21,6 +21,7 @@ struct ShaderSource<BuiltIn::ClippingMaskProgram, gfx::Backend::Type::Metal> {
static constexpr auto name = "ClippingMaskProgram";
static constexpr auto vertexMainFunction = "vertexMain";
static constexpr auto fragmentMainFunction = "fragmentMain";
static constexpr auto hasPermutations = false;
static const std::array<AttributeInfo, 1> attributes;
static const std::array<UniformBlockInfo, 1> uniforms;

View File

@@ -13,6 +13,7 @@ struct ShaderSource<BuiltIn::CollisionBoxShader, gfx::Backend::Type::Metal> {
static constexpr auto name = "CollisionBoxShader";
static constexpr auto vertexMainFunction = "vertexMain";
static constexpr auto fragmentMainFunction = "fragmentMain";
static constexpr auto hasPermutations = false;
static const std::array<AttributeInfo, 5> attributes;
static const std::array<UniformBlockInfo, 1> uniforms;

View File

@@ -13,6 +13,7 @@ struct ShaderSource<BuiltIn::CollisionCircleShader, gfx::Backend::Type::Metal> {
static constexpr auto name = "CollisionCircleShader";
static constexpr auto vertexMainFunction = "vertexMain";
static constexpr auto fragmentMainFunction = "fragmentMain";
static constexpr auto hasPermutations = false;
static const std::array<AttributeInfo, 4> attributes;
static const std::array<UniformBlockInfo, 1> uniforms;

View File

@@ -13,6 +13,7 @@ struct ShaderSource<BuiltIn::DebugShader, gfx::Backend::Type::Metal> {
static constexpr auto name = "DebugShader";
static constexpr auto vertexMainFunction = "vertexMain";
static constexpr auto fragmentMainFunction = "fragmentMain";
static constexpr auto hasPermutations = false;
static const std::array<AttributeInfo, 1> attributes;
static const std::array<UniformBlockInfo, 1> uniforms;

View File

@@ -13,8 +13,9 @@ struct ShaderSource<BuiltIn::FillShader, gfx::Backend::Type::Metal> {
static constexpr auto name = "FillShader";
static constexpr auto vertexMainFunction = "vertexMain";
static constexpr auto fragmentMainFunction = "fragmentMain";
static constexpr auto hasPermutations = true;
static const std::array<AttributeInfo, 4> attributes;
static const std::array<AttributeInfo, 3> attributes;
static const std::array<UniformBlockInfo, 5> uniforms;
static const std::array<TextureInfo, 0> textures;
@@ -22,14 +23,24 @@ struct ShaderSource<BuiltIn::FillShader, gfx::Backend::Type::Metal> {
struct VertexStage {
short2 position [[attribute(0)]];
#if !defined(HAS_UNIFORM_u_color)
float4 color [[attribute(1)]];
#endif
#if !defined(HAS_UNIFORM_u_opacity)
float2 opacity [[attribute(2)]];
#endif
};
struct FragmentStage {
float4 position [[position, invariant]];
float4 color;
#if !defined(HAS_UNIFORM_u_color)
half4 color;
#endif
#if !defined(HAS_UNIFORM_u_opacity)
half opacity;
#endif
};
struct alignas(16) FillDrawableUBO {
@@ -58,16 +69,14 @@ FragmentStage vertex vertexMain(thread const VertexStage vertx [[stage_in]],
device const FillInterpolateUBO& interp [[buffer(5)]],
device const FillPermutationUBO& permutation [[buffer(6)]],
device const ExpressionInputsUBO& expr [[buffer(7)]]) {
const auto color = colorFor(permutation.color, props.color, vertx.color, interp.color_t, expr);
const auto opacity = valueFor(permutation.opacity, props.opacity, vertx.opacity, interp.opacity_t, expr);
float4 position = drawable.matrix * float4(float2(vertx.position), 0.0f, 1.0f);
return {
.position = position,
.color = color,
.opacity = half(opacity),
.position = drawable.matrix * float4(float2(vertx.position), 0.0f, 1.0f),
#if !defined(HAS_UNIFORM_u_color)
.color = half4(colorFor(permutation.color, props.color, vertx.color, interp.color_t, expr)),
#endif
#if !defined(HAS_UNIFORM_u_opacity)
.opacity = half(valueFor(permutation.opacity, props.opacity, vertx.opacity, interp.opacity_t, expr)),
#endif
};
}
@@ -78,7 +87,19 @@ half4 fragment fragmentMain(FragmentStage in [[stage_in]],
return half4(1.0);
}
return half4(in.color * in.opacity);
#if defined(HAS_UNIFORM_u_color)
const half4 color = half4(props.color);
#else
const half4 color = in.color;
#endif
#if defined(HAS_UNIFORM_u_opacity)
const half opacity = props.opacity;
#else
const half opacity = in.opacity;
#endif
return half4(color * opacity);
}
)";
};
@@ -88,13 +109,13 @@ struct ShaderSource<BuiltIn::FillOutlineShader, gfx::Backend::Type::Metal> {
static constexpr auto name = "FillOutlineShader";
static constexpr auto vertexMainFunction = "vertexMain";
static constexpr auto fragmentMainFunction = "fragmentMain";
static constexpr auto hasPermutations = true;
static const std::array<AttributeInfo, 4> attributes;
static const std::array<AttributeInfo, 3> attributes;
static const std::array<UniformBlockInfo, 5> uniforms;
static const std::array<TextureInfo, 0> textures;
static constexpr auto source = R"(
struct VertexStage {
short2 position [[attribute(0)]];
float4 outline_color [[attribute(1)]];
@@ -103,9 +124,13 @@ struct VertexStage {
struct FragmentStage {
float4 position [[position, invariant]];
float4 outline_color;
float2 pos;
#if !defined(HAS_UNIFORM_u_outline_color)
half4 outline_color;
#endif
#if !defined(HAS_UNIFORM_u_opacity)
half opacity;
#endif
};
struct alignas(16) FillOutlineDrawableUBO {
@@ -136,18 +161,16 @@ FragmentStage vertex vertexMain(thread const VertexStage vertx [[stage_in]],
device const FillOutlineInterpolateUBO& interp [[buffer(5)]],
device const FillOutlinePermutationUBO& permutation [[buffer(6)]],
device const ExpressionInputsUBO& expr [[buffer(7)]]) {
const auto outline_color = colorFor(permutation.outline_color, props.outline_color, vertx.outline_color, interp.outline_color_t, expr);
const auto opacity = valueFor(permutation.opacity, props.opacity, vertx.opacity, interp.opacity_t, expr);
float4 position = drawable.matrix * float4(float2(vertx.position), 0.0f, 1.0f);
float2 v_pos = (position.xy / position.w + 1.0) / 2.0 * drawable.world;
const float4 position = drawable.matrix * float4(float2(vertx.position), 0.0f, 1.0f);
return {
.position = position,
.outline_color = outline_color,
.pos = v_pos,
.opacity = half(opacity),
.pos = (position.xy / position.w + 1.0) / 2.0 * drawable.world,
#if !defined(HAS_UNIFORM_u_outline_color)
.outline_color = half4(colorFor(permutation.outline_color, props.outline_color, vertx.outline_color, interp.outline_color_t, expr)),
#endif
#if !defined(HAS_UNIFORM_u_opacity)
.opacity = half( valueFor(permutation.opacity, props.opacity, vertx.opacity, interp.opacity_t, expr)),
#endif
};
}
@@ -164,7 +187,19 @@ half4 fragment fragmentMain(FragmentStage in [[stage_in]],
// float dist = length(in.pos - in.position.xy);
// float alpha = 1.0 - smoothstep(0.0, 1.0, dist);
return half4(in.outline_color * in.opacity);
#if defined(HAS_UNIFORM_u_outline_color)
const half4 color = half4(props.outline_color);
#else
const half4 color = in.outline_color;
#endif
#if defined(HAS_UNIFORM_u_opacity)
const half opacity = props.opacity;
#else
const half opacity = in.opacity;
#endif
return half4(color * opacity);
}
)";
};
@@ -174,27 +209,41 @@ struct ShaderSource<BuiltIn::FillPatternShader, gfx::Backend::Type::Metal> {
static constexpr auto name = "FillPatternShader";
static constexpr auto vertexMainFunction = "vertexMain";
static constexpr auto fragmentMainFunction = "fragmentMain";
static constexpr auto hasPermutations = true;
static const std::array<AttributeInfo, 4> attributes;
static const std::array<UniformBlockInfo, 6> uniforms;
static const std::array<TextureInfo, 1> textures;
static constexpr auto source = R"(
struct VertexStage {
short2 position [[attribute(0)]];
#if !defined(HAS_UNIFORM_u_pattern_from)
ushort4 pattern_from [[attribute(1)]];
#endif
#if !defined(HAS_UNIFORM_u_pattern_to)
ushort4 pattern_to [[attribute(2)]];
#endif
#if !defined(HAS_UNIFORM_u_opacity)
float2 opacity [[attribute(3)]];
#endif
};
struct FragmentStage {
float4 position [[position, invariant]];
float4 pattern_from;
float4 pattern_to;
float2 v_pos_a;
float2 v_pos_b;
#if !defined(HAS_UNIFORM_u_pattern_from)
float4 pattern_from;
#endif
#if !defined(HAS_UNIFORM_u_pattern_to)
float4 pattern_to;
#endif
#if !defined(HAS_UNIFORM_u_opacity)
half opacity;
#endif
};
struct alignas(16) FillPatternDrawableUBO {
@@ -235,37 +284,51 @@ FragmentStage vertex vertexMain(thread const VertexStage vertx [[stage_in]],
device const FillPatternInterpolateUBO& interp [[buffer(7)]],
device const FillPatternPermutationUBO& permutation [[buffer(8)]],
device const ExpressionInputsUBO& expr [[buffer(9)]]) {
#if defined(HAS_UNIFORM_u_pattern_from)
const auto pattern_from = tileProps.pattern_from;
#else
const auto pattern_from = patternFor(permutation.pattern_from, tileProps.pattern_from, vertx.pattern_from, interp.pattern_from_t, expr);
#endif
#if defined(HAS_UNIFORM_u_pattern_to)
const auto pattern_to = tileProps.pattern_to;
#else
const auto pattern_to = patternFor(permutation.pattern_to, tileProps.pattern_to, vertx.pattern_to, interp.pattern_to_t, expr);
const auto opacity = valueFor(permutation.opacity, props.opacity, vertx.opacity, interp.opacity_t, expr);
#endif
float2 pattern_tl_a = pattern_from.xy;
float2 pattern_br_a = pattern_from.zw;
float2 pattern_tl_b = pattern_to.xy;
float2 pattern_br_b = pattern_to.zw;
const float2 pattern_tl_a = pattern_from.xy;
const float2 pattern_br_a = pattern_from.zw;
const float2 pattern_tl_b = pattern_to.xy;
const float2 pattern_br_b = pattern_to.zw;
float pixelRatio = drawable.scale.x;
float tileZoomRatio = drawable.scale.y;
float fromScale = drawable.scale.z;
float toScale = drawable.scale.w;
const float pixelRatio = drawable.scale.x;
const float tileZoomRatio = drawable.scale.y;
const float fromScale = drawable.scale.z;
const float toScale = drawable.scale.w;
float2 display_size_a = float2((pattern_br_a.x - pattern_tl_a.x) / pixelRatio, (pattern_br_a.y - pattern_tl_a.y) / pixelRatio);
float2 display_size_b = float2((pattern_br_b.x - pattern_tl_b.x) / pixelRatio, (pattern_br_b.y - pattern_tl_b.y) / pixelRatio);
float2 postion = float2(vertx.position);
const float2 display_size_a = float2((pattern_br_a.x - pattern_tl_a.x) / pixelRatio, (pattern_br_a.y - pattern_tl_a.y) / pixelRatio);
const float2 display_size_b = float2((pattern_br_b.x - pattern_tl_b.x) / pixelRatio, (pattern_br_b.y - pattern_tl_b.y) / pixelRatio);
const float2 postion = float2(vertx.position);
return {
.position = drawable.matrix * float4(postion, 0, 1),
.pattern_from = pattern_from,
.pattern_to = pattern_to,
.v_pos_a = get_pattern_pos(drawable.pixel_coord_upper, drawable.pixel_coord_lower, fromScale * display_size_a, tileZoomRatio, postion),
.v_pos_b = get_pattern_pos(drawable.pixel_coord_upper, drawable.pixel_coord_lower, toScale * display_size_b, tileZoomRatio, postion),
.opacity = half(opacity),
#if !defined(HAS_UNIFORM_u_pattern_from)
.pattern_from = pattern_from,
#endif
#if !defined(HAS_UNIFORM_u_pattern_to)
.pattern_to = pattern_to,
#endif
#if !defined(HAS_UNIFORM_u_opacity)
.opacity = half(valueFor(permutation.opacity, props.opacity, vertx.opacity, interp.opacity_t, expr)),
#endif
};
}
half4 fragment fragmentMain(FragmentStage in [[stage_in]],
device const FillPatternDrawableUBO& drawable [[buffer(4)]],
device const FillPatternTilePropsUBO& tileProps [[buffer(5)]],
device const FillPatternEvaluatedPropsUBO& props [[buffer(6)]],
device const FillPatternPermutationUBO& permutation [[buffer(8)]],
texture2d<float, access::sample> image0 [[texture(0)]],
@@ -274,10 +337,28 @@ half4 fragment fragmentMain(FragmentStage in [[stage_in]],
return half4(1.0);
}
const float2 pattern_tl_a = in.pattern_from.xy;
const float2 pattern_br_a = in.pattern_from.zw;
const float2 pattern_tl_b = in.pattern_to.xy;
const float2 pattern_br_b = in.pattern_to.zw;
#if defined(HAS_UNIFORM_u_pattern_from)
const auto pattern_from = tileProps.pattern_from;
#else
const auto pattern_from = in.pattern_from;
#endif
#if defined(HAS_UNIFORM_u_pattern_to)
const auto pattern_to = tileProps.pattern_to;
#else
const auto pattern_to = in.pattern_to;
#endif
#if defined(HAS_UNIFORM_u_opacity)
const auto opacity = props.opacity;
#else
const auto opacity = in.opacity;
#endif
const float2 pattern_tl_a = pattern_from.xy;
const float2 pattern_br_a = pattern_from.zw;
const float2 pattern_tl_b = pattern_to.xy;
const float2 pattern_br_b = pattern_to.zw;
const float2 imagecoord = glMod(in.v_pos_a, 1.0);
const float2 pos = mix(pattern_tl_a / drawable.texsize, pattern_br_a / drawable.texsize, imagecoord);
@@ -287,7 +368,7 @@ half4 fragment fragmentMain(FragmentStage in [[stage_in]],
const float2 pos2 = mix(pattern_tl_b / drawable.texsize, pattern_br_b / drawable.texsize, imagecoord_b);
const float4 color2 = image0.sample(image0_sampler, pos2);
return half4(mix(color1, color2, props.fade) * in.opacity);
return half4(mix(color1, color2, props.fade) * opacity);
}
)";
};
@@ -297,6 +378,7 @@ struct ShaderSource<BuiltIn::FillOutlinePatternShader, gfx::Backend::Type::Metal
static constexpr auto name = "FillOutlinePatternShader";
static constexpr auto vertexMainFunction = "vertexMain";
static constexpr auto fragmentMainFunction = "fragmentMain";
static constexpr auto hasPermutations = true;
static const std::array<AttributeInfo, 4> attributes;
static const std::array<UniformBlockInfo, 6> uniforms;
@@ -306,19 +388,33 @@ struct ShaderSource<BuiltIn::FillOutlinePatternShader, gfx::Backend::Type::Metal
struct VertexStage {
short2 position [[attribute(0)]];
#if !defined(HAS_UNIFORM_u_pattern_from)
ushort4 pattern_from [[attribute(1)]];
#endif
#if !defined(HAS_UNIFORM_u_pattern_to)
ushort4 pattern_to [[attribute(2)]];
#endif
#if !defined(HAS_UNIFORM_u_opacity)
float2 opacity [[attribute(3)]];
#endif
};
struct FragmentStage {
float4 position [[position, invariant]];
float2 v_pos_a;
float2 v_pos_b;
float4 pattern_from;
float4 pattern_to;
float2 v_pos;
#if !defined(HAS_UNIFORM_u_pattern_from)
float4 pattern_from;
#endif
#if !defined(HAS_UNIFORM_u_pattern_to)
float4 pattern_to;
#endif
#if !defined(HAS_UNIFORM_u_opacity)
half opacity;
#endif
};
struct alignas(16) FillOutlinePatternDrawableUBO {
@@ -360,39 +456,58 @@ FragmentStage vertex vertexMain(thread const VertexStage vertx [[stage_in]],
device const FillOutlinePatternInterpolateUBO& interp [[buffer(7)]],
device const FillOutlinePatternPermutationUBO& permutation [[buffer(8)]],
device const ExpressionInputsUBO& expr [[buffer(9)]]) {
#if defined(HAS_UNIFORM_u_pattern_from)
const auto pattern_from = tileProps.pattern_from;
#else
const auto pattern_from = patternFor(permutation.pattern_from, tileProps.pattern_from, vertx.pattern_from, interp.pattern_from_t, expr);
#endif
#if defined(HAS_UNIFORM_u_pattern_to)
const auto pattern_to = tileProps.pattern_to;
#else
const auto pattern_to = patternFor(permutation.pattern_to, tileProps.pattern_to, vertx.pattern_to, interp.pattern_to_t, expr);
#endif
#if !defined(HAS_UNIFORM_u_opacity)
const auto opacity = valueFor(permutation.opacity, props.opacity, vertx.opacity, interp.opacity_t, expr);
#endif
float2 pattern_tl_a = pattern_from.xy;
float2 pattern_br_a = pattern_from.zw;
float2 pattern_tl_b = pattern_to.xy;
float2 pattern_br_b = pattern_to.zw;
const float2 pattern_tl_a = pattern_from.xy;
const float2 pattern_br_a = pattern_from.zw;
const float2 pattern_tl_b = pattern_to.xy;
const float2 pattern_br_b = pattern_to.zw;
float pixelRatio = drawable.scale.x;
float tileZoomRatio = drawable.scale.y;
float fromScale = drawable.scale.z;
float toScale = drawable.scale.w;
const float pixelRatio = drawable.scale.x;
const float tileZoomRatio = drawable.scale.y;
const float fromScale = drawable.scale.z;
const float toScale = drawable.scale.w;
float2 display_size_a = float2((pattern_br_a.x - pattern_tl_a.x) / pixelRatio, (pattern_br_a.y - pattern_tl_a.y) / pixelRatio);
float2 display_size_b = float2((pattern_br_b.x - pattern_tl_b.x) / pixelRatio, (pattern_br_b.y - pattern_tl_b.y) / pixelRatio);
float2 pos2 = float2(vertx.position);
float4 position = drawable.matrix * float4(pos2, 0, 1);
const float2 display_size_a = float2((pattern_br_a.x - pattern_tl_a.x) / pixelRatio, (pattern_br_a.y - pattern_tl_a.y) / pixelRatio);
const float2 display_size_b = float2((pattern_br_b.x - pattern_tl_b.x) / pixelRatio, (pattern_br_b.y - pattern_tl_b.y) / pixelRatio);
const float2 pos2 = float2(vertx.position);
const float4 position = drawable.matrix * float4(pos2, 0, 1);
return {
.position = position,
.pattern_from = pattern_from,
.pattern_to = pattern_to,
.v_pos_a = get_pattern_pos(drawable.pixel_coord_upper, drawable.pixel_coord_lower, fromScale * display_size_a, tileZoomRatio, pos2),
.v_pos_b = get_pattern_pos(drawable.pixel_coord_upper, drawable.pixel_coord_lower, toScale * display_size_b, tileZoomRatio, pos2),
.v_pos = (position.xy / position.w + 1.0) / 2.0 * drawable.world,
#if !defined(HAS_UNIFORM_u_pattern_from)
.pattern_from = pattern_from,
#endif
#if !defined(HAS_UNIFORM_u_pattern_to)
.pattern_to = pattern_to,
#endif
#if !defined(HAS_UNIFORM_u_opacity)
.opacity = half(opacity),
#endif
};
}
half4 fragment fragmentMain(FragmentStage in [[stage_in]],
device const FillOutlinePatternDrawableUBO& drawable [[buffer(4)]],
device const FillOutlinePatternTilePropsUBO& tileProps [[buffer(5)]],
device const FillOutlinePatternEvaluatedPropsUBO& props [[buffer(6)]],
device const FillOutlinePatternPermutationUBO& permutation [[buffer(8)]],
texture2d<float, access::sample> image0 [[texture(0)]],
@@ -401,10 +516,28 @@ half4 fragment fragmentMain(FragmentStage in [[stage_in]],
return half4(1.0);
}
const float2 pattern_tl_a = in.pattern_from.xy;
const float2 pattern_br_a = in.pattern_from.zw;
const float2 pattern_tl_b = in.pattern_to.xy;
const float2 pattern_br_b = in.pattern_to.zw;
#if defined(HAS_UNIFORM_u_pattern_from)
const auto pattern_from = tileProps.pattern_from;
#else
const auto pattern_from = in.pattern_from;
#endif
#if defined(HAS_UNIFORM_u_pattern_to)
const auto pattern_to = tileProps.pattern_to;
#else
const auto pattern_to = in.pattern_to;
#endif
#if defined(HAS_UNIFORM_u_opacity)
const auto opacity = props.opacity;
#else
const auto opacity = in.opacity;
#endif
const float2 pattern_tl_a = pattern_from.xy;
const float2 pattern_br_a = pattern_from.zw;
const float2 pattern_tl_b = pattern_to.xy;
const float2 pattern_br_b = pattern_to.zw;
const float2 imagecoord = glMod(in.v_pos_a, 1.0);
const float2 pos = mix(pattern_tl_a / drawable.texsize, pattern_br_a / drawable.texsize, imagecoord);
@@ -418,7 +551,7 @@ half4 fragment fragmentMain(FragmentStage in [[stage_in]],
//float dist = length(in.v_pos - in.position.xy);
//float alpha = 1.0 - smoothstep(0.0, 1.0, dist);
return half4(mix(color1, color2, props.fade) * in.opacity);
return half4(mix(color1, color2, props.fade) * opacity);
}
)";
};

View File

@@ -13,6 +13,7 @@ struct ShaderSource<BuiltIn::FillExtrusionShader, gfx::Backend::Type::Metal> {
static constexpr auto name = "FillExtrusionShader";
static constexpr auto vertexMainFunction = "vertexMain";
static constexpr auto fragmentMainFunction = "fragmentMain";
static constexpr auto hasPermutations = false;
static const std::array<AttributeInfo, 5> attributes;
static const std::array<UniformBlockInfo, 5> uniforms;

View File

@@ -13,6 +13,7 @@ struct ShaderSource<BuiltIn::FillExtrusionPatternShader, gfx::Backend::Type::Met
static constexpr auto name = "FillExtrusionPatternShader";
static constexpr auto vertexMainFunction = "vertexMain";
static constexpr auto fragmentMainFunction = "fragmentMain";
static constexpr auto hasPermutations = false;
static const std::array<AttributeInfo, 6> attributes;
static const std::array<UniformBlockInfo, 6> uniforms;

View File

@@ -13,6 +13,7 @@ struct ShaderSource<BuiltIn::HeatmapShader, gfx::Backend::Type::Metal> {
static constexpr auto name = "HeatmapShader";
static constexpr auto vertexMainFunction = "vertexMain";
static constexpr auto fragmentMainFunction = "fragmentMain";
static constexpr auto hasPermutations = false;
static const std::array<AttributeInfo, 3> attributes;
static const std::array<UniformBlockInfo, 5> uniforms;

View File

@@ -13,6 +13,7 @@ struct ShaderSource<BuiltIn::HeatmapTextureShader, gfx::Backend::Type::Metal> {
static constexpr auto name = "HeatmapTextureShader";
static constexpr auto vertexMainFunction = "vertexMain";
static constexpr auto fragmentMainFunction = "fragmentMain";
static constexpr auto hasPermutations = false;
static const std::array<AttributeInfo, 1> attributes;
static const std::array<UniformBlockInfo, 1> uniforms;

View File

@@ -13,6 +13,7 @@ struct ShaderSource<BuiltIn::HillshadeShader, gfx::Backend::Type::Metal> {
static constexpr auto name = "HillshadeShader";
static constexpr auto vertexMainFunction = "vertexMain";
static constexpr auto fragmentMainFunction = "fragmentMain";
static constexpr auto hasPermutations = false;
static const std::array<AttributeInfo, 2> attributes;
static const std::array<UniformBlockInfo, 2> uniforms;

View File

@@ -13,6 +13,7 @@ struct ShaderSource<BuiltIn::HillshadePrepareShader, gfx::Backend::Type::Metal>
static constexpr auto name = "HillshadePrepareShader";
static constexpr auto vertexMainFunction = "vertexMain";
static constexpr auto fragmentMainFunction = "fragmentMain";
static constexpr auto hasPermutations = false;
static const std::array<AttributeInfo, 2> attributes;
static const std::array<UniformBlockInfo, 1> uniforms;

View File

@@ -13,32 +13,52 @@ struct ShaderSource<BuiltIn::LineShader, gfx::Backend::Type::Metal> {
static constexpr auto name = "LineShader";
static constexpr auto vertexMainFunction = "vertexMain";
static constexpr auto fragmentMainFunction = "fragmentMain";
static constexpr auto hasPermutations = true;
static const std::array<AttributeInfo, 8> attributes;
static const std::array<UniformBlockInfo, 5> uniforms;
static const std::array<TextureInfo, 0> textures;
static constexpr auto source = R"(
struct VertexStage {
short2 pos_normal [[attribute(0)]];
uchar4 data [[attribute(1)]];
#if !defined(HAS_UNIFORM_u_color)
float4 color [[attribute(2)]];
#endif
#if !defined(HAS_UNIFORM_u_blur)
float2 blur [[attribute(3)]];
#endif
#if !defined(HAS_UNIFORM_u_opacity)
float2 opacity [[attribute(4)]];
#endif
#if !defined(HAS_UNIFORM_u_gapwidth)
float2 gapwidth [[attribute(5)]];
#endif
#if !defined(HAS_UNIFORM_u_offset)
float2 offset [[attribute(6)]];
#endif
#if !defined(HAS_UNIFORM_u_width)
float2 width [[attribute(7)]];
#endif
};
struct FragmentStage {
float4 position [[position, invariant]];
float2 width2;
float2 normal;
float gamma_scale;
half gamma_scale;
#if !defined(HAS_UNIFORM_u_color)
float4 color;
#endif
#if !defined(HAS_UNIFORM_u_blur)
float blur;
#endif
#if !defined(HAS_UNIFORM_u_opacity)
float opacity;
#endif
};
FragmentStage vertex vertexMain(thread const VertexStage vertx [[stage_in]],
@@ -48,12 +68,21 @@ FragmentStage vertex vertexMain(thread const VertexStage vertx [[stage_in]],
device const LinePermutationUBO& permutation [[buffer(11)]],
device const ExpressionInputsUBO& expr [[buffer(12)]]) {
const auto color = colorFor(permutation.color, props.color, vertx.color, interp.color_t, expr);
const auto blur = valueFor(permutation.blur, props.blur, vertx.blur, interp.blur_t, expr);
const auto opacity = valueFor(permutation.opacity, props.opacity, vertx.opacity, interp.opacity_t, expr);
#if defined(HAS_UNIFORM_u_gapwidth)
const auto gapwidth = props.gapwidth / 2;
#else
const auto gapwidth = valueFor(permutation.gapwidth, props.gapwidth, vertx.gapwidth, interp.gapwidth_t, expr) / 2;
#endif
#if defined(HAS_UNIFORM_u_offset)
const auto offset = props.offset * -1;
#else
const auto offset = valueFor(permutation.offset, props.offset, vertx.offset, interp.offset_t, expr) * -1;
#endif
#if defined(HAS_UNIFORM_u_width)
const auto width = props.width;
#else
const auto width = valueFor(permutation.width, props.width, vertx.width, interp.width_t, expr);
#endif
// the distance over which the line edge fades out.
// Retina devices need a smaller distance to avoid aliasing.
@@ -95,29 +124,53 @@ FragmentStage vertex vertexMain(thread const VertexStage vertx [[stage_in]],
.position = position,
.width2 = float2(outset, inset),
.normal = v_normal,
.gamma_scale = extrude_length_without_perspective / extrude_length_with_perspective,
.color = color,
.blur = blur,
.opacity = opacity,
.gamma_scale = half(extrude_length_without_perspective / extrude_length_with_perspective),
#if !defined(HAS_UNIFORM_u_color)
.color = colorFor(permutation.color, props.color, vertx.color, interp.color_t, expr),
#endif
#if !defined(HAS_UNIFORM_u_blur)
.blur = valueFor(permutation.blur, props.blur, vertx.blur, interp.blur_t, expr),
#endif
#if !defined(HAS_UNIFORM_u_opacity)
.opacity = valueFor(permutation.opacity, props.opacity, vertx.opacity, interp.opacity_t, expr),
#endif
};
}
half4 fragment fragmentMain(FragmentStage in [[stage_in]],
device const LineUBO& line [[buffer(8)]],
device const LinePropertiesUBO& props [[buffer(9)]],
device const LinePermutationUBO& permutation [[buffer(11)]]) {
if (permutation.overdrawInspector) {
return half4(1.0);
}
#if defined(HAS_UNIFORM_u_color)
const float4 color = props.color;
#else
const float4 color = in.color;
#endif
#if defined(HAS_UNIFORM_u_blur)
const float blur = props.blur;
#else
const float blur = in.blur;
#endif
#if defined(HAS_UNIFORM_u_opacity)
const float opacity = props.opacity;
#else
const float opacity = in.opacity;
#endif
// Calculate the distance of the pixel from the line in pixels.
const float dist = length(in.normal) * in.width2.x;
// Calculate the antialiasing fade factor. This is either when fading in the
// line in case of an offset line (v_width2.y) or when fading out (v_width2.x)
const float blur2 = (in.blur + 1.0 / line.device_pixel_ratio) * in.gamma_scale;
const float blur2 = (blur + 1.0 / line.device_pixel_ratio) * in.gamma_scale;
const float alpha = clamp(min(dist - (in.width2.y - blur2), in.width2.x - dist) / blur2, 0.0, 1.0);
return half4(in.color * (alpha * in.opacity));
return half4(color * (alpha * opacity));
}
)";
};
@@ -127,35 +180,59 @@ struct ShaderSource<BuiltIn::LinePatternShader, gfx::Backend::Type::Metal> {
static constexpr auto name = "LinePatternShader";
static constexpr auto vertexMainFunction = "vertexMain";
static constexpr auto fragmentMainFunction = "fragmentMain";
static constexpr auto hasPermutations = false;
static const std::array<AttributeInfo, 9> attributes;
static const std::array<UniformBlockInfo, 6> uniforms;
static const std::array<TextureInfo, 1> textures;
static constexpr auto source = R"(
struct VertexStage {
short2 pos_normal [[attribute(0)]];
uchar4 data [[attribute(1)]];
#if !defined(HAS_UNIFORM_u_blur)
float2 blur [[attribute(2)]];
#endif
#if !defined(HAS_UNIFORM_u_opacity)
float2 opacity [[attribute(3)]];
#endif
#if !defined(HAS_UNIFORM_u_gapwidth)
float2 gapwidth [[attribute(4)]];
#endif
#if !defined(HAS_UNIFORM_u_offset)
float2 offset [[attribute(5)]];
#endif
#if !defined(HAS_UNIFORM_u_width)
float2 width [[attribute(6)]];
#endif
#if !defined(HAS_UNIFORM_u_pattern_from)
ushort4 pattern_from [[attribute(7)]];
#endif
#if !defined(HAS_UNIFORM_u_pattern_to)
ushort4 pattern_to [[attribute(8)]];
#endif
};
struct FragmentStage {
float4 position [[position, invariant]];
float2 width2;
float2 normal;
float gamma_scale;
float blur;
float opacity;
float4 pattern_from;
float4 pattern_to;
half gamma_scale;
float linesofar;
#if !defined(HAS_UNIFORM_u_blur)
float blur;
#endif
#if !defined(HAS_UNIFORM_u_opacity)
float opacity;
#endif
#if !defined(HAS_UNIFORM_u_pattern_from)
float4 pattern_from;
#endif
#if !defined(HAS_UNIFORM_u_pattern_to)
float4 pattern_to;
#endif
};
struct alignas(16) LinePatternUBO {
@@ -202,14 +279,21 @@ FragmentStage vertex vertexMain(thread const VertexStage vertx [[stage_in]],
device const LinePermutationUBO& permutation [[buffer(13)]],
device const ExpressionInputsUBO& expr [[buffer(14)]]) {
const auto blur = valueFor(permutation.blur, props.blur, vertx.blur, interp.blur_t, expr);
const auto opacity = valueFor(permutation.opacity, props.opacity, vertx.opacity, interp.opacity_t, expr);
#if defined(HAS_UNIFORM_u_gapwidth)
const auto gapwidth = props.gapwidth / 2;
#else
const auto gapwidth = valueFor(permutation.gapwidth, props.gapwidth, vertx.gapwidth, interp.gapwidth_t, expr) / 2;
#endif
#if defined(HAS_UNIFORM_u_offset)
const auto offset = props.offset * -1;
#else
const auto offset = valueFor(permutation.offset, props.offset, vertx.offset, interp.offset_t, expr) * -1;
#endif
#if defined(HAS_UNIFORM_u_width)
const auto width = props.width;
#else
const auto width = valueFor(permutation.width, props.width, vertx.width, interp.width_t, expr);
const auto pattern_from = patternFor(permutation.pattern_from, tileProps.pattern_from, vertx.pattern_from, interp.pattern_from_t, expr);
const auto pattern_to = patternFor(permutation.pattern_to, tileProps.pattern_to, vertx.pattern_to, interp.pattern_to_t, expr);
#endif
// the distance over which the line edge fades out.
// Retina devices need a smaller distance to avoid aliasing.
@@ -218,7 +302,7 @@ FragmentStage vertex vertexMain(thread const VertexStage vertx [[stage_in]],
const float2 a_extrude = float2(vertx.data.xy) - 128.0;
const float a_direction = fmod(float(vertx.data.z), 4.0) - 1.0;
float linesofar = (floor(vertx.data.z / 4.0) + vertx.data.w * 64.0) * LINE_DISTANCE_SCALE;
const float linesofar = (floor(vertx.data.z / 4.0) + vertx.data.w * 64.0) * LINE_DISTANCE_SCALE;
const float2 pos = floor(float2(vertx.pos_normal) * 0.5);
// x is 1 if it's a round cap, 0 otherwise
@@ -253,17 +337,28 @@ FragmentStage vertex vertexMain(thread const VertexStage vertx [[stage_in]],
.position = position,
.width2 = float2(outset, inset),
.normal = v_normal,
.gamma_scale = extrude_length_without_perspective / extrude_length_with_perspective,
.blur = blur,
.opacity = opacity,
.pattern_from = pattern_from,
.pattern_to = pattern_to,
.gamma_scale = half(extrude_length_without_perspective / extrude_length_with_perspective),
.linesofar = linesofar,
#if !defined(HAS_UNIFORM_u_blur)
.blur = valueFor(permutation.blur, props.blur, vertx.blur, interp.blur_t, expr),
#endif
#if !defined(HAS_UNIFORM_u_opacity)
.opacity = valueFor(permutation.opacity, props.opacity, vertx.opacity, interp.opacity_t, expr),
#endif
#if !defined(HAS_UNIFORM_u_pattern_from)
.pattern_from = patternFor(permutation.pattern_from, tileProps.pattern_from, vertx.pattern_from, interp.pattern_from_t, expr),
#endif
#if !defined(HAS_UNIFORM_u_pattern_to)
.pattern_to = patternFor(permutation.pattern_to, tileProps.pattern_to, vertx.pattern_to, interp.pattern_to_t, expr),
#endif
};
}
half4 fragment fragmentMain(FragmentStage in [[stage_in]],
device const LinePatternUBO& line [[buffer(9)]],
device const LinePatternPropertiesUBO& props [[buffer(10)]],
device const LinePatternTilePropertiesUBO& tileProps [[buffer(12)]],
device const LinePermutationUBO& permutation [[buffer(13)]],
texture2d<float, access::sample> image0 [[texture(0)]],
sampler image0_sampler [[sampler(0)]]) {
@@ -271,47 +366,68 @@ half4 fragment fragmentMain(FragmentStage in [[stage_in]],
return half4(1.0);
}
float2 pattern_tl_a = in.pattern_from.xy;
float2 pattern_br_a = in.pattern_from.zw;
float2 pattern_tl_b = in.pattern_to.xy;
float2 pattern_br_b = in.pattern_to.zw;
#if defined(HAS_UNIFORM_u_blur)
const auto blur = props.blur;
#else
const auto blur = in.blur;
#endif
#if defined(HAS_UNIFORM_u_opacity)
const auto opacity = props.opacity;
#else
const auto opacity = in.opacity;
#endif
#if defined(HAS_UNIFORM_u_pattern_from)
const auto pattern_from = tileProps.pattern_from;
#else
const auto pattern_from = in.pattern_from;
#endif
#if defined(HAS_UNIFORM_u_pattern_to)
const auto pattern_to = tileProps.pattern_to;
#else
const auto pattern_to = in.pattern_to;
#endif
float pixelRatio = line.scale.x;
float tileZoomRatio = line.scale.y;
float fromScale = line.scale.z;
float toScale = line.scale.w;
const float2 pattern_tl_a = pattern_from.xy;
const float2 pattern_br_a = pattern_from.zw;
const float2 pattern_tl_b = pattern_to.xy;
const float2 pattern_br_b = pattern_to.zw;
float2 display_size_a = float2((pattern_br_a.x - pattern_tl_a.x) / pixelRatio, (pattern_br_a.y - pattern_tl_a.y) / pixelRatio);
float2 display_size_b = float2((pattern_br_b.x - pattern_tl_b.x) / pixelRatio, (pattern_br_b.y - pattern_tl_b.y) / pixelRatio);
const float pixelRatio = line.scale.x;
const float tileZoomRatio = line.scale.y;
const float fromScale = line.scale.z;
const float toScale = line.scale.w;
float2 pattern_size_a = float2(display_size_a.x * fromScale / tileZoomRatio, display_size_a.y);
float2 pattern_size_b = float2(display_size_b.x * toScale / tileZoomRatio, display_size_b.y);
const float2 display_size_a = float2((pattern_br_a.x - pattern_tl_a.x) / pixelRatio, (pattern_br_a.y - pattern_tl_a.y) / pixelRatio);
const float2 display_size_b = float2((pattern_br_b.x - pattern_tl_b.x) / pixelRatio, (pattern_br_b.y - pattern_tl_b.y) / pixelRatio);
const float2 pattern_size_a = float2(display_size_a.x * fromScale / tileZoomRatio, display_size_a.y);
const float2 pattern_size_b = float2(display_size_b.x * toScale / tileZoomRatio, display_size_b.y);
// Calculate the distance of the pixel from the line in pixels.
float dist = length(in.normal) * in.width2.x;
const float dist = length(in.normal) * in.width2.x;
// Calculate the antialiasing fade factor. This is either when fading in
// the line in case of an offset line (in.width2.y) or when fading out
// (in.width2.x)
float blur2 = (in.blur + 1.0 / DEVICE_PIXEL_RATIO) * in.gamma_scale;
float alpha = clamp(min(dist - (in.width2.y - blur2), in.width2.x - dist) / blur2, 0.0, 1.0);
const float blur2 = (blur + 1.0 / DEVICE_PIXEL_RATIO) * in.gamma_scale;
const float alpha = clamp(min(dist - (in.width2.y - blur2), in.width2.x - dist) / blur2, 0.0, 1.0);
float x_a = glMod(in.linesofar / pattern_size_a.x, 1.0);
float x_b = glMod(in.linesofar / pattern_size_b.x, 1.0);
const float x_a = glMod(in.linesofar / pattern_size_a.x, 1.0);
const float x_b = glMod(in.linesofar / pattern_size_b.x, 1.0);
// in.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 + (in.normal.y * clamp(in.width2.x, 0.0, (pattern_size_a.y + 2.0) / 2.0) / pattern_size_a.y);
float y_b = 0.5 + (in.normal.y * clamp(in.width2.x, 0.0, (pattern_size_b.y + 2.0) / 2.0) / pattern_size_b.y);
float2 pos_a = mix(pattern_tl_a / line.texsize, pattern_br_a / line.texsize, float2(x_a, y_a));
float2 pos_b = mix(pattern_tl_b / line.texsize, pattern_br_b / line.texsize, float2(x_b, y_b));
const float y_a = 0.5 + (in.normal.y * clamp(in.width2.x, 0.0, (pattern_size_a.y + 2.0) / 2.0) / pattern_size_a.y);
const float y_b = 0.5 + (in.normal.y * clamp(in.width2.x, 0.0, (pattern_size_b.y + 2.0) / 2.0) / pattern_size_b.y);
const float2 pos_a = mix(pattern_tl_a / line.texsize, pattern_br_a / line.texsize, float2(x_a, y_a));
const float2 pos_b = mix(pattern_tl_b / line.texsize, pattern_br_b / line.texsize, float2(x_b, y_b));
float4 color = mix(image0.sample(image0_sampler, pos_a), image0.sample(image0_sampler, pos_b), line.fade);
const float4 color = mix(image0.sample(image0_sampler, pos_a), image0.sample(image0_sampler, pos_b), line.fade);
return half4(color * alpha * in.opacity);
return half4(color * alpha * opacity);
}
)";
};
@@ -321,36 +437,60 @@ struct ShaderSource<BuiltIn::LineSDFShader, gfx::Backend::Type::Metal> {
static constexpr auto name = "LineSDFShader";
static constexpr auto vertexMainFunction = "vertexMain";
static constexpr auto fragmentMainFunction = "fragmentMain";
static constexpr auto hasPermutations = true;
static const std::array<AttributeInfo, 9> attributes;
static const std::array<UniformBlockInfo, 5> uniforms;
static const std::array<TextureInfo, 1> textures;
static constexpr auto source = R"(
struct VertexStage {
short2 pos_normal [[attribute(0)]];
uchar4 data [[attribute(1)]];
#if !defined(HAS_UNIFORM_u_color)
float4 color [[attribute(2)]];
#endif
#if !defined(HAS_UNIFORM_u_blur)
float2 blur [[attribute(3)]];
#endif
#if !defined(HAS_UNIFORM_u_opacity)
float2 opacity [[attribute(4)]];
#endif
#if !defined(HAS_UNIFORM_u_gapwidth)
float2 gapwidth [[attribute(5)]];
#endif
#if !defined(HAS_UNIFORM_u_offset)
float2 offset [[attribute(6)]];
#endif
#if !defined(HAS_UNIFORM_u_width)
float2 width [[attribute(7)]];
#endif
#if !defined(HAS_UNIFORM_u_floorwidth)
float2 floorwidth [[attribute(8)]];
#endif
};
struct FragmentStage {
float4 position [[position, invariant]];
float4 color;
float2 width2;
float2 normal;
float gamma_scale;
float blur;
float opacity;
float2 tex_a;
float2 tex_b;
half gamma_scale;
#if !defined(HAS_UNIFORM_u_color)
float4 color;
#endif
#if !defined(HAS_UNIFORM_u_blur)
float blur;
#endif
#if !defined(HAS_UNIFORM_u_opacity)
float opacity;
#endif
#if !defined(HAS_UNIFORM_u_floorwidth)
float floorwidth;
#endif
};
struct alignas(16) LineSDFUBO {
@@ -395,13 +535,26 @@ FragmentStage vertex vertexMain(thread const VertexStage vertx [[stage_in]],
device const LinePermutationUBO& permutation [[buffer(12)]],
device const ExpressionInputsUBO& expr [[buffer(13)]]) {
const auto color = colorFor(permutation.color, props.color, vertx.color, interp.color_t, expr);
const auto blur = valueFor(permutation.blur, props.blur, vertx.blur, interp.blur_t, expr);
const auto opacity = valueFor(permutation.opacity, props.opacity, vertx.opacity, interp.opacity_t, expr);
#if defined(HAS_UNIFORM_u_gapwidth)
const auto gapwidth = props.gapwidth / 2;
#else
const auto gapwidth = valueFor(permutation.gapwidth, props.gapwidth, vertx.gapwidth, interp.gapwidth_t, expr) / 2;
#endif
#if defined(HAS_UNIFORM_u_offset)
const auto offset = props.offset * -1;
#else
const auto offset = valueFor(permutation.offset, props.offset, vertx.offset, interp.offset_t, expr) * -1;
#endif
#if defined(HAS_UNIFORM_u_width)
const auto width = props.width;
#else
const auto width = valueFor(permutation.width, props.width, vertx.width, interp.width_t, expr);
#endif
#if defined(HAS_UNIFORM_u_floorwidth)
const auto floorwidth = props.floorwidth;
#else
const auto floorwidth = valueFor(permutation.floorwidth, props.floorwidth, vertx.floorwidth, interp.floorwidth_t, expr);
#endif
// the distance over which the line edge fades out.
// Retina devices need a smaller distance to avoid aliasing.
@@ -443,20 +596,30 @@ FragmentStage vertex vertexMain(thread const VertexStage vertx [[stage_in]],
return {
.position = position,
.color = color,
.width2 = float2(outset, inset),
.normal = v_normal,
.gamma_scale = extrude_length_without_perspective / extrude_length_with_perspective,
.blur = blur,
.opacity = opacity,
.gamma_scale = half(extrude_length_without_perspective / extrude_length_with_perspective),
.tex_a = float2(linesofar * line.patternscale_a.x / floorwidth, (normal.y * line.patternscale_a.y + line.tex_y_a) * 2.0),
.tex_b = float2(linesofar * line.patternscale_b.x / floorwidth, (normal.y * line.patternscale_b.y + line.tex_y_b) * 2.0),
#if !defined(HAS_UNIFORM_u_color)
.color = colorFor(permutation.color, props.color, vertx.color, interp.color_t, expr),
#endif
#if !defined(HAS_UNIFORM_u_blur)
.blur = valueFor(permutation.blur, props.blur, vertx.blur, interp.blur_t, expr),
#endif
#if !defined(HAS_UNIFORM_u_opacity)
.opacity = valueFor(permutation.opacity, props.opacity, vertx.opacity, interp.opacity_t, expr),
#endif
#if !defined(HAS_UNIFORM_u_floorwidth)
.floorwidth = floorwidth,
#endif
};
}
half4 fragment fragmentMain(FragmentStage in [[stage_in]],
device const LineSDFUBO& line [[buffer(9)]],
device const LineSDFPropertiesUBO& props [[buffer(10)]],
device const LinePermutationUBO& permutation [[buffer(12)]],
texture2d<float, access::sample> image0 [[texture(0)]],
sampler image0_sampler [[sampler(0)]]) {
@@ -464,18 +627,39 @@ half4 fragment fragmentMain(FragmentStage in [[stage_in]],
return half4(1.0);
}
const float dist = length(in.normal) * in.width2.x;
#if defined(HAS_UNIFORM_u_color)
const float4 color = props.color;
#else
const float4 color = in.color;
#endif
#if defined(HAS_UNIFORM_u_blur)
const float blur = props.blur;
#else
const float blur = in.blur;
#endif
#if defined(HAS_UNIFORM_u_opacity)
const float opacity = props.opacity;
#else
const float opacity = in.opacity;
#endif
#if defined(HAS_UNIFORM_u_floorwidth)
const float floorwidth = props.floorwidth;
#else
const float floorwidth = in.floorwidth;
#endif
// Calculate the antialiasing fade factor. This is either when fading in the
// line in case of an offset line (v_width2.y) or when fading out (v_width2.x)
const float blur2 = (in.blur + 1.0 / line.device_pixel_ratio) * in.gamma_scale;
float alpha = clamp(min(dist - (in.width2.y - blur2), in.width2.x - dist) / blur2, 0.0, 1.0);
// line in case of an offset line (`v_width2.y`) or when fading out (`v_width2.x`)
const float blur2 = (blur + 1.0 / line.device_pixel_ratio) * in.gamma_scale;
float sdfdist_a = image0.sample(image0_sampler, in.tex_a).a;
float sdfdist_b = image0.sample(image0_sampler, in.tex_b).a;
float sdfdist = mix(sdfdist_a, sdfdist_b, line.mix);
alpha *= smoothstep(0.5 - line.sdfgamma / in.floorwidth, 0.5 + line.sdfgamma / in.floorwidth, sdfdist);
const float sdfdist_a = image0.sample(image0_sampler, in.tex_a).a;
const float sdfdist_b = image0.sample(image0_sampler, in.tex_b).a;
const float sdfdist = mix(sdfdist_a, sdfdist_b, line.mix);
const float dist = length(in.normal) * in.width2.x;
const float alpha = clamp(min(dist - (in.width2.y - blur2), in.width2.x - dist) / blur2, 0.0, 1.0) *
smoothstep(0.5 - line.sdfgamma / floorwidth, 0.5 + line.sdfgamma / floorwidth, sdfdist);
return half4(in.color * (alpha * in.opacity));
return half4(color * (alpha * opacity));
}
)";
};
@@ -485,13 +669,13 @@ struct ShaderSource<BuiltIn::LineBasicShader, gfx::Backend::Type::Metal> {
static constexpr auto name = "LineBasicShader";
static constexpr auto vertexMainFunction = "vertexMain";
static constexpr auto fragmentMainFunction = "fragmentMain";
static constexpr auto hasPermutations = true;
static const std::array<AttributeInfo, 2> attributes;
static const std::array<UniformBlockInfo, 2> uniforms;
static const std::array<TextureInfo, 0> textures;
static constexpr auto source = R"(
struct VertexStage {
short2 pos_normal [[attribute(0)]];
uchar4 data [[attribute(1)]];
@@ -501,9 +685,7 @@ struct FragmentStage {
float4 position [[position, invariant]];
float width2;
float2 normal;
float gamma_scale;
float4 color;
float opacity;
half gamma_scale;
};
FragmentStage vertex vertexMain(thread const VertexStage vertx [[stage_in]],
@@ -540,24 +722,23 @@ FragmentStage vertex vertexMain(thread const VertexStage vertx [[stage_in]],
.position = position,
.width2 = outset,
.normal = v_normal,
.gamma_scale = extrude_length_without_perspective / extrude_length_with_perspective,
.color = props.color,
.opacity = props.opacity,
.gamma_scale = half(extrude_length_without_perspective / extrude_length_with_perspective),
};
}
half4 fragment fragmentMain(FragmentStage in [[stage_in]],
device const LineBasicUBO& line [[buffer(2)]]) {
device const LineBasicUBO& line [[buffer(2)]],
device const LineBasicPropertiesUBO& props [[buffer(3)]]) {
// Calculate the distance of the pixel from the line in pixels.
const float dist = length(in.normal) * in.width2;
// Calculate the antialiasing fade factor. This is either when fading in the
// line in case of an offset line (v_width2.y) or when fading out (v_width2.x)
// line in case of an offset line (`v_width2.y`) or when fading out (`v_width2.x`)
const float blur2 = (1.0 / line.device_pixel_ratio) * in.gamma_scale;
const float alpha = clamp(min(dist + blur2, in.width2 - dist) / blur2, 0.0, 1.0);
return half4(in.color * (alpha * in.opacity));
return half4(props.color * (alpha * props.opacity));
}
)";
};

View File

@@ -13,6 +13,7 @@ struct ShaderSource<BuiltIn::LineGradientShader, gfx::Backend::Type::Metal> {
static constexpr auto name = "LineGradientShader";
static constexpr auto vertexMainFunction = "vertexMain";
static constexpr auto fragmentMainFunction = "fragmentMain";
static constexpr auto hasPermutations = false;
static const std::array<AttributeInfo, 7> attributes;
static const std::array<UniformBlockInfo, 5> uniforms;

View File

@@ -13,6 +13,7 @@ struct ShaderSource<BuiltIn::RasterShader, gfx::Backend::Type::Metal> {
static constexpr auto name = "RasterShader";
static constexpr auto vertexMainFunction = "vertexMain";
static constexpr auto fragmentMainFunction = "fragmentMain";
static constexpr auto hasPermutations = false;
static const std::array<AttributeInfo, 2> attributes;
static const std::array<UniformBlockInfo, 1> uniforms;

View File

@@ -5,48 +5,83 @@
#include <mbgl/shaders/mtl/background.hpp>
#include <mbgl/shaders/mtl/shader_program.hpp>
#include <mbgl/shaders/shader_source.hpp>
#include <mbgl/util/hash.hpp>
#include <mbgl/util/containers.hpp>
#include <numeric>
#include <string>
#include <unordered_map>
#include <type_traits>
namespace mbgl {
namespace mtl {
class ShaderGroupBase : public gfx::ShaderGroup {
public:
using StringIDSet = mbgl::unordered_set<StringIdentity>;
protected:
using DefinesMap = mbgl::unordered_map<std::string, std::string>;
void addAdditionalDefines(const StringIDSet& propertiesAsUniforms, DefinesMap& additionalDefines) {
const std::string uniformPrefix = "HAS_UNIFORM_u_";
additionalDefines.reserve(propertiesAsUniforms.size() + 1);
additionalDefines.insert(std::make_pair("HAS_PERMUTATIONS", std::string()));
for (const auto nameID : propertiesAsUniforms) {
// We expect the names to be prefixed by "a_", but we need just the base here.
const auto name = stringIndexer().get(nameID);
const auto* base = (name[0] == 'a' && name[1] == '_') ? &name[2] : name.data();
additionalDefines.insert(std::make_pair(uniformPrefix + base, std::string()));
}
}
};
template <shaders::BuiltIn ShaderID>
class ShaderGroup final : public gfx::ShaderGroup {
class ShaderGroup final : public ShaderGroupBase {
public:
ShaderGroup(const ProgramParameters& programParameters_)
: gfx::ShaderGroup(),
: ShaderGroupBase(),
programParameters(programParameters_) {}
~ShaderGroup() noexcept override = default;
gfx::ShaderPtr getOrCreateShader(gfx::Context& gfxContext,
const mbgl::unordered_set<StringIdentity>& propertiesAsUniforms,
std::string_view /*firstAttribName*/) override {
constexpr auto& name = shaders::ShaderSource<ShaderID, gfx::Backend::Type::Metal>::name;
constexpr auto& source = shaders::ShaderSource<ShaderID, gfx::Backend::Type::Metal>::source;
constexpr auto& vertMain = shaders::ShaderSource<ShaderID, gfx::Backend::Type::Metal>::vertexMainFunction;
constexpr auto& fragMain = shaders::ShaderSource<ShaderID, gfx::Backend::Type::Metal>::fragmentMainFunction;
using ShaderSource = shaders::ShaderSource<ShaderID, gfx::Backend::Type::Metal>;
constexpr auto& name = ShaderSource::name;
constexpr auto& source = ShaderSource::source;
constexpr auto& vertMain = ShaderSource::vertexMainFunction;
constexpr auto& fragMain = ShaderSource::fragmentMainFunction;
constexpr auto permutations = shaders::ShaderSource<ShaderID, gfx::Backend::Type::Metal>::hasPermutations;
const std::string shaderName = std::string(name);
const size_t key = permutations
? util::order_independent_hash(propertiesAsUniforms.begin(), propertiesAsUniforms.end())
: 0;
const std::string shaderName = permutations ? getShaderName(name, key) : name;
auto shader = get<mtl::ShaderProgram>(shaderName);
if (!shader) {
DefinesMap additionalDefines;
if (permutations) {
addAdditionalDefines(propertiesAsUniforms, additionalDefines);
}
auto& context = static_cast<Context&>(gfxContext);
const auto shaderSource = std::string(shaders::prelude) + source;
shader = context.createProgram(shaderName, shaderSource, vertMain, fragMain, programParameters, {});
shader = context.createProgram(
shaderName, shaderSource, vertMain, fragMain, programParameters, additionalDefines);
assert(shader);
if (!shader || !registerShader(shader, shaderName)) {
assert(false);
throw std::runtime_error("Failed to register " + shaderName + " with shader group!");
}
shader->setBindMissingAttributes(!permutations);
using ShaderClass = shaders::ShaderSource<ShaderID, gfx::Backend::Type::Metal>;
for (const auto& attrib : ShaderClass::attributes) {
if (!permutations || !propertiesAsUniforms.count(attrib.nameID)) {
shader->initAttribute(attrib);
}
}
for (const auto& uniform : ShaderClass::uniforms) {
shader->initUniformBlock(uniform);
}

View File

@@ -6,7 +6,6 @@
#include <mbgl/mtl/vertex_attribute.hpp>
#include <Foundation/NSSharedPtr.hpp>
#include <Metal/MTLLibrary.hpp>
#include <optional>
#include <string>
@@ -50,7 +49,7 @@ public:
RendererBackend& backend,
MTLFunctionPtr vertexFunction,
MTLFunctionPtr fragmentFunction);
~ShaderProgram() noexcept override = default;
~ShaderProgram() noexcept override;
static constexpr std::string_view Name{"GenericMTLShader"};
const std::string_view typeName() const noexcept override { return Name; }
@@ -70,6 +69,9 @@ public:
void initUniformBlock(const shaders::UniformBlockInfo&);
void initTexture(const shaders::TextureInfo&);
bool getBindMissingAttributes() const { return bindMissingAttributes; }
void setBindMissingAttributes(bool value) { bindMissingAttributes = value; }
protected:
std::string shaderName;
RendererBackend& backend;
@@ -78,6 +80,7 @@ protected:
UniformBlockArray uniformBlocks;
VertexAttributeArray vertexAttributes;
std::unordered_map<StringIdentity, std::size_t> textureBindings;
bool bindMissingAttributes = true;
};
} // namespace mtl

View File

@@ -13,6 +13,7 @@ struct ShaderSource<BuiltIn::SymbolIconShader, gfx::Backend::Type::Metal> {
static constexpr auto name = "SymbolIconShader";
static constexpr auto vertexMainFunction = "vertexMain";
static constexpr auto fragmentMainFunction = "fragmentMain";
static constexpr auto hasPermutations = true;
static const std::array<AttributeInfo, 6> attributes;
static const std::array<UniformBlockInfo, 7> uniforms;
@@ -25,14 +26,20 @@ struct VertexStage {
float4 pixeloffset [[attribute(2)]];
float3 projected_pos [[attribute(3)]];
float fade_opacity [[attribute(4)]];
#if !defined(HAS_UNIFORM_u_opacity)
float opacity [[attribute(5)]];
#endif
};
struct FragmentStage {
float4 position [[position, invariant]];
float2 tex;
float fade_opacity;
float opacity;
half fade_opacity;
#if !defined(HAS_UNIFORM_u_opacity)
half opacity;
#endif
};
FragmentStage vertex vertexMain(thread const VertexStage vertx [[stage_in]],
@@ -44,8 +51,6 @@ FragmentStage vertex vertexMain(thread const VertexStage vertx [[stage_in]],
device const SymbolPermutationUBO& permutation [[buffer(13)]],
device const ExpressionInputsUBO& expr [[buffer(14)]]) {
const auto opacity = valueFor(permutation.opacity, paint.opacity, vertx.opacity, interp.opacity_t, expr);
const float2 a_pos = vertx.pos_offset.xy;
const float2 a_offset = vertx.pos_offset.zw;
@@ -107,13 +112,16 @@ FragmentStage vertex vertexMain(thread const VertexStage vertx [[stage_in]],
return {
.position = position,
.tex = a_tex / drawable.texsize,
.fade_opacity = max(0.0, min(1.0, fade_opacity[0] + fade_change)),
.opacity = opacity,
.fade_opacity = half(max(0.0, min(1.0, fade_opacity[0] + fade_change))),
#if !defined(HAS_UNIFORM_u_opacity)
.opacity = half(valueFor(permutation.opacity, paint.opacity, vertx.opacity, interp.opacity_t, expr)),
#endif
};
}
half4 fragment fragmentMain(FragmentStage in [[stage_in]],
device const SymbolDrawableUBO& drawable [[buffer(8)]],
device const SymbolDrawablePaintUBO& paint [[buffer(10)]],
device const SymbolPermutationUBO& permutation [[buffer(13)]],
texture2d<float, access::sample> image [[texture(0)]],
sampler image_sampler [[sampler(0)]]) {
@@ -121,7 +129,13 @@ half4 fragment fragmentMain(FragmentStage in [[stage_in]],
return half4(1.0);
}
return half4(image.sample(image_sampler, in.tex) * (in.opacity * in.fade_opacity));
#if defined(HAS_UNIFORM_u_opacity)
const half opacity = half(paint.opacity);
#else
const half opacity = in.opacity;
#endif
return half4(image.sample(image_sampler, in.tex) * (opacity * in.fade_opacity));
}
)";
};

View File

@@ -13,6 +13,7 @@ struct ShaderSource<BuiltIn::SymbolSDFIconShader, gfx::Backend::Type::Metal> {
static constexpr auto name = "SymbolSDFIconShader";
static constexpr auto vertexMainFunction = "vertexMain";
static constexpr auto fragmentMainFunction = "fragmentMain";
static constexpr auto hasPermutations = true;
static const std::array<AttributeInfo, 10> attributes;
static const std::array<UniformBlockInfo, 7> uniforms;
@@ -26,22 +27,43 @@ struct VertexStage {
float3 projected_pos [[attribute(3)]];
float fade_opacity [[attribute(4)]];
#if !defined(HAS_UNIFORM_u_fill_color)
float4 fill_color [[attribute(5)]];
#endif
#if !defined(HAS_UNIFORM_u_halo_color)
float4 halo_color [[attribute(6)]];
#endif
#if !defined(HAS_UNIFORM_u_opacity)
float opacity [[attribute(7)]];
#endif
#if !defined(HAS_UNIFORM_u_halo_width)
float halo_width [[attribute(8)]];
#endif
#if !defined(HAS_UNIFORM_u_halo_blur)
float halo_blur [[attribute(9)]];
#endif
};
struct FragmentStage {
float4 position [[position, invariant]];
float4 fill_color;
float4 halo_color;
float halo_width;
float halo_blur;
float opacity;
float2 data0;
float3 data1;
#if !defined(HAS_UNIFORM_u_fill_color)
half4 fill_color;
#endif
#if !defined(HAS_UNIFORM_u_halo_color)
half4 halo_color;
#endif
#if !defined(HAS_UNIFORM_u_opacity)
half opacity;
#endif
#if !defined(HAS_UNIFORM_u_halo_width)
half halo_width;
#endif
#if !defined(HAS_UNIFORM_u_halo_blur)
half halo_blur;
#endif
};
FragmentStage vertex vertexMain(thread const VertexStage vertx [[stage_in]],
@@ -53,12 +75,6 @@ FragmentStage vertex vertexMain(thread const VertexStage vertx [[stage_in]],
device const SymbolPermutationUBO& permutation [[buffer(15)]],
device const ExpressionInputsUBO& expr [[buffer(16)]]) {
const auto fill_color = colorFor(permutation.fill_color, paint.fill_color, vertx.fill_color, interp.fill_color_t, expr);
const auto halo_color = colorFor(permutation.halo_color, paint.halo_color, vertx.halo_color, interp.halo_color_t, expr);
const auto opacity = valueFor(permutation.opacity, paint.opacity, vertx.opacity, interp.opacity_t, expr);
const auto halo_width = valueFor(permutation.halo_width, paint.halo_width, vertx.halo_width, interp.halo_width_t, expr);
const auto halo_blur = valueFor(permutation.halo_blur, paint.halo_blur, vertx.halo_blur, interp.halo_blur_t, expr);
const float2 a_pos = vertx.pos_offset.xy;
const float2 a_offset = vertx.pos_offset.zw;
@@ -128,11 +144,21 @@ FragmentStage vertex vertexMain(thread const VertexStage vertx [[stage_in]],
return {
.position = position,
.fill_color = fill_color,
.halo_color = halo_color,
.halo_width = halo_width,
.halo_blur = halo_blur,
.opacity = opacity,
#if !defined(HAS_UNIFORM_u_fill_color)
.fill_color = half4(colorFor(permutation.fill_color, paint.fill_color, vertx.fill_color, interp.fill_color_t, expr)),
#endif
#if !defined(HAS_UNIFORM_u_halo_color)
.halo_color = half4(colorFor(permutation.halo_color, paint.halo_color, vertx.halo_color, interp.halo_color_t, expr)),
#endif
#if !defined(HAS_UNIFORM_u_halo_width)
.halo_width = half(valueFor(permutation.halo_width, paint.halo_width, vertx.halo_width, interp.halo_width_t, expr)),
#endif
#if !defined(HAS_UNIFORM_u_halo_blur)
.halo_blur = half(valueFor(permutation.halo_blur, paint.halo_blur, vertx.halo_blur, interp.halo_blur_t, expr)),
#endif
#if !defined(HAS_UNIFORM_u_opacity)
.opacity = half(valueFor(permutation.opacity, paint.opacity, vertx.opacity, interp.opacity_t, expr)),
#endif
.data0 = a_tex / drawable.texsize,
.data1 = float3(gamma_scale, size, interpolated_fade_opacity),
};
@@ -141,6 +167,7 @@ FragmentStage vertex vertexMain(thread const VertexStage vertx [[stage_in]],
half4 fragment fragmentMain(FragmentStage in [[stage_in]],
device const SymbolDrawableUBO& drawable [[buffer(10)]],
device const SymbolDynamicUBO& dynamic [[buffer(11)]],
device const SymbolDrawablePaintUBO& paint [[buffer(12)]],
device const SymbolDrawableTilePropsUBO& props [[buffer(13)]],
device const SymbolPermutationUBO& permutation [[buffer(15)]],
texture2d<float, access::sample> image [[texture(0)]],
@@ -149,29 +176,47 @@ half4 fragment fragmentMain(FragmentStage in [[stage_in]],
return half4(1.0);
}
const float EDGE_GAMMA = 0.105 / dynamic.device_pixel_ratio;
#if defined(HAS_UNIFORM_u_fill_color)
const half4 fill_color = half4(paint.fill_color);
#else
const half4 fill_color = in.fill_color;
#endif
#if defined(HAS_UNIFORM_u_halo_color)
const half4 halo_color = half4(paint.halo_color);
#else
const half4 halo_color = in.halo_color;
#endif
#if defined(HAS_UNIFORM_u_opacity)
const half opacity = half(paint.opacity);
#else
const half opacity = in.opacity;
#endif
#if defined(HAS_UNIFORM_u_halo_width)
const half halo_width = half(paint.halo_width);
#else
const half halo_width = in.halo_width;
#endif
#if defined(HAS_UNIFORM_u_halo_blur)
const half halo_blur = half(paint.halo_blur);
#else
const half halo_blur = in.halo_blur;
#endif
const float EDGE_GAMMA = 0.105 / dynamic.device_pixel_ratio;
const float2 tex = in.data0.xy;
const float gamma_scale = in.data1.x;
const float size = in.data1.y;
const float fade_opacity = in.data1[2];
const float fontScale = props.is_text ? size / 24.0 : size;
float4 color = in.fill_color;
float gamma = EDGE_GAMMA / (fontScale * drawable.gamma_scale);
float buff = (256.0 - 64.0) / 256.0;
if (props.is_halo) {
color = in.halo_color;
gamma = (in.halo_blur * 1.19 / SDF_PX + EDGE_GAMMA) / (fontScale * drawable.gamma_scale);
buff = (6.0 - in.halo_width / fontScale) / SDF_PX;
}
const float fontGamma = fontScale * drawable.gamma_scale;
const half4 color = props.is_halo ? halo_color : fill_color;
const float gamma = ((props.is_halo ? (halo_blur * 1.19 / SDF_PX) : 0) + EDGE_GAMMA) / fontGamma;
const float buff = props.is_halo ? (6.0 - halo_width / fontScale) / SDF_PX : (256.0 - 64.0) / 256.0;
const float dist = image.sample(image_sampler, tex).a;
const float gamma_scaled = gamma * gamma_scale;
const float alpha = smoothstep(buff - gamma_scaled, buff + gamma_scaled, dist);
return half4(color * (alpha * in.opacity * fade_opacity));
return half4(color * (alpha * opacity * fade_opacity));
}
)";
};

View File

@@ -13,6 +13,7 @@ struct ShaderSource<BuiltIn::SymbolTextAndIconShader, gfx::Backend::Type::Metal>
static constexpr auto name = "SymbolTextAndIconShader";
static constexpr auto vertexMainFunction = "vertexMain";
static constexpr auto fragmentMainFunction = "fragmentMain";
static constexpr auto hasPermutations = true;
static const std::array<AttributeInfo, 9> attributes;
static const std::array<UniformBlockInfo, 7> uniforms;
@@ -28,22 +29,43 @@ struct VertexStage {
float3 projected_pos [[attribute(2)]];
float fade_opacity [[attribute(3)]];
#if !defined(HAS_UNIFORM_u_fill_color)
float4 fill_color [[attribute(4)]];
#endif
#if !defined(HAS_UNIFORM_u_halo_color)
float4 halo_color [[attribute(5)]];
#endif
#if !defined(HAS_UNIFORM_u_opacity)
float opacity [[attribute(6)]];
#endif
#if !defined(HAS_UNIFORM_u_halo_width)
float halo_width [[attribute(7)]];
#endif
#if !defined(HAS_UNIFORM_u_halo_blur)
float halo_blur [[attribute(8)]];
#endif
};
struct FragmentStage {
float4 position [[position, invariant]];
float4 fill_color;
float4 halo_color;
float halo_width;
float halo_blur;
float opacity;
float4 data0;
float4 data1;
#if !defined(HAS_UNIFORM_u_fill_color)
half4 fill_color;
#endif
#if !defined(HAS_UNIFORM_u_halo_color)
half4 halo_color;
#endif
#if !defined(HAS_UNIFORM_u_opacity)
half opacity;
#endif
#if !defined(HAS_UNIFORM_u_halo_width)
half halo_width;
#endif
#if !defined(HAS_UNIFORM_u_halo_blur)
half halo_blur;
#endif
};
FragmentStage vertex vertexMain(thread const VertexStage vertx [[stage_in]],
@@ -55,12 +77,6 @@ FragmentStage vertex vertexMain(thread const VertexStage vertx [[stage_in]],
device const SymbolPermutationUBO& permutation [[buffer(14)]],
device const ExpressionInputsUBO& expr [[buffer(15)]]) {
const auto fill_color = colorFor(permutation.fill_color, paint.fill_color, vertx.fill_color, interp.fill_color_t, expr);
const auto halo_color = colorFor(permutation.halo_color, paint.halo_color, vertx.halo_color, interp.halo_color_t, expr);
const auto opacity = valueFor(permutation.opacity, paint.opacity, vertx.opacity, interp.opacity_t, expr);
const auto halo_width = valueFor(permutation.halo_width, paint.halo_width, vertx.halo_width, interp.halo_width_t, expr);
const auto halo_blur = valueFor(permutation.halo_blur, paint.halo_blur, vertx.halo_blur, interp.halo_blur_t, expr);
const float2 a_pos = vertx.pos_offset.xy;
const float2 a_offset = vertx.pos_offset.zw;
@@ -130,19 +146,31 @@ FragmentStage vertex vertexMain(thread const VertexStage vertx [[stage_in]],
return {
.position = position,
.fill_color = fill_color,
.halo_color = halo_color,
.halo_width = halo_width,
.halo_blur = halo_blur,
.opacity = opacity,
.data0 = float4(a_tex / drawable.texsize, a_tex / drawable.texsize_icon),
.data1 = float4(gamma_scale, size, interpolated_fade_opacity, is_sdf),
#if !defined(HAS_UNIFORM_u_fill_color)
.fill_color = half(colorFor(permutation.fill_color, paint.fill_color, vertx.fill_color, interp.fill_color_t, expr));
#endif
#if !defined(HAS_UNIFORM_u_halo_color)
.halo_color = half(colorFor(permutation.halo_color, paint.halo_color, vertx.halo_color, interp.halo_color_t, expr));
#endif
#if !defined(HAS_UNIFORM_u_opacity)
.opacity = half(valueFor(permutation.opacity, paint.opacity, vertx.opacity, interp.opacity_t, expr));
#endif
#if !defined(HAS_UNIFORM_u_halo_width)
.halo_width = half(valueFor(permutation.halo_width, paint.halo_width, vertx.halo_width, interp.halo_width_t, expr));
#endif
#if !defined(HAS_UNIFORM_u_halo_blur)
.halo_blur = half(valueFor(permutation.halo_blur, paint.halo_blur, vertx.halo_blur, interp.halo_blur_t, expr));
#endif
};
}
half4 fragment fragmentMain(FragmentStage in [[stage_in]],
device const SymbolDrawableUBO& drawable [[buffer(9)]],
device const SymbolDynamicUBO& dynamic [[buffer(10)]],
device const SymbolDrawablePaintUBO& paint [[buffer(11)]],
device const SymbolDrawableTilePropsUBO& props [[buffer(12)]],
device const SymbolPermutationUBO& permutation [[buffer(14)]],
texture2d<float, access::sample> glyph_image [[texture(0)]],
@@ -153,36 +181,54 @@ half4 fragment fragmentMain(FragmentStage in [[stage_in]],
return half4(1.0);
}
#if defined(HAS_UNIFORM_u_fill_color)
const half4 fill_color = half4(paint.fill_color);
#else
const half4 fill_color = in.fill_color;
#endif
#if defined(HAS_UNIFORM_u_halo_color)
const half4 halo_color = half4(paint.halo_color);
#else
const half4 halo_color = in.halo_color;
#endif
#if defined(HAS_UNIFORM_u_opacity)
const half opacity = half(paint.opacity);
#else
const half opacity = in.opacity;
#endif
#if defined(HAS_UNIFORM_u_halo_width)
const half halo_width = half(paint.halo_width);
#else
const half halo_width = in.halo_width;
#endif
#if defined(HAS_UNIFORM_u_halo_blur)
const half halo_blur = half(paint.halo_blur);
#else
const half halo_blur = in.halo_blur;
#endif
const float fade_opacity = in.data1[2];
if (in.data1.w == ICON) {
const float2 tex_icon = in.data0.zw;
const float alpha = in.opacity * fade_opacity;
const float alpha = opacity * fade_opacity;
return half4(icon_image.sample(icon_sampler, tex_icon) * alpha);
}
const float2 tex = in.data0.xy;
const float EDGE_GAMMA = 0.105 / dynamic.device_pixel_ratio;
const float gamma_scale = in.data1.x;
const float size = in.data1.y;
const float fontScale = size / 24.0;
float4 color = in.fill_color;
float gamma = EDGE_GAMMA / (fontScale * drawable.gamma_scale);
float buff = (256.0 - 64.0) / 256.0;
if (props.is_halo) {
color = in.halo_color;
gamma = (in.halo_blur * 1.19 / SDF_PX + EDGE_GAMMA) / (fontScale * drawable.gamma_scale);
buff = (6.0 - in.halo_width / fontScale) / SDF_PX;
}
const half4 color = props.is_halo ? halo_color : fill_color;
const float fontGamma = fontScale * drawable.gamma_scale;
const float gamma = ((props.is_halo ? (halo_blur * 1.19 / SDF_PX) : 0) + EDGE_GAMMA) / fontGamma;
const float buff = props.is_halo ? (6.0 - halo_width / fontScale) / SDF_PX : (256.0 - 64.0) / 256.0;
const float dist = glyph_image.sample(glyph_sampler, tex).a;
const float gamma_scaled = gamma * gamma_scale;
const float alpha = smoothstep(buff - gamma_scaled, buff + gamma_scaled, dist);
return half4(color * (alpha * in.opacity * fade_opacity));
return half4(color * (alpha * opacity * fade_opacity));
}
)";
};

View File

@@ -210,6 +210,13 @@ bool Context::emplaceOrUpdateUniformBuffer(gfx::UniformBufferPtr& buffer,
}
}
const BufferResource& Context::getEmptyBuffer() {
if (!emptyBuffer) {
emptyBuffer.emplace(const_cast<Context&>(*this), nullptr, 0, MTL::ResourceStorageModeShared, false, false);
}
return *emptyBuffer;
}
const BufferResource& Context::getTileVertexBuffer() {
if (!tileVertexBuffer) {
const auto vertices = RenderStaticData::tileVertices();

View File

@@ -344,8 +344,14 @@ void Drawable::bindAttributes(RenderPass& renderPass) const noexcept {
if (buffer && buffer->get()) {
assert(binding->vertexStride * impl->vertexCount <= getBufferSize(binding->vertexBufferResource));
renderPass.bindVertex(buffer->get(), /*offset=*/0, attributeIndex);
} else if (impl->noBindingBuffer) {
} else {
const auto* shaderMTL = static_cast<const ShaderProgram*>(shader.get());
if (impl->noBindingBuffer && shaderMTL && shaderMTL->getBindMissingAttributes()) {
renderPass.bindVertex(impl->noBindingBuffer->get(), /*offset=*/0, attributeIndex);
} else {
auto& context = renderPass.getCommandEncoder().getContext();
renderPass.bindVertex(context.getEmptyBuffer(), /*offset=*/0, attributeIndex);
}
}
attributeIndex += 1;
}
@@ -536,6 +542,7 @@ void Drawable::upload(gfx::UploadPass& uploadPass_) {
for (auto& binding : impl->attributeBindings) {
if (!binding) {
assert("Missing attribute binding");
index += 1;
continue;
}

View File

@@ -124,7 +124,8 @@ void TileSourceRenderItem::updateDebugDrawables(DebugLayerGroupMap& debugLayerGr
};
// build a set of tiles to cover
std::unordered_set<OverscaledTileID> newTiles;
mbgl::unordered_set<OverscaledTileID> newTiles;
newTiles.reserve(renderTiles->size());
for (auto& tile : *renderTiles) {
newTiles.insert(tile.getOverscaledTileID());
}

View File

@@ -3,15 +3,10 @@
namespace mbgl {
namespace shaders {
const std::array<AttributeInfo, 4> ShaderSource<BuiltIn::FillShader, gfx::Backend::Type::Metal>::attributes = {
const std::array<AttributeInfo, 3> ShaderSource<BuiltIn::FillShader, gfx::Backend::Type::Metal>::attributes = {
AttributeInfo{0, gfx::AttributeDataType::Short2, 1, "a_pos"},
AttributeInfo{1, gfx::AttributeDataType::Float4, 1, "a_color"},
AttributeInfo{2, gfx::AttributeDataType::Float2, 1, "a_opacity"},
// This shader doesn't use it, but we need this so that the layer can assign the same
// attributes to all the drawables. If/When `VertexAttributeArray::resolve` allows it,
// this can be removed.
AttributeInfo{8, gfx::AttributeDataType::Float2, 1, "a_outline_color"},
};
const std::array<UniformBlockInfo, 5> ShaderSource<BuiltIn::FillShader, gfx::Backend::Type::Metal>::uniforms = {
UniformBlockInfo{3, true, false, sizeof(FillDrawableUBO), "FillDrawableUBO"},
@@ -22,13 +17,10 @@ const std::array<UniformBlockInfo, 5> ShaderSource<BuiltIn::FillShader, gfx::Bac
};
const std::array<TextureInfo, 0> ShaderSource<BuiltIn::FillShader, gfx::Backend::Type::Metal>::textures = {};
const std::array<AttributeInfo, 4> ShaderSource<BuiltIn::FillOutlineShader, gfx::Backend::Type::Metal>::attributes = {
const std::array<AttributeInfo, 3> ShaderSource<BuiltIn::FillOutlineShader, gfx::Backend::Type::Metal>::attributes = {
AttributeInfo{0, gfx::AttributeDataType::Short2, 1, "a_pos"},
AttributeInfo{1, gfx::AttributeDataType::Float4, 1, "a_outline_color"},
AttributeInfo{2, gfx::AttributeDataType::Float2, 1, "a_opacity"},
// See `a_outline_color` in FillShader
AttributeInfo{8, gfx::AttributeDataType::Float2, 1, "a_color"},
};
const std::array<UniformBlockInfo, 5> ShaderSource<BuiltIn::FillOutlineShader, gfx::Backend::Type::Metal>::uniforms = {
UniformBlockInfo{3, true, false, sizeof(FillOutlineDrawableUBO), "FillOutlineDrawableUBO"},
@@ -47,7 +39,7 @@ const std::array<AttributeInfo, 4> ShaderSource<BuiltIn::FillPatternShader, gfx:
};
const std::array<UniformBlockInfo, 6> ShaderSource<BuiltIn::FillPatternShader, gfx::Backend::Type::Metal>::uniforms = {
UniformBlockInfo{4, true, true, sizeof(FillPatternDrawableUBO), "FillPatternDrawableUBO"},
UniformBlockInfo{5, true, false, sizeof(FillPatternTilePropsUBO), "FillPatternTilePropsUBO"},
UniformBlockInfo{5, true, true, sizeof(FillPatternTilePropsUBO), "FillPatternTilePropsUBO"},
UniformBlockInfo{6, true, true, sizeof(FillPatternEvaluatedPropsUBO), "FillPatternEvaluatedPropsUBO"},
UniformBlockInfo{7, true, false, sizeof(FillPatternInterpolateUBO), "FillPatternInterpolateUBO"},
UniformBlockInfo{8, true, true, sizeof(FillPatternPermutationUBO), "FillPatternPermutationUBO"},
@@ -67,7 +59,7 @@ const std::array<AttributeInfo, 4>
const std::array<UniformBlockInfo, 6> ShaderSource<BuiltIn::FillOutlinePatternShader,
gfx::Backend::Type::Metal>::uniforms = {
UniformBlockInfo{4, true, true, sizeof(FillOutlinePatternDrawableUBO), "FillOutlinePatternDrawableUBO"},
UniformBlockInfo{5, true, false, sizeof(FillOutlinePatternTilePropsUBO), "FillOutlinePatternTilePropsUBO"},
UniformBlockInfo{5, true, true, sizeof(FillOutlinePatternTilePropsUBO), "FillOutlinePatternTilePropsUBO"},
UniformBlockInfo{6, true, true, sizeof(FillOutlinePatternEvaluatedPropsUBO), "FillOutlinePatternEvaluatedPropsUBO"},
UniformBlockInfo{7, true, false, sizeof(FillOutlinePatternInterpolateUBO), "FillOutlinePatternInterpolateUBO"},
UniformBlockInfo{8, true, true, sizeof(FillOutlinePatternPermutationUBO), "FillOutlinePatternPermutationUBO"},

View File

@@ -15,7 +15,7 @@ const std::array<AttributeInfo, 8> ShaderSource<BuiltIn::LineShader, gfx::Backen
};
const std::array<UniformBlockInfo, 5> ShaderSource<BuiltIn::LineShader, gfx::Backend::Type::Metal>::uniforms = {
UniformBlockInfo{8, true, true, sizeof(LineUBO), "LineUBO"},
UniformBlockInfo{9, true, false, sizeof(LinePropertiesUBO), "LinePropertiesUBO"},
UniformBlockInfo{9, true, true, sizeof(LinePropertiesUBO), "LinePropertiesUBO"},
UniformBlockInfo{10, true, false, sizeof(LineInterpolationUBO), "LineInterpolationUBO"},
UniformBlockInfo{11, true, true, sizeof(LinePermutationUBO), "LinePermutationUBO"},
UniformBlockInfo{12, true, false, sizeof(ExpressionInputsUBO), "ExpressionInputsUBO"},
@@ -35,9 +35,9 @@ const std::array<AttributeInfo, 9> ShaderSource<BuiltIn::LinePatternShader, gfx:
};
const std::array<UniformBlockInfo, 6> ShaderSource<BuiltIn::LinePatternShader, gfx::Backend::Type::Metal>::uniforms = {
UniformBlockInfo{9, true, true, sizeof(LinePatternUBO), "LinePatternUBO"},
UniformBlockInfo{10, true, false, sizeof(LinePatternPropertiesUBO), "LinePatternPropertiesUBO"},
UniformBlockInfo{10, true, true, sizeof(LinePatternPropertiesUBO), "LinePatternPropertiesUBO"},
UniformBlockInfo{11, true, false, sizeof(LinePatternInterpolationUBO), "LinePatternInterpolationUBO"},
UniformBlockInfo{12, true, false, sizeof(LinePatternTilePropertiesUBO), "LinePatternTilePropertiesUBO"},
UniformBlockInfo{12, true, true, sizeof(LinePatternTilePropertiesUBO), "LinePatternTilePropertiesUBO"},
UniformBlockInfo{13, true, true, sizeof(LinePermutationUBO), "LinePermutationUBO"},
UniformBlockInfo{14, true, false, sizeof(ExpressionInputsUBO), "ExpressionInputsUBO"},
};
@@ -58,7 +58,7 @@ const std::array<AttributeInfo, 9> ShaderSource<BuiltIn::LineSDFShader, gfx::Bac
};
const std::array<UniformBlockInfo, 5> ShaderSource<BuiltIn::LineSDFShader, gfx::Backend::Type::Metal>::uniforms = {
UniformBlockInfo{9, true, true, sizeof(LineSDFUBO), "LineSDFUBO"},
UniformBlockInfo{10, true, false, sizeof(LineSDFPropertiesUBO), "LineSDFPropertiesUBO"},
UniformBlockInfo{10, true, true, sizeof(LineSDFPropertiesUBO), "LineSDFPropertiesUBO"},
UniformBlockInfo{11, true, false, sizeof(LineSDFInterpolationUBO), "LineSDFInterpolationUBO"},
UniformBlockInfo{12, true, true, sizeof(LinePermutationUBO), "LinePermutationUBO"},
UniformBlockInfo{13, true, false, sizeof(ExpressionInputsUBO), "ExpressionInputsUBO"},
@@ -73,7 +73,7 @@ const std::array<AttributeInfo, 2> ShaderSource<BuiltIn::LineBasicShader, gfx::B
};
const std::array<UniformBlockInfo, 2> ShaderSource<BuiltIn::LineBasicShader, gfx::Backend::Type::Metal>::uniforms = {
UniformBlockInfo{2, true, true, sizeof(LineBasicUBO), "LineBasicUBO"},
UniformBlockInfo{3, true, false, sizeof(LineBasicPropertiesUBO), "LineBasicPropertiesUBO"},
UniformBlockInfo{3, true, true, sizeof(LineBasicPropertiesUBO), "LineBasicPropertiesUBO"},
};
const std::array<TextureInfo, 0> ShaderSource<BuiltIn::LineBasicShader, gfx::Backend::Type::Metal>::textures = {};

View File

@@ -12,6 +12,7 @@
#include <mbgl/util/logging.hpp>
#include <mbgl/util/string_indexer.hpp>
#include <Metal/MTLLibrary.hpp>
#include <Metal/MTLRenderPass.hpp>
#include <Metal/MTLRenderPipeline.hpp>
@@ -103,6 +104,8 @@ ShaderProgram::ShaderProgram(std::string name, RendererBackend& backend_, MTLFun
vertexFunction(std::move(vert)),
fragmentFunction(std::move(frag)) {}
ShaderProgram::~ShaderProgram() noexcept = default;
MTLRenderPipelineStatePtr ShaderProgram::getRenderPipelineState(const gfx::Renderable& renderable,
const MTLVertexDescriptorPtr& vertexDescriptor,
const gfx::ColorMode& colorMode) const {

View File

@@ -23,7 +23,7 @@ const std::array<UniformBlockInfo, 7> ShaderSource<BuiltIn::SymbolSDFIconShader,
{
UniformBlockInfo{10, true, true, sizeof(SymbolDrawableUBO), "SymbolDrawableUBO"},
UniformBlockInfo{11, true, true, sizeof(SymbolDynamicUBO), "SymbolDynamicUBO"},
UniformBlockInfo{12, true, false, sizeof(SymbolDrawablePaintUBO), "SymbolDrawablePaintUBO"},
UniformBlockInfo{12, true, true, sizeof(SymbolDrawablePaintUBO), "SymbolDrawablePaintUBO"},
UniformBlockInfo{13, true, true, sizeof(SymbolDrawableTilePropsUBO), "SymbolDrawableTilePropsUBO"},
UniformBlockInfo{14, true, false, sizeof(SymbolDrawableInterpolateUBO), "SymbolDrawableInterpolateUBO"},
UniformBlockInfo{15, true, true, sizeof(SymbolPermutationUBO), "SymbolPermutationUBO"},

View File

@@ -22,7 +22,7 @@ const std::array<UniformBlockInfo, 7>
ShaderSource<BuiltIn::SymbolTextAndIconShader, gfx::Backend::Type::Metal>::uniforms = {
UniformBlockInfo{9, true, true, sizeof(SymbolDrawableUBO), "SymbolDrawableUBO"},
UniformBlockInfo{10, true, true, sizeof(SymbolDynamicUBO), "SymbolDynamicUBO"},
UniformBlockInfo{11, true, false, sizeof(SymbolDrawablePaintUBO), "SymbolDrawablePaintUBO"},
UniformBlockInfo{11, true, true, sizeof(SymbolDrawablePaintUBO), "SymbolDrawablePaintUBO"},
UniformBlockInfo{12, true, true, sizeof(SymbolDrawableTilePropsUBO), "SymbolDrawableTilePropsUBO"},
UniformBlockInfo{13, true, false, sizeof(SymbolDrawableInterpolateUBO), "SymbolDrawableInterpolateUBO"},
UniformBlockInfo{14, true, true, sizeof(SymbolPermutationUBO), "SymbolPermutationUBO"},

View File

@@ -1,3 +1,5 @@
#if MLN_RENDER_BACKEND_OPENGL
#include <mbgl/test/util.hpp>
#include <mbgl/gfx/headless_frontend.hpp>
@@ -109,3 +111,5 @@ TEST(CustomLayer, Basic) {
test::checkImage("test/fixtures/custom_layer/basic", frontend.render(map).image, 0.0006, 0.1);
}
#endif

View File

@@ -1,3 +1,5 @@
#if MLN_RENDER_BACKEND_OPENGL
#include <mbgl/test/util.hpp>
#include <mbgl/test/stub_geometry_tile_feature.hpp>
@@ -380,3 +382,5 @@ TEST(Buckets, RasterBucketMaskComplex) {
expectedSegments.emplace_back(0, 0, 24, 36);
EXPECT_EQ(expectedSegments, bucket.segments);
}
#endif

View File

@@ -1,3 +1,4 @@
#if MLN_RENDER_BACKEND_OPENGL
#include <mbgl/test/util.hpp>
#include <mbgl/gfx/backend_scope.hpp>
@@ -122,3 +123,5 @@ TEST(GLContextMode, Shared) {
test::checkImage("test/fixtures/shared_context", frontend.render(map).image, 0.5, 0.1);
}
#endif

View File

@@ -1,3 +1,5 @@
#if MLN_RENDER_BACKEND_OPENGL
#include <mbgl/gfx/gfx_types.hpp>
#include <mbgl/gfx/types.hpp>
#include <mbgl/gl/defines.hpp>
@@ -176,3 +178,5 @@ TEST(GL, sizedFor) {
ASSERT_EQ(GL_INVALID_ENUM,
Enum<gfx::TexturePixelType>::sizedFor(TexturePixelType::RGBA, static_cast<TextureChannelDataType>(-1)));
}
#endif

View File

@@ -1,3 +1,5 @@
#if MLN_RENDER_BACKEND_OPENGL
#include <mbgl/test/util.hpp>
#include <mbgl/platform/gl_functions.hpp>
@@ -257,3 +259,5 @@ TEST(GLFunctions, OpenGLES) {
EXPECT_NE(glTexStorage3D, nullptr);
EXPECT_NE(glGetInternalformativ, nullptr);
}
#endif

View File

@@ -1,3 +1,4 @@
#if MLN_RENDER_BACKEND_OPENGL
#include <mbgl/test/util.hpp>
#include <mbgl/gfx/backend_scope.hpp>
@@ -66,3 +67,5 @@ TEST(GLObject, Store) {
context.reset();
EXPECT_TRUE(context.empty());
}
#endif

View File

@@ -1,3 +1,4 @@
#if MLN_RENDER_BACKEND_OPENGL
#include <mbgl/test/util.hpp>
#include <mbgl/gl/renderer_backend.hpp>
@@ -126,3 +127,4 @@ TEST(BackendScope, ChainedScopes) {
ASSERT_FALSE(activatedA);
ASSERT_FALSE(activatedB);
}
#endif

View File

@@ -9,6 +9,30 @@
#include <random>
#include <vector>
#if MLN_RENDER_BACKEND_METAL
#include <mbgl/shaders/mtl/background.hpp>
#include <mbgl/shaders/mtl/background_pattern.hpp>
#include <mbgl/shaders/mtl/circle.hpp>
#include <mbgl/shaders/mtl/clipping_mask.hpp>
#include <mbgl/shaders/mtl/collision_box.hpp>
#include <mbgl/shaders/mtl/collision_circle.hpp>
#include <mbgl/shaders/mtl/debug.hpp>
#include <mbgl/shaders/mtl/fill.hpp>
#include <mbgl/shaders/mtl/fill_extrusion.hpp>
#include <mbgl/shaders/mtl/fill_extrusion_pattern.hpp>
#include <mbgl/shaders/mtl/heatmap.hpp>
#include <mbgl/shaders/mtl/heatmap_texture.hpp>
#include <mbgl/shaders/mtl/hillshade.hpp>
#include <mbgl/shaders/mtl/hillshade_prepare.hpp>
#include <mbgl/shaders/mtl/line.hpp>
#include <mbgl/shaders/mtl/line_gradient.hpp>
#include <mbgl/shaders/mtl/fill.hpp>
#include <mbgl/shaders/mtl/raster.hpp>
#include <mbgl/shaders/mtl/symbol_icon.hpp>
#include <mbgl/shaders/mtl/symbol_sdf.hpp>
#include <mbgl/shaders/mtl/symbol_text_and_icon.hpp>
#endif
using namespace mbgl;
TEST(OrderIndependentHash, Permutations) {
@@ -18,8 +42,11 @@ TEST(OrderIndependentHash, Permutations) {
constexpr int iterations = 10;
// Use values up to this large
constexpr size_t maxVal = 10;
// Repeat all that with different random seeds
constexpr int seeds = 5;
std::seed_seq seed{0xf00dLL};
for (int curSeed = 0; curSeed < seeds; ++curSeed) {
std::seed_seq seed{0xf00dLL + curSeed};
std::default_random_engine engine(seed);
std::uniform_int_distribution<size_t> distribution(0, maxVal);
@@ -36,12 +63,6 @@ TEST(OrderIndependentHash, Permutations) {
size_t initialValue = 0;
do {
const auto curValue = util::order_independent_hash(values.begin(), values.end());
if (isFirst || curValue != initialValue) {
for (auto v : values) {
std::cout << v << ",";
}
std::cout << " - " << std::hex << curValue << std::endl;
}
if (isFirst) {
initialValue = curValue;
isFirst = false;
@@ -52,3 +73,87 @@ TEST(OrderIndependentHash, Permutations) {
}
}
}
}
#if MLN_RENDER_BACKEND_METAL
using namespace mbgl::shaders;
template <typename TSet, typename TIter = typename TSet::const_iterator, typename TFunc>
void each_subset(const TSet& sofar, TIter beg, TIter end, TFunc f) {
if (beg == end) {
f(sofar.cbegin(), sofar.cend());
} else {
TSet with = sofar;
with.insert(*beg);
each_subset<TSet, TIter>(with, std::next(beg), end, f);
each_subset<TSet, TIter>(sofar, std::next(beg), end, f);
}
}
/// Ensure that no combination of attributes used by a shader definition produce a hash conflict
template <typename ShaderType>
void checkShaderHashes() {
using AttribSet = mbgl::unordered_set<StringIdentity>;
AttribSet attributes;
for (const auto& attrib : ShaderType::attributes) {
attributes.insert(attrib.nameID);
}
std::set<std::size_t> subsetHashes;
each_subset(AttribSet{}, attributes.cbegin(), attributes.cend(), [&](auto beg, auto end) {
if (beg != end) {
std::vector<StringIdentity> subset(beg, end);
std::optional<std::size_t> firstHash;
do {
const auto hash = util::order_independent_hash(subset.begin(), subset.end());
if (firstHash) {
// All permutations of the subset must yield the same hash key as the first
EXPECT_EQ(*firstHash, hash);
} else {
firstHash.emplace(hash);
// All subset hashes must be unique
EXPECT_TRUE(subsetHashes.insert(hash).second);
}
} while (std::next_permutation(subset.begin(), subset.end()));
}
});
EXPECT_EQ(static_cast<size_t>(std::pow(2, attributes.size())), 1 + subsetHashes.size());
}
template <BuiltIn... type>
void checkShaderHashes() {
// For OpenGL, we would need to do reflection
//(checkShaderHashes<ShaderSource<type, gfx::Backend::Type::OpenGL>>(),...);
(checkShaderHashes<ShaderSource<type, gfx::Backend::Type::Metal>>(), ...);
}
TEST(OrderIndependentHash, Shaders) {
checkShaderHashes<BuiltIn::BackgroundShader,
BuiltIn::BackgroundPatternShader,
BuiltIn::CircleShader,
BuiltIn::CollisionBoxShader,
BuiltIn::CollisionCircleShader,
BuiltIn::DebugShader,
BuiltIn::FillShader,
BuiltIn::FillOutlineShader,
BuiltIn::LineGradientShader,
BuiltIn::LinePatternShader,
BuiltIn::LineSDFShader,
BuiltIn::LineShader,
BuiltIn::LineBasicShader,
BuiltIn::FillPatternShader,
BuiltIn::FillOutlinePatternShader,
BuiltIn::FillExtrusionShader,
BuiltIn::FillExtrusionPatternShader,
BuiltIn::HeatmapShader,
BuiltIn::HeatmapTextureShader,
BuiltIn::HillshadePrepareShader,
BuiltIn::HillshadeShader,
BuiltIn::RasterShader,
BuiltIn::SymbolIconShader,
BuiltIn::SymbolSDFIconShader,
BuiltIn::SymbolTextAndIconShader>();
}
#endif

View File

@@ -1,3 +1,4 @@
#if MLN_RENDER_BACKEND_OPENGL
#include <mbgl/test/util.hpp>
#include <mbgl/platform/gl_functions.hpp>
@@ -203,3 +204,5 @@ TEST(OffscreenTexture, ClearRenderPassColor) {
auto image = offscreenTexture->readStillImage();
test::checkImage("test/fixtures/offscreen_texture/clear-render-pass-color", image, 0, 0);
}
#endif