Metal permutations (#1903)
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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&&);
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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; }
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
)";
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
)";
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
)";
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
)";
|
||||
};
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
)";
|
||||
};
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
)";
|
||||
};
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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"},
|
||||
|
||||
@@ -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 = {};
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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"},
|
||||
|
||||
@@ -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"},
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user