Optimize fill extrusion memory by using instancing [Core optimization] (#4256)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Bart Louwers <bart@emeel.net> Co-authored-by: Adrian Cojocaru <adrian.cojocaru92@yahoo.com>
This commit is contained in:
@@ -94,7 +94,9 @@ MLN_GENERATED_OPENGL_SHADER_HEADERS = [
|
|||||||
"include/mbgl/shaders/gl/fill_outline_pattern.hpp",
|
"include/mbgl/shaders/gl/fill_outline_pattern.hpp",
|
||||||
"include/mbgl/shaders/gl/fill_outline_triangulated.hpp",
|
"include/mbgl/shaders/gl/fill_outline_triangulated.hpp",
|
||||||
"include/mbgl/shaders/gl/fill_extrusion.hpp",
|
"include/mbgl/shaders/gl/fill_extrusion.hpp",
|
||||||
|
"include/mbgl/shaders/gl/fill_extrusion_instanced.hpp",
|
||||||
"include/mbgl/shaders/gl/fill_extrusion_pattern.hpp",
|
"include/mbgl/shaders/gl/fill_extrusion_pattern.hpp",
|
||||||
|
"include/mbgl/shaders/gl/fill_extrusion_pattern_instanced.hpp",
|
||||||
"include/mbgl/shaders/gl/heatmap.hpp",
|
"include/mbgl/shaders/gl/heatmap.hpp",
|
||||||
"include/mbgl/shaders/gl/heatmap_texture.hpp",
|
"include/mbgl/shaders/gl/heatmap_texture.hpp",
|
||||||
"include/mbgl/shaders/gl/hillshade_prepare.hpp",
|
"include/mbgl/shaders/gl/hillshade_prepare.hpp",
|
||||||
|
|||||||
@@ -32,7 +32,9 @@ list(APPEND
|
|||||||
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/fill_outline_pattern.hpp
|
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/fill_outline_pattern.hpp
|
||||||
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/fill_outline_triangulated.hpp
|
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/fill_outline_triangulated.hpp
|
||||||
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/fill_extrusion.hpp
|
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/fill_extrusion.hpp
|
||||||
|
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/fill_extrusion_instanced.hpp
|
||||||
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/fill_extrusion_pattern.hpp
|
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/fill_extrusion_pattern.hpp
|
||||||
|
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/fill_extrusion_pattern_instanced.hpp
|
||||||
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/heatmap.hpp
|
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/heatmap.hpp
|
||||||
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/heatmap_texture.hpp
|
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/heatmap_texture.hpp
|
||||||
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/hillshade_prepare.hpp
|
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/gl/hillshade_prepare.hpp
|
||||||
|
|||||||
@@ -301,8 +301,8 @@ public:
|
|||||||
/// Sum of element strides, and the total size of a vertex in the buffer
|
/// Sum of element strides, and the total size of a vertex in the buffer
|
||||||
std::size_t getTotalSize() const;
|
std::size_t getTotalSize() const;
|
||||||
|
|
||||||
/// Get the largest count value of the attribute elements
|
/// Get the smallest count value of the attribute elements
|
||||||
std::size_t getMaxCount() const;
|
std::size_t getMinCount() const;
|
||||||
|
|
||||||
/// Get a attribute element.
|
/// Get a attribute element.
|
||||||
/// Returns a pointer to the element on success, or null if the attribute doesn't exists.
|
/// Returns a pointer to the element on success, or null if the attribute doesn't exists.
|
||||||
|
|||||||
16
include/mbgl/shaders/gl/fill_extrusion_instanced.hpp
Normal file
16
include/mbgl/shaders/gl/fill_extrusion_instanced.hpp
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
// Generated code, do not modify this file!
|
||||||
|
#pragma once
|
||||||
|
#include <mbgl/shaders/shader_source.hpp>
|
||||||
|
|
||||||
|
namespace mbgl {
|
||||||
|
namespace shaders {
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct ShaderSource<BuiltIn::FillExtrusionInstancedShader, gfx::Backend::Type::OpenGL> {
|
||||||
|
static constexpr const char* name = "FillExtrusionInstancedShader";
|
||||||
|
static constexpr const char* vertex = R"()";
|
||||||
|
static constexpr const char* fragment = R"()";
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace shaders
|
||||||
|
} // namespace mbgl
|
||||||
16
include/mbgl/shaders/gl/fill_extrusion_pattern_instanced.hpp
Normal file
16
include/mbgl/shaders/gl/fill_extrusion_pattern_instanced.hpp
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
// Generated code, do not modify this file!
|
||||||
|
#pragma once
|
||||||
|
#include <mbgl/shaders/shader_source.hpp>
|
||||||
|
|
||||||
|
namespace mbgl {
|
||||||
|
namespace shaders {
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct ShaderSource<BuiltIn::FillExtrusionPatternInstancedShader, gfx::Backend::Type::OpenGL> {
|
||||||
|
static constexpr const char* name = "FillExtrusionPatternInstancedShader";
|
||||||
|
static constexpr const char* vertex = R"()";
|
||||||
|
static constexpr const char* fragment = R"()";
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace shaders
|
||||||
|
} // namespace mbgl
|
||||||
@@ -78,6 +78,7 @@ enum {
|
|||||||
};
|
};
|
||||||
|
|
||||||
#define MLN_UBO_CONSOLIDATION (MLN_RENDER_BACKEND_METAL || MLN_RENDER_BACKEND_VULKAN || MLN_RENDER_BACKEND_WEBGPU)
|
#define MLN_UBO_CONSOLIDATION (MLN_RENDER_BACKEND_METAL || MLN_RENDER_BACKEND_VULKAN || MLN_RENDER_BACKEND_WEBGPU)
|
||||||
|
#define MLN_USE_FILL_EXTRUSION_INSTANCING (MLN_RENDER_BACKEND_METAL)
|
||||||
|
|
||||||
} // namespace shaders
|
} // namespace shaders
|
||||||
} // namespace mbgl
|
} // namespace mbgl
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ struct ShaderSource<BuiltIn::FillExtrusionShader, gfx::Backend::Type::Metal> {
|
|||||||
static constexpr auto vertexMainFunction = "vertexMain";
|
static constexpr auto vertexMainFunction = "vertexMain";
|
||||||
static constexpr auto fragmentMainFunction = "fragmentMain";
|
static constexpr auto fragmentMainFunction = "fragmentMain";
|
||||||
|
|
||||||
static const std::array<AttributeInfo, 5> attributes;
|
static const std::array<AttributeInfo, 4> attributes;
|
||||||
static constexpr std::array<AttributeInfo, 0> instanceAttributes{};
|
static constexpr std::array<AttributeInfo, 0> instanceAttributes{};
|
||||||
static const std::array<TextureInfo, 0> textures;
|
static const std::array<TextureInfo, 0> textures;
|
||||||
|
|
||||||
@@ -78,16 +78,15 @@ struct ShaderSource<BuiltIn::FillExtrusionShader, gfx::Backend::Type::Metal> {
|
|||||||
|
|
||||||
struct VertexStage {
|
struct VertexStage {
|
||||||
short2 pos [[attribute(0)]];
|
short2 pos [[attribute(0)]];
|
||||||
short4 normal_ed [[attribute(1)]];
|
|
||||||
|
|
||||||
#if !defined(HAS_UNIFORM_u_color)
|
#if !defined(HAS_UNIFORM_u_color)
|
||||||
float4 color [[attribute(2)]];
|
float4 color [[attribute(1)]];
|
||||||
#endif
|
#endif
|
||||||
#if !defined(HAS_UNIFORM_u_base)
|
#if !defined(HAS_UNIFORM_u_base)
|
||||||
float base [[attribute(3)]];
|
float base [[attribute(2)]];
|
||||||
#endif
|
#endif
|
||||||
#if !defined(HAS_UNIFORM_u_height)
|
#if !defined(HAS_UNIFORM_u_height)
|
||||||
float height [[attribute(4)]];
|
float height [[attribute(3)]];
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -119,8 +118,8 @@ FragmentStage vertex vertexMain(thread const VertexStage vertx [[stage_in]],
|
|||||||
const auto height = max(unpack_mix_float(vertx.height, drawable.height_t), 0.0);
|
const auto height = max(unpack_mix_float(vertx.height, drawable.height_t), 0.0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const float3 normal = float3(vertx.normal_ed.xyz);
|
const float3 normal = float3(0.0, 0.0, 1.0);
|
||||||
const float t = glMod(normal.x, 2.0);
|
const float t = 1.0;
|
||||||
const float z = (t != 0.0) ? height : base; // TODO: This would come out wrong on GL for negative values, check it...
|
const float z = (t != 0.0) ? height : base; // TODO: This would come out wrong on GL for negative values, check it...
|
||||||
const float4 position = drawable.matrix * float4(float2(vertx.pos), z, 1);
|
const float4 position = drawable.matrix * float4(float2(vertx.pos), z, 1);
|
||||||
|
|
||||||
@@ -146,7 +145,149 @@ FragmentStage vertex vertexMain(thread const VertexStage vertx [[stage_in]],
|
|||||||
color += min(float4(0.03, 0.03, 0.03, 1.0), float4(1.0));
|
color += min(float4(0.03, 0.03, 0.03, 1.0), float4(1.0));
|
||||||
|
|
||||||
// Calculate cos(theta), where theta is the angle between surface normal and diffuse light ray
|
// Calculate cos(theta), where theta is the angle between surface normal and diffuse light ray
|
||||||
const float directionalFraction = clamp(dot(normal / 16384.0, props.light_position_base.xyz), 0.0, 1.0);
|
const float directionalFraction = clamp(dot(normal, props.light_position_base.xyz), 0.0, 1.0);
|
||||||
|
|
||||||
|
// Adjust directional so that the range of values for highlight/shading is
|
||||||
|
// narrower with lower light intensity and with lighter/brighter surface colors
|
||||||
|
const float minDirectional = 1.0 - props.light_intensity;
|
||||||
|
const float maxDirectional = max(1.0 - luminance + props.light_intensity, 1.0);
|
||||||
|
float directional = mix(minDirectional, maxDirectional, directionalFraction);
|
||||||
|
|
||||||
|
// Add gradient along z axis of side surfaces
|
||||||
|
if (normal.y != 0.0) {
|
||||||
|
// This avoids another branching statement, but multiplies by a constant of 0.84 if no
|
||||||
|
// vertical gradient, and otherwise calculates the gradient based on base + height
|
||||||
|
// TODO: If we're optimizing to the level of avoiding branches, we should pre-compute
|
||||||
|
// the square root when height is a uniform.
|
||||||
|
const float fMin = mix(0.7, 0.98, 1.0 - props.light_intensity);
|
||||||
|
const float factor = clamp((t + base) * pow(height / 150.0, 0.5), fMin, 1.0);
|
||||||
|
directional *= (1.0 - props.vertical_gradient) + (props.vertical_gradient * factor);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assign final color based on surface + ambient light color, diffuse light directional,
|
||||||
|
// and light color with lower bounds adjusted to hue of light so that shading is tinted
|
||||||
|
// with the complementary (opposite) color to the light color
|
||||||
|
const float3 light_color = props.light_color_pad.rgb;
|
||||||
|
const float3 minLight = mix(0.0, 0.3, 1.0 - light_color.rgb);
|
||||||
|
vcolor += float4(clamp(color.rgb * directional * light_color.rgb, minLight, 1.0), 0.0);
|
||||||
|
|
||||||
|
return {
|
||||||
|
.position = position,
|
||||||
|
.color = half4(vcolor * props.opacity),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment FragmentOutput fragmentMain(FragmentStage in [[stage_in]]) {
|
||||||
|
return { in.color/*, in.position.z*/ };
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct ShaderSource<BuiltIn::FillExtrusionInstancedShader, gfx::Backend::Type::Metal> {
|
||||||
|
static constexpr auto name = "FillExtrusionInstancedShader";
|
||||||
|
static constexpr auto vertexMainFunction = "vertexMain";
|
||||||
|
static constexpr auto fragmentMainFunction = "fragmentMain";
|
||||||
|
|
||||||
|
static const std::array<AttributeInfo, 1> attributes;
|
||||||
|
static const std::array<AttributeInfo, 5> instanceAttributes;
|
||||||
|
static const std::array<TextureInfo, 0> textures;
|
||||||
|
|
||||||
|
static constexpr auto prelude = fillExtrusionShaderPrelude;
|
||||||
|
static constexpr auto source = R"(
|
||||||
|
|
||||||
|
struct VertexStage {
|
||||||
|
short2 pos [[attribute(0)]];
|
||||||
|
|
||||||
|
#if !defined(HAS_UNIFORM_u_color)
|
||||||
|
float4 color [[attribute(3)]];
|
||||||
|
#endif
|
||||||
|
#if !defined(HAS_UNIFORM_u_base)
|
||||||
|
float base [[attribute(4)]];
|
||||||
|
#endif
|
||||||
|
#if !defined(HAS_UNIFORM_u_height)
|
||||||
|
float height [[attribute(5)]];
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
struct OutlineInstance {
|
||||||
|
short2 pos;
|
||||||
|
ushort2 ed_discard;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FragmentStage {
|
||||||
|
float4 position [[position, invariant]];
|
||||||
|
half4 color;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FragmentOutput {
|
||||||
|
half4 color [[color(0)]];
|
||||||
|
//float depth [[depth(less)]]; // Write depth value if it's less than what's already there
|
||||||
|
};
|
||||||
|
|
||||||
|
FragmentStage vertex vertexMain(thread const VertexStage vertx [[stage_in]],
|
||||||
|
device const uint32_t& uboIndex [[buffer(idGlobalUBOIndex)]],
|
||||||
|
device const FillExtrusionDrawableUBO* drawableVector [[buffer(idFillExtrusionDrawableUBO)]],
|
||||||
|
device const FillExtrusionPropsUBO& props [[buffer(idFillExtrusionPropsUBO)]],
|
||||||
|
uint instanceID [[ instance_id ]],
|
||||||
|
device const OutlineInstance* outline [[buffer(fillExtrusionUBOCount + 1)]]) {
|
||||||
|
|
||||||
|
if (outline[instanceID].ed_discard.y) {
|
||||||
|
return {
|
||||||
|
.position = float4(0.0),
|
||||||
|
.color = half4(0.0),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
device const FillExtrusionDrawableUBO& drawable = drawableVector[uboIndex];
|
||||||
|
|
||||||
|
#if defined(HAS_UNIFORM_u_base)
|
||||||
|
const auto base = props.light_position_base.w;
|
||||||
|
#else
|
||||||
|
const auto base = max(unpack_mix_float(vertx.base, drawable.base_t), 0.0);
|
||||||
|
#endif
|
||||||
|
#if defined(HAS_UNIFORM_u_height)
|
||||||
|
const auto height = props.height;
|
||||||
|
#else
|
||||||
|
const auto height = max(unpack_mix_float(vertx.height, drawable.height_t), 0.0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
float2 p1 = float2(outline[instanceID + 1].pos);
|
||||||
|
float2 p2 = float2(outline[instanceID + 0].pos);
|
||||||
|
float2 perp = p1 - p2;
|
||||||
|
float magnitude = sqrt(perp.x * perp.x + perp.y * perp.y);
|
||||||
|
if (magnitude > 0) {
|
||||||
|
perp = perp / magnitude;
|
||||||
|
}
|
||||||
|
|
||||||
|
const float3 normal = float3(-perp.y, perp.x, 0.0);
|
||||||
|
const float t = float(vertx.pos.y);
|
||||||
|
const float z = (t != 0.0) ? height : base; // TODO: This would come out wrong on GL for negative values, check it...
|
||||||
|
const float4 position = drawable.matrix * float4(float2(outline[instanceID + vertx.pos.x].pos), z, 1);
|
||||||
|
|
||||||
|
#if defined(OVERDRAW_INSPECTOR)
|
||||||
|
return {
|
||||||
|
.position = position,
|
||||||
|
.color = half4(1.0),
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(HAS_UNIFORM_u_color)
|
||||||
|
auto color = props.color;
|
||||||
|
#else
|
||||||
|
auto color = unpack_mix_color(vertx.color, drawable.color_t);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Relative luminance (how dark/bright is the surface color?)
|
||||||
|
const float luminance = color.r * 0.2126 + color.g * 0.7152 + color.b * 0.0722;
|
||||||
|
|
||||||
|
float4 vcolor = float4(0.0, 0.0, 0.0, 1.0);
|
||||||
|
|
||||||
|
// Add slight ambient lighting so no extrusions are totally black
|
||||||
|
color += min(float4(0.03, 0.03, 0.03, 1.0), float4(1.0));
|
||||||
|
|
||||||
|
// Calculate cos(theta), where theta is the angle between surface normal and diffuse light ray
|
||||||
|
const float directionalFraction = clamp(dot(normal, props.light_position_base.xyz), 0.0, 1.0);
|
||||||
|
|
||||||
// Adjust directional so that the range of values for highlight/shading is
|
// Adjust directional so that the range of values for highlight/shading is
|
||||||
// narrower with lower light intensity and with lighter/brighter surface colors
|
// narrower with lower light intensity and with lighter/brighter surface colors
|
||||||
@@ -190,7 +331,7 @@ struct ShaderSource<BuiltIn::FillExtrusionPatternShader, gfx::Backend::Type::Met
|
|||||||
static constexpr auto vertexMainFunction = "vertexMain";
|
static constexpr auto vertexMainFunction = "vertexMain";
|
||||||
static constexpr auto fragmentMainFunction = "fragmentMain";
|
static constexpr auto fragmentMainFunction = "fragmentMain";
|
||||||
|
|
||||||
static const std::array<AttributeInfo, 6> attributes;
|
static const std::array<AttributeInfo, 5> attributes;
|
||||||
static constexpr std::array<AttributeInfo, 0> instanceAttributes{};
|
static constexpr std::array<AttributeInfo, 0> instanceAttributes{};
|
||||||
static const std::array<TextureInfo, 1> textures;
|
static const std::array<TextureInfo, 1> textures;
|
||||||
|
|
||||||
@@ -199,19 +340,18 @@ struct ShaderSource<BuiltIn::FillExtrusionPatternShader, gfx::Backend::Type::Met
|
|||||||
|
|
||||||
struct VertexStage {
|
struct VertexStage {
|
||||||
short2 pos [[attribute(0)]];
|
short2 pos [[attribute(0)]];
|
||||||
short4 normal_ed [[attribute(1)]];
|
|
||||||
|
|
||||||
#if !defined(HAS_UNIFORM_u_base)
|
#if !defined(HAS_UNIFORM_u_base)
|
||||||
float base [[attribute(2)]];
|
float base [[attribute(1)]];
|
||||||
#endif
|
#endif
|
||||||
#if !defined(HAS_UNIFORM_u_height)
|
#if !defined(HAS_UNIFORM_u_height)
|
||||||
float height [[attribute(3)]];
|
float height [[attribute(2)]];
|
||||||
#endif
|
#endif
|
||||||
#if !defined(HAS_UNIFORM_u_pattern_from)
|
#if !defined(HAS_UNIFORM_u_pattern_from)
|
||||||
ushort4 pattern_from [[attribute(4)]];
|
ushort4 pattern_from [[attribute(3)]];
|
||||||
#endif
|
#endif
|
||||||
#if !defined(HAS_UNIFORM_u_pattern_to)
|
#if !defined(HAS_UNIFORM_u_pattern_to)
|
||||||
ushort4 pattern_to [[attribute(5)]];
|
ushort4 pattern_to [[attribute(4)]];
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -255,9 +395,8 @@ FragmentStage vertex vertexMain(thread const VertexStage vertx [[stage_in]],
|
|||||||
const auto height = max(unpack_mix_float(vertx.height, drawable.height_t), 0.0);
|
const auto height = max(unpack_mix_float(vertx.height, drawable.height_t), 0.0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const float3 normal = float3(vertx.normal_ed.xyz);
|
const float3 normal = float3(0.0, 0.0, 1.0);
|
||||||
const float edgedistance = vertx.normal_ed.w;
|
const float t = 1.0;
|
||||||
const float t = glMod(normal.x, 2.0);
|
|
||||||
const float z = (t != 0.0) ? height : base; // TODO: This would come out wrong on GL for negative values, check it...
|
const float z = (t != 0.0) ? height : base; // TODO: This would come out wrong on GL for negative values, check it...
|
||||||
const float4 position = drawable.matrix * float4(float2(vertx.pos), z, 1);
|
const float4 position = drawable.matrix * float4(float2(vertx.pos), z, 1);
|
||||||
|
|
||||||
@@ -296,12 +435,10 @@ FragmentStage vertex vertexMain(thread const VertexStage vertx [[stage_in]],
|
|||||||
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_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 display_size_b = float2((pattern_br_b.x - pattern_tl_b.x) / pixelRatio, (pattern_br_b.y - pattern_tl_b.y) / pixelRatio);
|
||||||
|
|
||||||
const float2 pos = normal.x == 1.0 && normal.y == 0.0 && normal.z == 16384.0
|
const float2 pos = float2(vertx.pos); // extrusion top
|
||||||
? float2(vertx.pos) // extrusion top
|
|
||||||
: float2(edgedistance, z * drawable.height_factor); // extrusion side
|
|
||||||
|
|
||||||
float4 lighting = float4(0.0, 0.0, 0.0, 1.0);
|
float4 lighting = float4(0.0, 0.0, 0.0, 1.0);
|
||||||
float directional = clamp(dot(normal / 16383.0, props.light_position_base.xyz), 0.0, 1.0);
|
float directional = clamp(dot(normal, props.light_position_base.xyz), 0.0, 1.0);
|
||||||
directional = mix((1.0 - props.light_intensity), max((0.5 + props.light_intensity), 1.0), directional);
|
directional = mix((1.0 - props.light_intensity), max((0.5 + props.light_intensity), 1.0), directional);
|
||||||
|
|
||||||
if (normal.y != 0.0) {
|
if (normal.y != 0.0) {
|
||||||
@@ -370,5 +507,225 @@ fragment FragmentOutput fragmentMain(FragmentStage in [[stage_in]],
|
|||||||
)";
|
)";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct ShaderSource<BuiltIn::FillExtrusionPatternInstancedShader, gfx::Backend::Type::Metal> {
|
||||||
|
static constexpr auto name = "FillExtrusionPatternInstancedShader";
|
||||||
|
static constexpr auto vertexMainFunction = "vertexMain";
|
||||||
|
static constexpr auto fragmentMainFunction = "fragmentMain";
|
||||||
|
|
||||||
|
static const std::array<AttributeInfo, 1> attributes;
|
||||||
|
static const std::array<AttributeInfo, 6> instanceAttributes;
|
||||||
|
static const std::array<TextureInfo, 1> textures;
|
||||||
|
|
||||||
|
static constexpr auto prelude = fillExtrusionShaderPrelude;
|
||||||
|
static constexpr auto source = R"(
|
||||||
|
|
||||||
|
struct VertexStage {
|
||||||
|
short2 pos [[attribute(0)]];
|
||||||
|
|
||||||
|
#if !defined(HAS_UNIFORM_u_base)
|
||||||
|
float base [[attribute(3)]];
|
||||||
|
#endif
|
||||||
|
#if !defined(HAS_UNIFORM_u_height)
|
||||||
|
float height [[attribute(4)]];
|
||||||
|
#endif
|
||||||
|
#if !defined(HAS_UNIFORM_u_pattern_from)
|
||||||
|
ushort4 pattern_from [[attribute(5)]];
|
||||||
|
#endif
|
||||||
|
#if !defined(HAS_UNIFORM_u_pattern_to)
|
||||||
|
ushort4 pattern_to [[attribute(6)]];
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
struct OutlineInstance {
|
||||||
|
short2 pos;
|
||||||
|
ushort2 ed_discard;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FragmentStage {
|
||||||
|
float4 position [[position, invariant]];
|
||||||
|
float4 lighting;
|
||||||
|
float2 pos_a;
|
||||||
|
float2 pos_b;
|
||||||
|
|
||||||
|
#if !defined(HAS_UNIFORM_u_pattern_from)
|
||||||
|
half4 pattern_from;
|
||||||
|
#endif
|
||||||
|
#if !defined(HAS_UNIFORM_u_pattern_to)
|
||||||
|
half4 pattern_to;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FragmentOutput {
|
||||||
|
half4 color [[color(0)]];
|
||||||
|
//float depth [[depth(less)]]; // Write depth value if it's less than what's already there
|
||||||
|
};
|
||||||
|
|
||||||
|
FragmentStage vertex vertexMain(thread const VertexStage vertx [[stage_in]],
|
||||||
|
device const GlobalPaintParamsUBO& paintParams [[buffer(idGlobalPaintParamsUBO)]],
|
||||||
|
device const uint32_t& uboIndex [[buffer(idGlobalUBOIndex)]],
|
||||||
|
device const FillExtrusionDrawableUBO* drawableVector [[buffer(idFillExtrusionDrawableUBO)]],
|
||||||
|
device const FillExtrusionTilePropsUBO* tilePropsVector [[buffer(idFillExtrusionTilePropsUBO)]],
|
||||||
|
device const FillExtrusionPropsUBO& props [[buffer(idFillExtrusionPropsUBO)]],
|
||||||
|
uint instanceID [[ instance_id ]],
|
||||||
|
device const OutlineInstance* outline [[buffer(fillExtrusionUBOCount + 1)]]) {
|
||||||
|
|
||||||
|
if (outline[instanceID].ed_discard.y) {
|
||||||
|
return {
|
||||||
|
.position = float4(0.0),
|
||||||
|
.lighting = float4(0.0),
|
||||||
|
.pos_a = float2(0.0),
|
||||||
|
.pos_b = float2(0.0),
|
||||||
|
|
||||||
|
#if !defined(HAS_UNIFORM_u_pattern_from)
|
||||||
|
.pattern_from = half4(0.0),
|
||||||
|
#endif
|
||||||
|
#if !defined(HAS_UNIFORM_u_pattern_to)
|
||||||
|
.pattern_to = half4(0.0),
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
device const FillExtrusionDrawableUBO& drawable = drawableVector[uboIndex];
|
||||||
|
device const FillExtrusionTilePropsUBO& tileProps = tilePropsVector[uboIndex];
|
||||||
|
|
||||||
|
#if defined(HAS_UNIFORM_u_base)
|
||||||
|
const auto base = props.light_position_base.w;
|
||||||
|
#else
|
||||||
|
const auto base = max(unpack_mix_float(vertx.base, drawable.base_t), 0.0);
|
||||||
|
#endif
|
||||||
|
#if defined(HAS_UNIFORM_u_height)
|
||||||
|
const auto height = props.height;
|
||||||
|
#else
|
||||||
|
const auto height = max(unpack_mix_float(vertx.height, drawable.height_t), 0.0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
float2 p1 = float2(outline[instanceID + 1].pos);
|
||||||
|
float2 p2 = float2(outline[instanceID + 0].pos);
|
||||||
|
float2 perp = p1 - p2;
|
||||||
|
float magnitude = sqrt(perp.x * perp.x + perp.y * perp.y);
|
||||||
|
if (magnitude > 0) {
|
||||||
|
perp = perp / magnitude;
|
||||||
|
}
|
||||||
|
|
||||||
|
const float3 normal = float3(-perp.y, perp.x, 0.0);
|
||||||
|
const float edgedistance = outline[instanceID + 1 - vertx.pos.x].ed_discard.x;
|
||||||
|
const float t = float(vertx.pos.y);
|
||||||
|
const float z = (t != 0.0) ? height : base; // TODO: This would come out wrong on GL for negative values, check it...
|
||||||
|
const float4 position = drawable.matrix * float4(float2(outline[instanceID + vertx.pos.x].pos), z, 1);
|
||||||
|
|
||||||
|
#if defined(OVERDRAW_INSPECTOR)
|
||||||
|
return {
|
||||||
|
.position = position,
|
||||||
|
.lighting = float4(1.0),
|
||||||
|
.pos_a = float2(1.0),
|
||||||
|
.pos_b = float2(1.0),
|
||||||
|
|
||||||
|
#if !defined(HAS_UNIFORM_u_pattern_from)
|
||||||
|
.pattern_from = half4(1.0),
|
||||||
|
#endif
|
||||||
|
#if !defined(HAS_UNIFORM_u_pattern_to)
|
||||||
|
.pattern_to = half4(1.0),
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(HAS_UNIFORM_u_pattern_from)
|
||||||
|
const auto pattern_from = tileProps.pattern_from;
|
||||||
|
#else
|
||||||
|
const auto pattern_from = float4(vertx.pattern_from);
|
||||||
|
#endif
|
||||||
|
#if defined(HAS_UNIFORM_u_pattern_to)
|
||||||
|
const auto pattern_to = tileProps.pattern_to;
|
||||||
|
#else
|
||||||
|
const auto pattern_to = float4(vertx.pattern_to);
|
||||||
|
#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 float pixelRatio = paintParams.pixel_ratio;
|
||||||
|
const float tileZoomRatio = drawable.tile_ratio;
|
||||||
|
const float fromScale = props.from_scale;
|
||||||
|
const float toScale = props.to_scale;
|
||||||
|
|
||||||
|
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 pos = float2(edgedistance, z * drawable.height_factor); // extrusion side
|
||||||
|
|
||||||
|
float4 lighting = float4(0.0, 0.0, 0.0, 1.0);
|
||||||
|
float directional = clamp(dot(normal, props.light_position_base.xyz), 0.0, 1.0);
|
||||||
|
directional = mix((1.0 - props.light_intensity), max((0.5 + props.light_intensity), 1.0), directional);
|
||||||
|
|
||||||
|
if (normal.y != 0.0) {
|
||||||
|
// This avoids another branching statement, but multiplies by a constant of 0.84 if no vertical gradient,
|
||||||
|
// and otherwise calculates the gradient based on base + height
|
||||||
|
directional *= (
|
||||||
|
(1.0 - props.vertical_gradient) +
|
||||||
|
(props.vertical_gradient * clamp((t + base) * pow(height / 150.0, 0.5), mix(0.7, 0.98, 1.0 - props.light_intensity), 1.0)));
|
||||||
|
}
|
||||||
|
|
||||||
|
lighting.rgb += clamp(directional * props.light_color_pad.rgb, mix(float3(0.0), float3(0.3), 1.0 - props.light_color_pad.rgb), float3(1.0));
|
||||||
|
lighting *= props.opacity;
|
||||||
|
|
||||||
|
return {
|
||||||
|
.position = position,
|
||||||
|
.lighting = lighting,
|
||||||
|
.pos_a = get_pattern_pos(drawable.pixel_coord_upper, drawable.pixel_coord_lower, fromScale * display_size_a, tileZoomRatio, pos),
|
||||||
|
.pos_b = get_pattern_pos(drawable.pixel_coord_upper, drawable.pixel_coord_lower, toScale * display_size_b, tileZoomRatio, pos),
|
||||||
|
|
||||||
|
#if !defined(HAS_UNIFORM_u_pattern_from)
|
||||||
|
.pattern_from = half4(pattern_from),
|
||||||
|
#endif
|
||||||
|
#if !defined(HAS_UNIFORM_u_pattern_to)
|
||||||
|
.pattern_to = half4(pattern_to),
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment FragmentOutput fragmentMain(FragmentStage in [[stage_in]],
|
||||||
|
device const uint32_t& uboIndex [[buffer(idGlobalUBOIndex)]],
|
||||||
|
device const FillExtrusionTilePropsUBO* tilePropsVector [[buffer(idFillExtrusionTilePropsUBO)]],
|
||||||
|
device const FillExtrusionPropsUBO& props [[buffer(idFillExtrusionPropsUBO)]],
|
||||||
|
texture2d<float, access::sample> image0 [[texture(0)]],
|
||||||
|
sampler image0_sampler [[sampler(0)]]) {
|
||||||
|
#if defined(OVERDRAW_INSPECTOR)
|
||||||
|
return {half4(1.0)/*, in.position.z*/};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
device const FillExtrusionTilePropsUBO& tileProps = tilePropsVector[uboIndex];
|
||||||
|
|
||||||
|
#if defined(HAS_UNIFORM_u_pattern_from)
|
||||||
|
const auto pattern_from = float4(tileProps.pattern_from);
|
||||||
|
#else
|
||||||
|
const auto pattern_from = float4(in.pattern_from);
|
||||||
|
#endif
|
||||||
|
#if defined(HAS_UNIFORM_u_pattern_to)
|
||||||
|
const auto pattern_to = float4(tileProps.pattern_to);
|
||||||
|
#else
|
||||||
|
const auto pattern_to = float4(in.pattern_to);
|
||||||
|
#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.pos_a, 1.0);
|
||||||
|
const float2 pos = mix(pattern_tl_a / tileProps.texsize, pattern_br_a / tileProps.texsize, imagecoord);
|
||||||
|
const float4 color1 = image0.sample(image0_sampler, pos);
|
||||||
|
|
||||||
|
const float2 imagecoord_b = glMod(in.pos_b, 1.0);
|
||||||
|
const float2 pos2 = mix(pattern_tl_b / tileProps.texsize, pattern_br_b / tileProps.texsize, imagecoord_b);
|
||||||
|
const float4 color2 = image0.sample(image0_sampler, pos2);
|
||||||
|
|
||||||
|
return {half4(mix(color1, color2, props.fade) * in.lighting)/*, in.position.z*/};
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace shaders
|
} // namespace shaders
|
||||||
} // namespace mbgl
|
} // namespace mbgl
|
||||||
|
|||||||
@@ -77,11 +77,13 @@ public:
|
|||||||
using ShaderClass = shaders::ShaderSource<ShaderID, gfx::Backend::Type::Metal>;
|
using ShaderClass = shaders::ShaderSource<ShaderID, gfx::Backend::Type::Metal>;
|
||||||
for (const auto& attrib : ShaderClass::attributes) {
|
for (const auto& attrib : ShaderClass::attributes) {
|
||||||
if (!propertiesAsUniforms.second.count(attrib.id)) {
|
if (!propertiesAsUniforms.second.count(attrib.id)) {
|
||||||
shader->initAttribute(attrib);
|
shader->initVertexAttribute(attrib);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const auto& attrib : ShaderClass::instanceAttributes) {
|
for (const auto& attrib : ShaderClass::instanceAttributes) {
|
||||||
shader->initInstanceAttribute(attrib);
|
if (!propertiesAsUniforms.second.count(attrib.id)) {
|
||||||
|
shader->initInstanceAttribute(attrib);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for (const auto& texture : ShaderClass::textures) {
|
for (const auto& texture : ShaderClass::textures) {
|
||||||
shader->initTexture(texture);
|
shader->initTexture(texture);
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ public:
|
|||||||
|
|
||||||
const gfx::VertexAttributeArray& getInstanceAttributes() const override { return instanceAttributes; }
|
const gfx::VertexAttributeArray& getInstanceAttributes() const override { return instanceAttributes; }
|
||||||
|
|
||||||
void initAttribute(const shaders::AttributeInfo&);
|
void initVertexAttribute(const shaders::AttributeInfo&);
|
||||||
void initInstanceAttribute(const shaders::AttributeInfo&);
|
void initInstanceAttribute(const shaders::AttributeInfo&);
|
||||||
void initTexture(const shaders::TextureInfo&);
|
void initTexture(const shaders::TextureInfo&);
|
||||||
|
|
||||||
|
|||||||
@@ -422,7 +422,13 @@ enum {
|
|||||||
|
|
||||||
enum {
|
enum {
|
||||||
idFillExtrusionPosVertexAttribute,
|
idFillExtrusionPosVertexAttribute,
|
||||||
|
|
||||||
|
#if MLN_USE_FILL_EXTRUSION_INSTANCING
|
||||||
|
idFillExtrusionOutlinePosAttribute,
|
||||||
|
idFillExtrusionEdDiscardAttribute,
|
||||||
|
#else
|
||||||
idFillExtrusionNormalEdVertexAttribute,
|
idFillExtrusionNormalEdVertexAttribute,
|
||||||
|
#endif
|
||||||
|
|
||||||
// Data driven
|
// Data driven
|
||||||
idFillExtrusionBaseVertexAttribute,
|
idFillExtrusionBaseVertexAttribute,
|
||||||
|
|||||||
@@ -19,7 +19,9 @@
|
|||||||
#include <mbgl/shaders/gl/fill_outline_pattern.hpp>
|
#include <mbgl/shaders/gl/fill_outline_pattern.hpp>
|
||||||
#include <mbgl/shaders/gl/fill_outline_triangulated.hpp>
|
#include <mbgl/shaders/gl/fill_outline_triangulated.hpp>
|
||||||
#include <mbgl/shaders/gl/fill_extrusion.hpp>
|
#include <mbgl/shaders/gl/fill_extrusion.hpp>
|
||||||
|
#include <mbgl/shaders/gl/fill_extrusion_instanced.hpp>
|
||||||
#include <mbgl/shaders/gl/fill_extrusion_pattern.hpp>
|
#include <mbgl/shaders/gl/fill_extrusion_pattern.hpp>
|
||||||
|
#include <mbgl/shaders/gl/fill_extrusion_pattern_instanced.hpp>
|
||||||
#include <mbgl/shaders/gl/heatmap.hpp>
|
#include <mbgl/shaders/gl/heatmap.hpp>
|
||||||
#include <mbgl/shaders/gl/heatmap_texture.hpp>
|
#include <mbgl/shaders/gl/heatmap_texture.hpp>
|
||||||
#include <mbgl/shaders/gl/hillshade_prepare.hpp>
|
#include <mbgl/shaders/gl/hillshade_prepare.hpp>
|
||||||
|
|||||||
@@ -25,7 +25,9 @@ enum class BuiltIn {
|
|||||||
FillOutlinePatternShader,
|
FillOutlinePatternShader,
|
||||||
FillOutlineTriangulatedShader,
|
FillOutlineTriangulatedShader,
|
||||||
FillExtrusionShader,
|
FillExtrusionShader,
|
||||||
|
FillExtrusionInstancedShader,
|
||||||
FillExtrusionPatternShader,
|
FillExtrusionPatternShader,
|
||||||
|
FillExtrusionPatternInstancedShader,
|
||||||
HeatmapShader,
|
HeatmapShader,
|
||||||
HeatmapTextureShader,
|
HeatmapTextureShader,
|
||||||
HillshadePrepareShader,
|
HillshadePrepareShader,
|
||||||
|
|||||||
@@ -109,6 +109,13 @@
|
|||||||
"glsl_frag": "fill_extrusion.fragment.glsl",
|
"glsl_frag": "fill_extrusion.fragment.glsl",
|
||||||
"uses_ubos": true
|
"uses_ubos": true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "FillExtrusionInstancedShader",
|
||||||
|
"header": "fill_extrusion_instanced",
|
||||||
|
"glsl_vert": "_empty.glsl",
|
||||||
|
"glsl_frag": "_empty.glsl",
|
||||||
|
"uses_ubos": true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "FillExtrusionPatternShader",
|
"name": "FillExtrusionPatternShader",
|
||||||
"header": "fill_extrusion_pattern",
|
"header": "fill_extrusion_pattern",
|
||||||
@@ -116,6 +123,13 @@
|
|||||||
"glsl_frag": "fill_extrusion_pattern.fragment.glsl",
|
"glsl_frag": "fill_extrusion_pattern.fragment.glsl",
|
||||||
"uses_ubos": true
|
"uses_ubos": true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "FillExtrusionPatternInstancedShader",
|
||||||
|
"header": "fill_extrusion_pattern_instanced",
|
||||||
|
"glsl_vert": "_empty.glsl",
|
||||||
|
"glsl_frag": "_empty.glsl",
|
||||||
|
"uses_ubos": true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "HeatmapShader",
|
"name": "HeatmapShader",
|
||||||
"header": "heatmap",
|
"header": "heatmap",
|
||||||
|
|||||||
@@ -115,10 +115,11 @@ std::size_t VertexAttributeArray::getTotalSize() const {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t VertexAttributeArray::getMaxCount() const {
|
std::size_t VertexAttributeArray::getMinCount() const {
|
||||||
return std::accumulate(attrs.begin(), attrs.end(), std::size_t(0), [](const auto acc, const auto& attr) {
|
return std::accumulate(
|
||||||
return std::max(acc, (attr ? attr->getCount() : 0));
|
attrs.begin(), attrs.end(), std::numeric_limits<std::size_t>::max(), [](const auto acc, const auto& attr) {
|
||||||
});
|
return std::min(acc, (attr ? attr->getCount() : std::numeric_limits<std::size_t>::max()));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void VertexAttributeArray::clear() {
|
void VertexAttributeArray::clear() {
|
||||||
|
|||||||
@@ -279,7 +279,7 @@ void Drawable::draw(PaintParameters& parameters) const {
|
|||||||
const auto primitiveType = getPrimitiveType(mode.type);
|
const auto primitiveType = getPrimitiveType(mode.type);
|
||||||
constexpr auto indexType = MTL::IndexType::IndexTypeUInt16;
|
constexpr auto indexType = MTL::IndexType::IndexTypeUInt16;
|
||||||
constexpr auto indexSize = sizeof(std::uint16_t);
|
constexpr auto indexSize = sizeof(std::uint16_t);
|
||||||
const NS::UInteger instanceCount = instanceAttributes ? instanceAttributes->getMaxCount() : 1;
|
const NS::UInteger instanceCount = instanceAttributes ? instanceAttributes->getMinCount() : 1;
|
||||||
constexpr NS::UInteger baseInstance = 0;
|
constexpr NS::UInteger baseInstance = 0;
|
||||||
const NS::UInteger indexOffset = static_cast<NS::UInteger>(indexSize *
|
const NS::UInteger indexOffset = static_cast<NS::UInteger>(indexSize *
|
||||||
mlSegment.indexOffset); // in bytes, not indexes
|
mlSegment.indexOffset); // in bytes, not indexes
|
||||||
@@ -549,10 +549,12 @@ void Drawable::upload(gfx::UploadPass& uploadPass_) {
|
|||||||
impl->indexes->setDirty(false);
|
impl->indexes->setDirty(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool buildAttribs = !impl->vertexDesc || !vertexAttributes || !attributeUpdateTime ||
|
const bool buildVertexAttribs = !impl->vertexDesc || !vertexAttributes || !attributeUpdateTime ||
|
||||||
vertexAttributes->isModifiedAfter(*attributeUpdateTime);
|
vertexAttributes->isModifiedAfter(*attributeUpdateTime);
|
||||||
|
const bool buildInstanceAttribs = instanceAttributes && (!attributeUpdateTime ||
|
||||||
|
instanceAttributes->isModifiedAfter(*attributeUpdateTime));
|
||||||
|
|
||||||
if (buildAttribs) {
|
if (buildVertexAttribs || buildInstanceAttribs) {
|
||||||
#if !defined(NDEBUG)
|
#if !defined(NDEBUG)
|
||||||
const auto debugGroup = uploadPass.createDebugGroup(debugLabel(*this));
|
const auto debugGroup = uploadPass.createDebugGroup(debugLabel(*this));
|
||||||
#endif
|
#endif
|
||||||
@@ -575,8 +577,27 @@ void Drawable::upload(gfx::UploadPass& uploadPass_) {
|
|||||||
|
|
||||||
vertexAttributes->visitAttributes([](gfx::VertexAttribute& attrib) { attrib.setDirty(false); });
|
vertexAttributes->visitAttributes([](gfx::VertexAttribute& attrib) { attrib.setDirty(false); });
|
||||||
|
|
||||||
if (impl->attributeBindings != attributeBindings_) {
|
// Build instance attribute buffers
|
||||||
|
gfx::AttributeBindingArray instanceBindings_;
|
||||||
|
if (instanceAttributes) {
|
||||||
|
std::vector<std::unique_ptr<gfx::VertexBufferResource>> instanceBuffers;
|
||||||
|
instanceBindings_ = uploadPass.buildAttributeBindings(instanceAttributes->getMinCount(),
|
||||||
|
/*vertexType*/ gfx::AttributeDataType::Byte,
|
||||||
|
/*vertexAttributeIndex=*/-1,
|
||||||
|
/*vertexData=*/{},
|
||||||
|
shader->getInstanceAttributes(),
|
||||||
|
*instanceAttributes,
|
||||||
|
usage,
|
||||||
|
attributeUpdateTime,
|
||||||
|
instanceBuffers);
|
||||||
|
|
||||||
|
// clear dirty flag
|
||||||
|
instanceAttributes->visitAttributes([](gfx::VertexAttribute& attrib) { attrib.setDirty(false); });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (impl->attributeBindings != attributeBindings_ || impl->instanceBindings != instanceBindings_) {
|
||||||
impl->attributeBindings = std::move(attributeBindings_);
|
impl->attributeBindings = std::move(attributeBindings_);
|
||||||
|
impl->instanceBindings = std::move(instanceBindings_);
|
||||||
|
|
||||||
// hash
|
// hash
|
||||||
std::size_t hash{0};
|
std::size_t hash{0};
|
||||||
@@ -584,46 +605,52 @@ void Drawable::upload(gfx::UploadPass& uploadPass_) {
|
|||||||
// Create a layout descriptor for each attribute
|
// Create a layout descriptor for each attribute
|
||||||
auto vertDesc = NS::RetainPtr(MTL::VertexDescriptor::vertexDescriptor());
|
auto vertDesc = NS::RetainPtr(MTL::VertexDescriptor::vertexDescriptor());
|
||||||
|
|
||||||
NS::UInteger index = 0;
|
const auto applyBindings = [&](const gfx::AttributeBindingArray& attributeBindings,
|
||||||
for (auto& binding : impl->attributeBindings) {
|
MTL::VertexStepFunction stepFunction) {
|
||||||
if (!binding) {
|
NS::UInteger index = 0;
|
||||||
assert("Missing attribute binding");
|
for (auto& binding : attributeBindings) {
|
||||||
index += 1;
|
if (!binding) {
|
||||||
continue;
|
assert("Missing attribute binding");
|
||||||
}
|
index += 1;
|
||||||
|
continue;
|
||||||
if (!binding->vertexBufferResource && !impl->noBindingBuffer) {
|
|
||||||
if (const auto& buf = context.getEmptyVertexBuffer()) {
|
|
||||||
impl->noBindingBuffer = buf.get();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!binding->vertexBufferResource && !impl->noBindingBuffer) {
|
||||||
|
if (const auto& buf = context.getEmptyVertexBuffer()) {
|
||||||
|
impl->noBindingBuffer = buf.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& attribDesc = vertDesc->attributes()->object(index);
|
||||||
|
attribDesc->setBufferIndex(binding->bufferIndex);
|
||||||
|
attribDesc->setOffset(static_cast<NS::UInteger>(binding->attribute.offset));
|
||||||
|
attribDesc->setFormat(mtlVertexTypeOf(binding->attribute.dataType));
|
||||||
|
|
||||||
|
const auto& layoutDesc = vertDesc->layouts()->object(binding->bufferIndex);
|
||||||
|
if (!layoutDesc->stride()) {
|
||||||
|
assert(binding->vertexStride > 0);
|
||||||
|
layoutDesc->setStride(static_cast<NS::UInteger>(binding->vertexStride));
|
||||||
|
layoutDesc->setStepFunction(binding->vertexBufferResource ? stepFunction
|
||||||
|
: MTL::VertexStepFunctionConstant);
|
||||||
|
layoutDesc->setStepRate(binding->vertexBufferResource ? 1 : 0);
|
||||||
|
} else {
|
||||||
|
assert(layoutDesc->stride() == static_cast<NS::UInteger>(binding->vertexStride));
|
||||||
|
assert(layoutDesc->stepRate() == (binding->vertexBufferResource ? 1 : 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
mbgl::util::hash_combine(hash,
|
||||||
|
mbgl::util::hash(index,
|
||||||
|
binding->attribute.offset,
|
||||||
|
binding->attribute.dataType,
|
||||||
|
binding->vertexStride,
|
||||||
|
static_cast<bool>(binding->vertexBufferResource)));
|
||||||
|
|
||||||
|
index += 1;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const auto& attribDesc = vertDesc->attributes()->object(index);
|
applyBindings(impl->attributeBindings, MTL::VertexStepFunctionPerVertex);
|
||||||
attribDesc->setBufferIndex(binding->bufferIndex);
|
applyBindings(impl->instanceBindings, MTL::VertexStepFunctionPerInstance);
|
||||||
attribDesc->setOffset(static_cast<NS::UInteger>(binding->attribute.offset));
|
|
||||||
attribDesc->setFormat(mtlVertexTypeOf(binding->attribute.dataType));
|
|
||||||
|
|
||||||
const auto& layoutDesc = vertDesc->layouts()->object(binding->bufferIndex);
|
|
||||||
if (!layoutDesc->stride()) {
|
|
||||||
assert(binding->vertexStride > 0);
|
|
||||||
layoutDesc->setStride(static_cast<NS::UInteger>(binding->vertexStride));
|
|
||||||
layoutDesc->setStepFunction(binding->vertexBufferResource ? MTL::VertexStepFunctionPerVertex
|
|
||||||
: MTL::VertexStepFunctionConstant);
|
|
||||||
layoutDesc->setStepRate(binding->vertexBufferResource ? 1 : 0);
|
|
||||||
} else {
|
|
||||||
assert(layoutDesc->stride() == static_cast<NS::UInteger>(binding->vertexStride));
|
|
||||||
assert(layoutDesc->stepRate() == (binding->vertexBufferResource ? 1 : 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
mbgl::util::hash_combine(hash,
|
|
||||||
mbgl::util::hash(index,
|
|
||||||
binding->attribute.offset,
|
|
||||||
binding->attribute.dataType,
|
|
||||||
binding->vertexStride,
|
|
||||||
static_cast<bool>(binding->vertexBufferResource)));
|
|
||||||
|
|
||||||
index += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl->vertexDesc = std::move(vertDesc);
|
impl->vertexDesc = std::move(vertDesc);
|
||||||
impl->vertexDescHash = hash;
|
impl->vertexDescHash = hash;
|
||||||
@@ -631,31 +658,6 @@ void Drawable::upload(gfx::UploadPass& uploadPass_) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// build instance buffer
|
|
||||||
const bool buildInstanceBuffer =
|
|
||||||
(instanceAttributes && (!attributeUpdateTime || instanceAttributes->isModifiedAfter(*attributeUpdateTime)));
|
|
||||||
|
|
||||||
if (buildInstanceBuffer) {
|
|
||||||
// Build instance attribute buffers
|
|
||||||
std::vector<std::unique_ptr<gfx::VertexBufferResource>> instanceBuffers;
|
|
||||||
auto instanceBindings_ = uploadPass.buildAttributeBindings(instanceAttributes->getMaxCount(),
|
|
||||||
/*vertexType*/ gfx::AttributeDataType::Byte,
|
|
||||||
/*vertexAttributeIndex=*/-1,
|
|
||||||
/*vertexData=*/{},
|
|
||||||
shader->getInstanceAttributes(),
|
|
||||||
*instanceAttributes,
|
|
||||||
usage,
|
|
||||||
attributeUpdateTime,
|
|
||||||
instanceBuffers);
|
|
||||||
|
|
||||||
// clear dirty flag
|
|
||||||
instanceAttributes->visitAttributes([](gfx::VertexAttribute& attrib) { attrib.setDirty(false); });
|
|
||||||
|
|
||||||
if (impl->instanceBindings != instanceBindings_) {
|
|
||||||
impl->instanceBindings = std::move(instanceBindings_);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const bool texturesNeedUpload = std::any_of(
|
const bool texturesNeedUpload = std::any_of(
|
||||||
textures.begin(), textures.end(), [](const auto& texture) { return texture && texture->needsUpload(); });
|
textures.begin(), textures.end(), [](const auto& texture) { return texture && texture->needsUpload(); });
|
||||||
|
|
||||||
|
|||||||
@@ -117,7 +117,9 @@ void RendererBackend::initShaders(gfx::ShaderRegistry& shaders, const ProgramPar
|
|||||||
shaders::BuiltIn::FillOutlinePatternShader,
|
shaders::BuiltIn::FillOutlinePatternShader,
|
||||||
shaders::BuiltIn::FillOutlineTriangulatedShader,
|
shaders::BuiltIn::FillOutlineTriangulatedShader,
|
||||||
shaders::BuiltIn::FillExtrusionShader,
|
shaders::BuiltIn::FillExtrusionShader,
|
||||||
|
shaders::BuiltIn::FillExtrusionInstancedShader,
|
||||||
shaders::BuiltIn::FillExtrusionPatternShader,
|
shaders::BuiltIn::FillExtrusionPatternShader,
|
||||||
|
shaders::BuiltIn::FillExtrusionPatternInstancedShader,
|
||||||
shaders::BuiltIn::HeatmapShader,
|
shaders::BuiltIn::HeatmapShader,
|
||||||
shaders::BuiltIn::HeatmapTextureShader,
|
shaders::BuiltIn::HeatmapTextureShader,
|
||||||
shaders::BuiltIn::HillshadeShader,
|
shaders::BuiltIn::HillshadeShader,
|
||||||
|
|||||||
@@ -101,6 +101,25 @@ void FillExtrusionBucket::addFeature(const GeometryTileFeature& feature,
|
|||||||
for (std::size_t i = 0; i < nVertices; i++) {
|
for (std::size_t i = 0; i < nVertices; i++) {
|
||||||
const auto& p1 = ring[i];
|
const auto& p1 = ring[i];
|
||||||
|
|
||||||
|
#if MLN_USE_FILL_EXTRUSION_INSTANCING
|
||||||
|
vertices.emplace_back(layoutVertex(p1, edgeDistance, i == nVertices - 1));
|
||||||
|
flatIndices.emplace_back(triangleIndex);
|
||||||
|
triangleIndex++;
|
||||||
|
|
||||||
|
if (i < nVertices - 1) {
|
||||||
|
const auto& p2 = ring[i + 1];
|
||||||
|
|
||||||
|
const auto d1 = convertPoint<double>(p1);
|
||||||
|
const auto d2 = convertPoint<double>(p2);
|
||||||
|
|
||||||
|
const size_t dist = util::dist<uint16_t>(d1, d2);
|
||||||
|
if (edgeDistance + dist > static_cast<size_t>(std::numeric_limits<uint16_t>::max())) {
|
||||||
|
edgeDistance = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
edgeDistance += dist;
|
||||||
|
}
|
||||||
|
#else
|
||||||
vertices.emplace_back(
|
vertices.emplace_back(
|
||||||
FillExtrusionBucket::layoutVertex(p1, 0, 0, 1, 1, static_cast<uint16_t>(edgeDistance)));
|
FillExtrusionBucket::layoutVertex(p1, 0, 0, 1, 1, static_cast<uint16_t>(edgeDistance)));
|
||||||
flatIndices.emplace_back(triangleIndex);
|
flatIndices.emplace_back(triangleIndex);
|
||||||
@@ -141,6 +160,7 @@ void FillExtrusionBucket::addFeature(const GeometryTileFeature& feature,
|
|||||||
triangleSegment.vertexLength += 4;
|
triangleSegment.vertexLength += 4;
|
||||||
triangleSegment.indexLength += 6;
|
triangleSegment.indexLength += 6;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,13 @@ class BucketParameters;
|
|||||||
class RenderFillExtrusionLayer;
|
class RenderFillExtrusionLayer;
|
||||||
|
|
||||||
using FillExtrusionBinders = PaintPropertyBinders<style::FillExtrusionPaintProperties::DataDrivenProperties>;
|
using FillExtrusionBinders = PaintPropertyBinders<style::FillExtrusionPaintProperties::DataDrivenProperties>;
|
||||||
|
using FillExtrusionStaticVertex = gfx::Vertex<TypeList<attributes::pos>>;
|
||||||
|
|
||||||
|
#if MLN_USE_FILL_EXTRUSION_INSTANCING
|
||||||
|
using FillExtrusionLayoutVertex = gfx::Vertex<TypeList<attributes::pos, attributes::ed_discard>>;
|
||||||
|
#else
|
||||||
using FillExtrusionLayoutVertex = gfx::Vertex<TypeList<attributes::pos, attributes::normal_ed>>;
|
using FillExtrusionLayoutVertex = gfx::Vertex<TypeList<attributes::pos, attributes::normal_ed>>;
|
||||||
|
#endif
|
||||||
|
|
||||||
class FillExtrusionBucket final : public Bucket {
|
class FillExtrusionBucket final : public Bucket {
|
||||||
public:
|
public:
|
||||||
@@ -43,6 +49,16 @@ public:
|
|||||||
|
|
||||||
void update(const FeatureStates&, const GeometryTileLayer&, const std::string&, const ImagePositions&) override;
|
void update(const FeatureStates&, const GeometryTileLayer&, const std::string&, const ImagePositions&) override;
|
||||||
|
|
||||||
|
#if MLN_USE_FILL_EXTRUSION_INSTANCING
|
||||||
|
static FillExtrusionLayoutVertex layoutVertex(Point<int16_t> p, uint16_t edgeDistance, bool isDiscarded) {
|
||||||
|
return FillExtrusionLayoutVertex{{p.x, p.y},
|
||||||
|
{ // The edgeDistance attribute is used for wrapping fill_extrusion patterns
|
||||||
|
edgeDistance,
|
||||||
|
// When used as instance vector this specify if an instance is discarded
|
||||||
|
static_cast<uint16_t>(isDiscarded)
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
#else
|
||||||
static FillExtrusionLayoutVertex layoutVertex(
|
static FillExtrusionLayoutVertex layoutVertex(
|
||||||
Point<int16_t> p, double nx, double ny, double nz, unsigned short t, uint16_t e) {
|
Point<int16_t> p, double nx, double ny, double nz, unsigned short t, uint16_t e) {
|
||||||
const auto factor = pow(2, 13);
|
const auto factor = pow(2, 13);
|
||||||
@@ -57,6 +73,7 @@ public:
|
|||||||
// The edgedistance attribute is used for wrapping fill_extrusion patterns
|
// The edgedistance attribute is used for wrapping fill_extrusion patterns
|
||||||
static_cast<int16_t>(e)}}};
|
static_cast<int16_t>(e)}}};
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static std::array<float, 3> lightColor(const EvaluatedLight&);
|
static std::array<float, 3> lightColor(const EvaluatedLight&);
|
||||||
static std::array<float, 3> lightPosition(const EvaluatedLight&, const TransformState&);
|
static std::array<float, 3> lightPosition(const EvaluatedLight&, const TransformState&);
|
||||||
|
|||||||
@@ -163,6 +163,36 @@ void RenderFillExtrusionLayer::update(gfx::ShaderRegistry& shaders,
|
|||||||
|
|
||||||
tileLayerGroup->setStencilTiles(renderTiles);
|
tileLayerGroup->setStencilTiles(renderTiles);
|
||||||
|
|
||||||
|
#if MLN_USE_FILL_EXTRUSION_INSTANCING
|
||||||
|
if (!fillExtrusionInstancedGroup) {
|
||||||
|
fillExtrusionInstancedGroup = shaders.getShaderGroup("FillExtrusionInstancedShader");
|
||||||
|
}
|
||||||
|
if (!fillExtrusionPatternInstancedGroup) {
|
||||||
|
fillExtrusionPatternInstancedGroup = shaders.getShaderGroup("FillExtrusionPatternInstancedShader");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!staticDataVertices) {
|
||||||
|
staticDataVertices = std::make_shared<FillExtrusionVertexVector>(RenderStaticData::fillExtrusionVertices());
|
||||||
|
}
|
||||||
|
if (!staticDataIndices) {
|
||||||
|
staticDataIndices = std::make_shared<TriangleIndexVector>(RenderStaticData::fillExtrusionTriangleIndices());
|
||||||
|
}
|
||||||
|
if (!staticDataSegments) {
|
||||||
|
staticDataSegments = std::make_shared<SegmentVector>(RenderStaticData::fillExtrusionSegments());
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& instancedShaderGroup = hasPattern ? fillExtrusionPatternInstancedGroup : fillExtrusionInstancedGroup;
|
||||||
|
if (!instancedShaderGroup) {
|
||||||
|
removeAllDrawables();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto instanceVertexCount = staticDataVertices->elements();
|
||||||
|
std::unique_ptr<gfx::DrawableBuilder> instancedDepthBuilder;
|
||||||
|
std::unique_ptr<gfx::DrawableBuilder> instancedColorBuilder;
|
||||||
|
StringIDSetsPair instancePropertiesAsUniforms;
|
||||||
|
#endif
|
||||||
|
|
||||||
StringIDSetsPair propertiesAsUniforms;
|
StringIDSetsPair propertiesAsUniforms;
|
||||||
for (const RenderTile& tile : *renderTiles) {
|
for (const RenderTile& tile : *renderTiles) {
|
||||||
const auto& tileID = tile.getOverscaledTileID();
|
const auto& tileID = tile.getOverscaledTileID();
|
||||||
@@ -222,6 +252,31 @@ void RenderFillExtrusionLayer::update(gfx::ShaderRegistry& shaders,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if MLN_USE_FILL_EXTRUSION_INSTANCING
|
||||||
|
if (instancedDepthBuilder) {
|
||||||
|
instancedDepthBuilder->clearTweakers();
|
||||||
|
}
|
||||||
|
if (instancedColorBuilder) {
|
||||||
|
instancedColorBuilder->clearTweakers();
|
||||||
|
}
|
||||||
|
|
||||||
|
instancePropertiesAsUniforms.first.clear();
|
||||||
|
instancePropertiesAsUniforms.second.clear();
|
||||||
|
|
||||||
|
auto instanceAttrs = context.createVertexAttributeArray();
|
||||||
|
instanceAttrs->readDataDrivenPaintProperties<FillExtrusionBase,
|
||||||
|
FillExtrusionColor,
|
||||||
|
FillExtrusionHeight,
|
||||||
|
FillExtrusionPattern>(
|
||||||
|
binders, evaluated, instancePropertiesAsUniforms, idFillExtrusionBaseVertexAttribute);
|
||||||
|
|
||||||
|
const auto instancedShader = std::static_pointer_cast<gfx::ShaderProgramBase>(
|
||||||
|
instancedShaderGroup->getOrCreateShader(context, instancePropertiesAsUniforms));
|
||||||
|
if (!instancedShader) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// The non-pattern path in `render()` only uses two-pass rendering if there's translucency.
|
// The non-pattern path in `render()` only uses two-pass rendering if there's translucency.
|
||||||
// The pattern path always uses two passes.
|
// The pattern path always uses two passes.
|
||||||
const auto doDepthPass = (!opaque || hasPattern);
|
const auto doDepthPass = (!opaque || hasPattern);
|
||||||
@@ -272,6 +327,15 @@ void RenderFillExtrusionLayer::update(gfx::ShaderRegistry& shaders,
|
|||||||
if (colorBuilder) {
|
if (colorBuilder) {
|
||||||
colorBuilder->addTweaker(tweaker);
|
colorBuilder->addTweaker(tweaker);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if MLN_USE_FILL_EXTRUSION_INSTANCING
|
||||||
|
if (instancedDepthBuilder) {
|
||||||
|
instancedDepthBuilder->addTweaker(tweaker);
|
||||||
|
}
|
||||||
|
if (instancedColorBuilder) {
|
||||||
|
instancedColorBuilder->addTweaker(tweaker);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -282,6 +346,7 @@ void RenderFillExtrusionLayer::update(gfx::ShaderRegistry& shaders,
|
|||||||
sizeof(FillExtrusionLayoutVertex),
|
sizeof(FillExtrusionLayoutVertex),
|
||||||
gfx::AttributeDataType::Short2);
|
gfx::AttributeDataType::Short2);
|
||||||
}
|
}
|
||||||
|
#if !MLN_USE_FILL_EXTRUSION_INSTANCING
|
||||||
if (const auto& attr = vertexAttrs->set(idFillExtrusionNormalEdVertexAttribute)) {
|
if (const auto& attr = vertexAttrs->set(idFillExtrusionNormalEdVertexAttribute)) {
|
||||||
attr->setSharedRawData(bucket.sharedVertices,
|
attr->setSharedRawData(bucket.sharedVertices,
|
||||||
offsetof(FillExtrusionLayoutVertex, a2),
|
offsetof(FillExtrusionLayoutVertex, a2),
|
||||||
@@ -289,6 +354,7 @@ void RenderFillExtrusionLayer::update(gfx::ShaderRegistry& shaders,
|
|||||||
sizeof(FillExtrusionLayoutVertex),
|
sizeof(FillExtrusionLayoutVertex),
|
||||||
gfx::AttributeDataType::Short4);
|
gfx::AttributeDataType::Short4);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (doDepthPass) {
|
if (doDepthPass) {
|
||||||
depthBuilder->setRawVertices({}, vertexCount, gfx::AttributeDataType::Short2);
|
depthBuilder->setRawVertices({}, vertexCount, gfx::AttributeDataType::Short2);
|
||||||
@@ -321,11 +387,101 @@ void RenderFillExtrusionLayer::update(gfx::ShaderRegistry& shaders,
|
|||||||
++stats.drawablesAdded;
|
++stats.drawablesAdded;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (doDepthPass) {
|
if (doDepthPass) {
|
||||||
finish(*depthBuilder);
|
finish(*depthBuilder);
|
||||||
}
|
}
|
||||||
finish(*colorBuilder);
|
finish(*colorBuilder);
|
||||||
|
|
||||||
|
#if MLN_USE_FILL_EXTRUSION_INSTANCING
|
||||||
|
if (doDepthPass && !instancedDepthBuilder) {
|
||||||
|
if (auto builder = context.createDrawableBuilder(layerPrefix + "depthInstanced")) {
|
||||||
|
builder->setShader(instancedShader);
|
||||||
|
builder->setIs3D(true);
|
||||||
|
builder->setEnableColor(false);
|
||||||
|
builder->setRenderPass(drawPass);
|
||||||
|
builder->setCullFaceMode(gfx::CullFaceMode::backCCW());
|
||||||
|
builder->setDrawPriority(0);
|
||||||
|
if (tweaker) {
|
||||||
|
builder->addTweaker(tweaker);
|
||||||
|
}
|
||||||
|
instancedDepthBuilder = std::move(builder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!instancedColorBuilder) {
|
||||||
|
if (auto builder = context.createDrawableBuilder(layerPrefix + "colorInstanced")) {
|
||||||
|
builder->setShader(instancedShader);
|
||||||
|
builder->setIs3D(true);
|
||||||
|
builder->setEnableColor(true);
|
||||||
|
builder->setColorMode(gfx::ColorMode::alphaBlended());
|
||||||
|
builder->setRenderPass(drawPass);
|
||||||
|
builder->setCullFaceMode(gfx::CullFaceMode::backCCW());
|
||||||
|
builder->setDrawPriority(1);
|
||||||
|
if (tweaker) {
|
||||||
|
builder->addTweaker(tweaker);
|
||||||
|
}
|
||||||
|
instancedColorBuilder = std::move(builder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto instanceVertexAttrs = context.createVertexAttributeArray();
|
||||||
|
if (const auto& attr = instanceVertexAttrs->set(idFillExtrusionPosVertexAttribute)) {
|
||||||
|
attr->setSharedRawData(staticDataVertices,
|
||||||
|
offsetof(FillExtrusionStaticVertex, a1),
|
||||||
|
/*vertexOffset=*/0,
|
||||||
|
sizeof(FillExtrusionStaticVertex),
|
||||||
|
gfx::AttributeDataType::Short2);
|
||||||
|
}
|
||||||
|
if (const auto& attr = instanceAttrs->set(idFillExtrusionOutlinePosAttribute)) {
|
||||||
|
attr->setSharedRawData(bucket.sharedVertices,
|
||||||
|
offsetof(FillExtrusionLayoutVertex, a1),
|
||||||
|
/*vertexOffset=*/0,
|
||||||
|
sizeof(FillExtrusionLayoutVertex),
|
||||||
|
gfx::AttributeDataType::Short2);
|
||||||
|
}
|
||||||
|
if (const auto& attr = instanceAttrs->set(idFillExtrusionEdDiscardAttribute)) {
|
||||||
|
attr->setSharedRawData(bucket.sharedVertices,
|
||||||
|
offsetof(FillExtrusionLayoutVertex, a2),
|
||||||
|
/*vertexOffset=*/0,
|
||||||
|
sizeof(FillExtrusionLayoutVertex),
|
||||||
|
gfx::AttributeDataType::UShort2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (doDepthPass) {
|
||||||
|
instancedDepthBuilder->setRawVertices({}, instanceVertexCount, gfx::AttributeDataType::Short2);
|
||||||
|
instancedDepthBuilder->setVertexAttributes(instanceVertexAttrs);
|
||||||
|
instancedDepthBuilder->setInstanceAttributes(instanceAttrs);
|
||||||
|
}
|
||||||
|
|
||||||
|
instancedColorBuilder->setEnableStencil(doDepthPass);
|
||||||
|
instancedColorBuilder->setRawVertices({}, instanceVertexCount, gfx::AttributeDataType::Short2);
|
||||||
|
instancedColorBuilder->setVertexAttributes(std::move(instanceVertexAttrs));
|
||||||
|
instancedColorBuilder->setInstanceAttributes(std::move(instanceAttrs));
|
||||||
|
|
||||||
|
const auto finishInstance = [&](gfx::DrawableBuilder& instancedBuilder) {
|
||||||
|
if (!staticDataIndices->elements()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
instancedBuilder.setSegments(
|
||||||
|
gfx::Triangles(), staticDataIndices, staticDataSegments->data(), staticDataSegments->size());
|
||||||
|
|
||||||
|
instancedBuilder.flush(context);
|
||||||
|
|
||||||
|
for (auto& drawable : instancedBuilder.clearDrawables()) {
|
||||||
|
drawable->setTileID(tileID);
|
||||||
|
drawable->setType(static_cast<std::size_t>(hasPattern));
|
||||||
|
drawable->setLayerTweaker(layerTweaker);
|
||||||
|
drawable->setBinders(renderData.bucket, &binders);
|
||||||
|
drawable->setRenderTile(renderTilesOwner, &tile);
|
||||||
|
|
||||||
|
tileLayerGroup->addDrawable(drawPass, tileID, std::move(drawable));
|
||||||
|
++stats.drawablesAdded;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (doDepthPass) {
|
||||||
|
finishInstance(*instancedDepthBuilder);
|
||||||
|
}
|
||||||
|
finishInstance(*instancedColorBuilder);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <mbgl/renderer/render_layer.hpp>
|
#include <mbgl/renderer/render_layer.hpp>
|
||||||
|
#include <mbgl/renderer/buckets/fill_extrusion_bucket.hpp>
|
||||||
#include <mbgl/style/layers/fill_extrusion_layer_impl.hpp>
|
#include <mbgl/style/layers/fill_extrusion_layer_impl.hpp>
|
||||||
#include <mbgl/style/layers/fill_extrusion_layer_properties.hpp>
|
#include <mbgl/style/layers/fill_extrusion_layer_properties.hpp>
|
||||||
#include <mbgl/gfx/offscreen_texture.hpp>
|
|
||||||
|
|
||||||
namespace mbgl {
|
namespace mbgl {
|
||||||
|
|
||||||
@@ -40,7 +40,18 @@ private:
|
|||||||
|
|
||||||
gfx::ShaderGroupPtr fillExtrusionGroup;
|
gfx::ShaderGroupPtr fillExtrusionGroup;
|
||||||
gfx::ShaderGroupPtr fillExtrusionPatternGroup;
|
gfx::ShaderGroupPtr fillExtrusionPatternGroup;
|
||||||
std::unique_ptr<gfx::OffscreenTexture> renderTexture;
|
|
||||||
|
#if MLN_USE_FILL_EXTRUSION_INSTANCING
|
||||||
|
gfx::ShaderGroupPtr fillExtrusionInstancedGroup;
|
||||||
|
gfx::ShaderGroupPtr fillExtrusionPatternInstancedGroup;
|
||||||
|
|
||||||
|
using FillExtrusionVertexVector = gfx::VertexVector<FillExtrusionStaticVertex>;
|
||||||
|
using TriangleIndexVector = gfx::IndexVector<gfx::Triangles>;
|
||||||
|
|
||||||
|
std::shared_ptr<FillExtrusionVertexVector> staticDataVertices;
|
||||||
|
std::shared_ptr<TriangleIndexVector> staticDataIndices;
|
||||||
|
std::shared_ptr<SegmentVector> staticDataSegments;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace mbgl
|
} // namespace mbgl
|
||||||
|
|||||||
@@ -141,7 +141,7 @@ void RenderRasterLayer::update(gfx::ShaderRegistry& shaders,
|
|||||||
staticDataIndices = std::make_shared<TriangleIndexVector>(RenderStaticData::quadTriangleIndices());
|
staticDataIndices = std::make_shared<TriangleIndexVector>(RenderStaticData::quadTriangleIndices());
|
||||||
}
|
}
|
||||||
if (!staticDataSegments) {
|
if (!staticDataSegments) {
|
||||||
staticDataSegments = std::make_shared<RasterSegmentVector>(RenderStaticData::rasterSegments());
|
staticDataSegments = std::make_shared<SegmentVector>(RenderStaticData::rasterSegments());
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto createBuilder = [&] {
|
const auto createBuilder = [&] {
|
||||||
|
|||||||
@@ -61,9 +61,8 @@ private:
|
|||||||
using TriangleIndexVectorPtr = std::shared_ptr<TriangleIndexVector>;
|
using TriangleIndexVectorPtr = std::shared_ptr<TriangleIndexVector>;
|
||||||
TriangleIndexVectorPtr staticDataIndices;
|
TriangleIndexVectorPtr staticDataIndices;
|
||||||
|
|
||||||
using RasterSegmentVector = SegmentVector;
|
using SegmentVectorPtr = std::shared_ptr<SegmentVector>;
|
||||||
using RasterSegmentVectorPtr = std::shared_ptr<RasterSegmentVector>;
|
SegmentVectorPtr staticDataSegments;
|
||||||
std::shared_ptr<RasterSegmentVector> staticDataSegments;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace mbgl
|
} // namespace mbgl
|
||||||
|
|||||||
@@ -5,54 +5,86 @@
|
|||||||
|
|
||||||
namespace mbgl {
|
namespace mbgl {
|
||||||
|
|
||||||
gfx::VertexVector<gfx::Vertex<PositionOnlyLayoutAttributes>> RenderStaticData::tileVertices() {
|
|
||||||
gfx::VertexVector<gfx::Vertex<PositionOnlyLayoutAttributes>> result;
|
|
||||||
result.emplace_back(gfx::Vertex<PositionOnlyLayoutAttributes>({{{0, 0}}}));
|
|
||||||
result.emplace_back(gfx::Vertex<PositionOnlyLayoutAttributes>({{{util::EXTENT, 0}}}));
|
|
||||||
result.emplace_back(gfx::Vertex<PositionOnlyLayoutAttributes>({{{0, util::EXTENT}}}));
|
|
||||||
result.emplace_back(gfx::Vertex<PositionOnlyLayoutAttributes>({{{util::EXTENT, util::EXTENT}}}));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
gfx::IndexVector<gfx::Triangles> RenderStaticData::quadTriangleIndices() {
|
|
||||||
gfx::IndexVector<gfx::Triangles> result;
|
|
||||||
result.emplace_back(0, 1, 2);
|
|
||||||
result.emplace_back(1, 2, 3);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
gfx::IndexVector<gfx::LineStrip> RenderStaticData::tileLineStripIndices() {
|
|
||||||
gfx::IndexVector<gfx::LineStrip> result;
|
|
||||||
result.emplace_back(0);
|
|
||||||
result.emplace_back(1);
|
|
||||||
result.emplace_back(3);
|
|
||||||
result.emplace_back(2);
|
|
||||||
result.emplace_back(0);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
gfx::VertexVector<RasterLayoutVertex> RenderStaticData::rasterVertices() {
|
|
||||||
gfx::VertexVector<RasterLayoutVertex> result;
|
|
||||||
result.emplace_back(RasterBucket::layoutVertex({0, 0}, {0, 0}));
|
|
||||||
result.emplace_back(RasterBucket::layoutVertex({util::EXTENT, 0}, {util::EXTENT, 0}));
|
|
||||||
result.emplace_back(RasterBucket::layoutVertex({0, util::EXTENT}, {0, util::EXTENT}));
|
|
||||||
result.emplace_back(RasterBucket::layoutVertex({util::EXTENT, util::EXTENT}, {util::EXTENT, util::EXTENT}));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
gfx::VertexVector<HeatmapTextureLayoutVertex> RenderStaticData::heatmapTextureVertices() {
|
|
||||||
gfx::VertexVector<HeatmapTextureLayoutVertex> result;
|
|
||||||
result.emplace_back(HeatmapBucket::textureVertex({0, 0}));
|
|
||||||
result.emplace_back(HeatmapBucket::textureVertex({1, 0}));
|
|
||||||
result.emplace_back(HeatmapBucket::textureVertex({0, 1}));
|
|
||||||
result.emplace_back(HeatmapBucket::textureVertex({1, 1}));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
RenderStaticData::RenderStaticData(std::unique_ptr<gfx::ShaderRegistry>&& shaders_)
|
RenderStaticData::RenderStaticData(std::unique_ptr<gfx::ShaderRegistry>&& shaders_)
|
||||||
: shaders(std::move(shaders_)),
|
: shaders(std::move(shaders_)),
|
||||||
clippingMaskSegments(tileTriangleSegments()) {}
|
clippingMaskSegments(tileTriangleSegments()) {}
|
||||||
|
|
||||||
|
void RenderStaticData::upload(gfx::UploadPass& uploadPass) {
|
||||||
|
if (!uploaded) {
|
||||||
|
// these are still used by stencil buffer rendering
|
||||||
|
tileVertexBuffer = uploadPass.createVertexBuffer(
|
||||||
|
tileVertices(), gfx::BufferUsageType::StaticDraw, /*persistent=*/false);
|
||||||
|
quadTriangleIndexBuffer = uploadPass.createIndexBuffer(
|
||||||
|
quadTriangleIndices(), gfx::BufferUsageType::StaticDraw, /*persistent=*/false);
|
||||||
|
uploaded = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gfx::VertexVector<gfx::Vertex<PositionOnlyLayoutAttributes>> RenderStaticData::tileVertices() {
|
||||||
|
gfx::VertexVector<gfx::Vertex<PositionOnlyLayoutAttributes>> vertices;
|
||||||
|
vertices.emplace_back(gfx::Vertex<PositionOnlyLayoutAttributes>({{{0, 0}}}));
|
||||||
|
vertices.emplace_back(gfx::Vertex<PositionOnlyLayoutAttributes>({{{util::EXTENT, 0}}}));
|
||||||
|
vertices.emplace_back(gfx::Vertex<PositionOnlyLayoutAttributes>({{{0, util::EXTENT}}}));
|
||||||
|
vertices.emplace_back(gfx::Vertex<PositionOnlyLayoutAttributes>({{{util::EXTENT, util::EXTENT}}}));
|
||||||
|
return vertices;
|
||||||
|
}
|
||||||
|
|
||||||
|
gfx::VertexVector<RasterLayoutVertex> RenderStaticData::rasterVertices() {
|
||||||
|
gfx::VertexVector<RasterLayoutVertex> vertices;
|
||||||
|
vertices.emplace_back(RasterBucket::layoutVertex({0, 0}, {0, 0}));
|
||||||
|
vertices.emplace_back(RasterBucket::layoutVertex({util::EXTENT, 0}, {util::EXTENT, 0}));
|
||||||
|
vertices.emplace_back(RasterBucket::layoutVertex({0, util::EXTENT}, {0, util::EXTENT}));
|
||||||
|
vertices.emplace_back(RasterBucket::layoutVertex({util::EXTENT, util::EXTENT}, {util::EXTENT, util::EXTENT}));
|
||||||
|
return vertices;
|
||||||
|
}
|
||||||
|
|
||||||
|
gfx::VertexVector<HeatmapTextureLayoutVertex> RenderStaticData::heatmapTextureVertices() {
|
||||||
|
gfx::VertexVector<HeatmapTextureLayoutVertex> vertices;
|
||||||
|
vertices.emplace_back(HeatmapBucket::textureVertex({0, 0}));
|
||||||
|
vertices.emplace_back(HeatmapBucket::textureVertex({1, 0}));
|
||||||
|
vertices.emplace_back(HeatmapBucket::textureVertex({0, 1}));
|
||||||
|
vertices.emplace_back(HeatmapBucket::textureVertex({1, 1}));
|
||||||
|
return vertices;
|
||||||
|
}
|
||||||
|
|
||||||
|
gfx::VertexVector<FillExtrusionStaticVertex> RenderStaticData::fillExtrusionVertices() {
|
||||||
|
gfx::VertexVector<HeatmapTextureLayoutVertex> vertices;
|
||||||
|
vertices.emplace_back(FillExtrusionStaticVertex{1, 0});
|
||||||
|
vertices.emplace_back(FillExtrusionStaticVertex{1, 1});
|
||||||
|
vertices.emplace_back(FillExtrusionStaticVertex{0, 0});
|
||||||
|
vertices.emplace_back(FillExtrusionStaticVertex{0, 1});
|
||||||
|
return vertices;
|
||||||
|
}
|
||||||
|
|
||||||
|
gfx::IndexVector<gfx::Triangles> RenderStaticData::quadTriangleIndices() {
|
||||||
|
gfx::IndexVector<gfx::Triangles> indices;
|
||||||
|
indices.emplace_back(0, 1, 2);
|
||||||
|
indices.emplace_back(1, 2, 3);
|
||||||
|
return indices;
|
||||||
|
}
|
||||||
|
|
||||||
|
gfx::IndexVector<gfx::LineStrip> RenderStaticData::tileLineStripIndices() {
|
||||||
|
gfx::IndexVector<gfx::LineStrip> indices;
|
||||||
|
indices.emplace_back(0);
|
||||||
|
indices.emplace_back(1);
|
||||||
|
indices.emplace_back(3);
|
||||||
|
indices.emplace_back(2);
|
||||||
|
indices.emplace_back(0);
|
||||||
|
return indices;
|
||||||
|
}
|
||||||
|
|
||||||
|
gfx::IndexVector<gfx::Triangles> RenderStaticData::fillExtrusionTriangleIndices() {
|
||||||
|
gfx::IndexVector<gfx::Triangles> indices;
|
||||||
|
// ┌──────┐
|
||||||
|
// │ 0 1 │ Counter-Clockwise winding order.
|
||||||
|
// │ │ Triangle 1: 0 => 2 => 1
|
||||||
|
// │ 2 3 │ Triangle 2: 1 => 2 => 3
|
||||||
|
// └──────┘
|
||||||
|
indices.emplace_back(0, 2, 1);
|
||||||
|
indices.emplace_back(1, 2, 3);
|
||||||
|
return indices;
|
||||||
|
}
|
||||||
|
|
||||||
SegmentVector RenderStaticData::tileTriangleSegments() {
|
SegmentVector RenderStaticData::tileTriangleSegments() {
|
||||||
SegmentVector segments;
|
SegmentVector segments;
|
||||||
segments.emplace_back(0, 0, 4, 6);
|
segments.emplace_back(0, 0, 4, 6);
|
||||||
@@ -77,15 +109,10 @@ SegmentVector RenderStaticData::heatmapTextureSegments() {
|
|||||||
return segments;
|
return segments;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderStaticData::upload(gfx::UploadPass& uploadPass) {
|
SegmentVector RenderStaticData::fillExtrusionSegments() {
|
||||||
if (!uploaded) {
|
SegmentVector segments;
|
||||||
// these are still used by stencil buffer rendering
|
segments.emplace_back(0, 0, 4, 6);
|
||||||
tileVertexBuffer = uploadPass.createVertexBuffer(
|
return segments;
|
||||||
tileVertices(), gfx::BufferUsageType::StaticDraw, /*persistent=*/false);
|
|
||||||
quadTriangleIndexBuffer = uploadPass.createIndexBuffer(
|
|
||||||
quadTriangleIndices(), gfx::BufferUsageType::StaticDraw, /*persistent=*/false);
|
|
||||||
uploaded = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace mbgl
|
} // namespace mbgl
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include <mbgl/gfx/shader_registry.hpp>
|
#include <mbgl/gfx/shader_registry.hpp>
|
||||||
#include <mbgl/renderer/buckets/heatmap_bucket.hpp>
|
#include <mbgl/renderer/buckets/heatmap_bucket.hpp>
|
||||||
#include <mbgl/renderer/buckets/raster_bucket.hpp>
|
#include <mbgl/renderer/buckets/raster_bucket.hpp>
|
||||||
|
#include <mbgl/renderer/buckets/fill_extrusion_bucket.hpp>
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
@@ -23,22 +24,22 @@ public:
|
|||||||
void upload(gfx::UploadPass&);
|
void upload(gfx::UploadPass&);
|
||||||
|
|
||||||
std::optional<gfx::VertexBuffer<gfx::Vertex<PositionOnlyLayoutAttributes>>> tileVertexBuffer;
|
std::optional<gfx::VertexBuffer<gfx::Vertex<PositionOnlyLayoutAttributes>>> tileVertexBuffer;
|
||||||
std::optional<gfx::VertexBuffer<RasterLayoutVertex>> rasterVertexBuffer;
|
|
||||||
std::optional<gfx::VertexBuffer<HeatmapTextureLayoutVertex>> heatmapTextureVertexBuffer;
|
|
||||||
|
|
||||||
std::optional<gfx::IndexBuffer> quadTriangleIndexBuffer;
|
std::optional<gfx::IndexBuffer> quadTriangleIndexBuffer;
|
||||||
std::optional<gfx::IndexBuffer> tileBorderIndexBuffer;
|
|
||||||
|
|
||||||
static gfx::VertexVector<gfx::Vertex<PositionOnlyLayoutAttributes>> tileVertices();
|
static gfx::VertexVector<gfx::Vertex<PositionOnlyLayoutAttributes>> tileVertices();
|
||||||
static gfx::IndexVector<gfx::Triangles> quadTriangleIndices();
|
|
||||||
static gfx::IndexVector<gfx::LineStrip> tileLineStripIndices();
|
|
||||||
static gfx::VertexVector<RasterLayoutVertex> rasterVertices();
|
static gfx::VertexVector<RasterLayoutVertex> rasterVertices();
|
||||||
static gfx::VertexVector<HeatmapTextureLayoutVertex> heatmapTextureVertices();
|
static gfx::VertexVector<HeatmapTextureLayoutVertex> heatmapTextureVertices();
|
||||||
|
static gfx::VertexVector<FillExtrusionStaticVertex> fillExtrusionVertices();
|
||||||
|
|
||||||
|
static gfx::IndexVector<gfx::Triangles> quadTriangleIndices();
|
||||||
|
static gfx::IndexVector<gfx::LineStrip> tileLineStripIndices();
|
||||||
|
static gfx::IndexVector<gfx::Triangles> fillExtrusionTriangleIndices();
|
||||||
|
|
||||||
static SegmentVector tileTriangleSegments();
|
static SegmentVector tileTriangleSegments();
|
||||||
static SegmentVector tileBorderSegments();
|
static SegmentVector tileBorderSegments();
|
||||||
static SegmentVector rasterSegments();
|
static SegmentVector rasterSegments();
|
||||||
static SegmentVector heatmapTextureSegments();
|
static SegmentVector heatmapTextureSegments();
|
||||||
|
static SegmentVector fillExtrusionSegments();
|
||||||
|
|
||||||
std::optional<gfx::Renderbuffer<gfx::RenderbufferPixelType::Depth>> depthRenderbuffer;
|
std::optional<gfx::Renderbuffer<gfx::RenderbufferPixelType::Depth>> depthRenderbuffer;
|
||||||
bool has3D = false;
|
bool has3D = false;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <mbgl/gfx/attribute.hpp>
|
#include <mbgl/gfx/attribute.hpp>
|
||||||
|
#include <mbgl/shaders/layer_ubo.hpp>
|
||||||
|
|
||||||
namespace mbgl {
|
namespace mbgl {
|
||||||
namespace attributes {
|
namespace attributes {
|
||||||
@@ -16,13 +17,18 @@ MBGL_DEFINE_ATTRIBUTE(int16_t, 4, pixeloffset);
|
|||||||
MBGL_DEFINE_ATTRIBUTE(int16_t, 2, label_pos);
|
MBGL_DEFINE_ATTRIBUTE(int16_t, 2, label_pos);
|
||||||
MBGL_DEFINE_ATTRIBUTE(int16_t, 2, anchor_pos);
|
MBGL_DEFINE_ATTRIBUTE(int16_t, 2, anchor_pos);
|
||||||
MBGL_DEFINE_ATTRIBUTE(uint16_t, 2, texture_pos);
|
MBGL_DEFINE_ATTRIBUTE(uint16_t, 2, texture_pos);
|
||||||
MBGL_DEFINE_ATTRIBUTE(int16_t, 4, normal_ed);
|
|
||||||
MBGL_DEFINE_ATTRIBUTE(float, 1, fade_opacity);
|
MBGL_DEFINE_ATTRIBUTE(float, 1, fade_opacity);
|
||||||
MBGL_DEFINE_ATTRIBUTE(uint16_t, 2, placed);
|
MBGL_DEFINE_ATTRIBUTE(uint16_t, 2, placed);
|
||||||
MBGL_DEFINE_ATTRIBUTE(uint16_t, 3, size);
|
MBGL_DEFINE_ATTRIBUTE(uint16_t, 3, size);
|
||||||
MBGL_DEFINE_ATTRIBUTE(float, 1, offset);
|
MBGL_DEFINE_ATTRIBUTE(float, 1, offset);
|
||||||
MBGL_DEFINE_ATTRIBUTE(float, 2, shift);
|
MBGL_DEFINE_ATTRIBUTE(float, 2, shift);
|
||||||
|
|
||||||
|
#if MLN_USE_FILL_EXTRUSION_INSTANCING
|
||||||
|
MBGL_DEFINE_ATTRIBUTE(uint16_t, 2, ed_discard);
|
||||||
|
#else
|
||||||
|
MBGL_DEFINE_ATTRIBUTE(int16_t, 4, normal_ed);
|
||||||
|
#endif
|
||||||
|
|
||||||
template <typename T, std::size_t N>
|
template <typename T, std::size_t N>
|
||||||
struct data {
|
struct data {
|
||||||
using Type = gfx::AttributeType<T, N>;
|
using Type = gfx::AttributeType<T, N>;
|
||||||
|
|||||||
@@ -9,37 +9,80 @@ namespace shaders {
|
|||||||
|
|
||||||
using FillExtrusionShaderSource = ShaderSource<BuiltIn::FillExtrusionShader, gfx::Backend::Type::Metal>;
|
using FillExtrusionShaderSource = ShaderSource<BuiltIn::FillExtrusionShader, gfx::Backend::Type::Metal>;
|
||||||
|
|
||||||
const std::array<AttributeInfo, 5> FillExtrusionShaderSource::attributes = {
|
const std::array<AttributeInfo, 4> FillExtrusionShaderSource::attributes = {
|
||||||
AttributeInfo{0, gfx::AttributeDataType::Short2, fillExtrusionUBOCount + 0, idFillExtrusionPosVertexAttribute},
|
AttributeInfo{0, gfx::AttributeDataType::Short2, fillExtrusionUBOCount + 0, idFillExtrusionPosVertexAttribute},
|
||||||
AttributeInfo{1, gfx::AttributeDataType::Short4, fillExtrusionUBOCount + 0, idFillExtrusionNormalEdVertexAttribute},
|
|
||||||
|
|
||||||
// Data driven
|
// Data driven
|
||||||
AttributeInfo{2, gfx::AttributeDataType::Float4, fillExtrusionUBOCount + 1, idFillExtrusionColorVertexAttribute},
|
AttributeInfo{1, gfx::AttributeDataType::Float4, fillExtrusionUBOCount + 1, idFillExtrusionColorVertexAttribute},
|
||||||
AttributeInfo{3, gfx::AttributeDataType::Float, fillExtrusionUBOCount + 1, idFillExtrusionBaseVertexAttribute},
|
AttributeInfo{2, gfx::AttributeDataType::Float, fillExtrusionUBOCount + 1, idFillExtrusionBaseVertexAttribute},
|
||||||
AttributeInfo{4, gfx::AttributeDataType::Float, fillExtrusionUBOCount + 1, idFillExtrusionHeightVertexAttribute},
|
AttributeInfo{3, gfx::AttributeDataType::Float, fillExtrusionUBOCount + 1, idFillExtrusionHeightVertexAttribute},
|
||||||
};
|
};
|
||||||
const std::array<TextureInfo, 0> FillExtrusionShaderSource::textures = {};
|
const std::array<TextureInfo, 0> FillExtrusionShaderSource::textures = {};
|
||||||
|
|
||||||
|
//
|
||||||
|
// Fill extrusion instanced
|
||||||
|
|
||||||
|
using FillExtrusionInstancedShaderSource =
|
||||||
|
ShaderSource<BuiltIn::FillExtrusionInstancedShader, gfx::Backend::Type::Metal>;
|
||||||
|
|
||||||
|
const std::array<AttributeInfo, 1> FillExtrusionInstancedShaderSource::attributes = {
|
||||||
|
AttributeInfo{0, gfx::AttributeDataType::Short2, fillExtrusionUBOCount + 0, idFillExtrusionPosVertexAttribute},
|
||||||
|
};
|
||||||
|
const std::array<AttributeInfo, 5> FillExtrusionInstancedShaderSource::instanceAttributes = {
|
||||||
|
AttributeInfo{1, gfx::AttributeDataType::Short2, fillExtrusionUBOCount + 1, idFillExtrusionOutlinePosAttribute},
|
||||||
|
AttributeInfo{2, gfx::AttributeDataType::UShort2, fillExtrusionUBOCount + 1, idFillExtrusionEdDiscardAttribute},
|
||||||
|
|
||||||
|
// Data driven
|
||||||
|
AttributeInfo{3, gfx::AttributeDataType::Float4, fillExtrusionUBOCount + 2, idFillExtrusionColorVertexAttribute},
|
||||||
|
AttributeInfo{4, gfx::AttributeDataType::Float, fillExtrusionUBOCount + 2, idFillExtrusionBaseVertexAttribute},
|
||||||
|
AttributeInfo{5, gfx::AttributeDataType::Float, fillExtrusionUBOCount + 2, idFillExtrusionHeightVertexAttribute},
|
||||||
|
};
|
||||||
|
const std::array<TextureInfo, 0> FillExtrusionInstancedShaderSource::textures = {};
|
||||||
|
|
||||||
//
|
//
|
||||||
// Fill extrusion pattern
|
// Fill extrusion pattern
|
||||||
|
|
||||||
using FillExtrusionPatternShaderSource = ShaderSource<BuiltIn::FillExtrusionPatternShader, gfx::Backend::Type::Metal>;
|
using FillExtrusionPatternShaderSource = ShaderSource<BuiltIn::FillExtrusionPatternShader, gfx::Backend::Type::Metal>;
|
||||||
|
|
||||||
const std::array<AttributeInfo, 6> FillExtrusionPatternShaderSource::attributes = {
|
const std::array<AttributeInfo, 5> FillExtrusionPatternShaderSource::attributes = {
|
||||||
AttributeInfo{0, gfx::AttributeDataType::Short2, fillExtrusionUBOCount + 0, idFillExtrusionPosVertexAttribute},
|
AttributeInfo{0, gfx::AttributeDataType::Short2, fillExtrusionUBOCount + 0, idFillExtrusionPosVertexAttribute},
|
||||||
AttributeInfo{1, gfx::AttributeDataType::Short4, fillExtrusionUBOCount + 0, idFillExtrusionNormalEdVertexAttribute},
|
|
||||||
|
|
||||||
// Data driven
|
// Data driven
|
||||||
AttributeInfo{2, gfx::AttributeDataType::Float, fillExtrusionUBOCount + 1, idFillExtrusionBaseVertexAttribute},
|
AttributeInfo{1, gfx::AttributeDataType::Float, fillExtrusionUBOCount + 1, idFillExtrusionBaseVertexAttribute},
|
||||||
AttributeInfo{3, gfx::AttributeDataType::Float, fillExtrusionUBOCount + 1, idFillExtrusionHeightVertexAttribute},
|
AttributeInfo{2, gfx::AttributeDataType::Float, fillExtrusionUBOCount + 1, idFillExtrusionHeightVertexAttribute},
|
||||||
AttributeInfo{
|
AttributeInfo{
|
||||||
4, gfx::AttributeDataType::UShort4, fillExtrusionUBOCount + 1, idFillExtrusionPatternFromVertexAttribute},
|
3, gfx::AttributeDataType::UShort4, fillExtrusionUBOCount + 1, idFillExtrusionPatternFromVertexAttribute},
|
||||||
AttributeInfo{
|
AttributeInfo{
|
||||||
5, gfx::AttributeDataType::UShort4, fillExtrusionUBOCount + 1, idFillExtrusionPatternToVertexAttribute},
|
4, gfx::AttributeDataType::UShort4, fillExtrusionUBOCount + 1, idFillExtrusionPatternToVertexAttribute},
|
||||||
};
|
};
|
||||||
const std::array<TextureInfo, 1> FillExtrusionPatternShaderSource::textures = {
|
const std::array<TextureInfo, 1> FillExtrusionPatternShaderSource::textures = {
|
||||||
TextureInfo{0, idFillExtrusionImageTexture},
|
TextureInfo{0, idFillExtrusionImageTexture},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// Fill extrusion pattern instanced
|
||||||
|
|
||||||
|
using FillExtrusionPatternInstancedShaderSource =
|
||||||
|
ShaderSource<BuiltIn::FillExtrusionPatternInstancedShader, gfx::Backend::Type::Metal>;
|
||||||
|
|
||||||
|
const std::array<AttributeInfo, 1> FillExtrusionPatternInstancedShaderSource::attributes = {
|
||||||
|
AttributeInfo{0, gfx::AttributeDataType::Short2, fillExtrusionUBOCount + 0, idFillExtrusionPosVertexAttribute},
|
||||||
|
};
|
||||||
|
const std::array<AttributeInfo, 6> FillExtrusionPatternInstancedShaderSource::instanceAttributes = {
|
||||||
|
AttributeInfo{1, gfx::AttributeDataType::Short2, fillExtrusionUBOCount + 1, idFillExtrusionOutlinePosAttribute},
|
||||||
|
AttributeInfo{2, gfx::AttributeDataType::UShort2, fillExtrusionUBOCount + 1, idFillExtrusionEdDiscardAttribute},
|
||||||
|
|
||||||
|
// Data driven
|
||||||
|
AttributeInfo{3, gfx::AttributeDataType::Float, fillExtrusionUBOCount + 2, idFillExtrusionBaseVertexAttribute},
|
||||||
|
AttributeInfo{4, gfx::AttributeDataType::Float, fillExtrusionUBOCount + 2, idFillExtrusionHeightVertexAttribute},
|
||||||
|
AttributeInfo{
|
||||||
|
5, gfx::AttributeDataType::UShort4, fillExtrusionUBOCount + 2, idFillExtrusionPatternFromVertexAttribute},
|
||||||
|
AttributeInfo{
|
||||||
|
6, gfx::AttributeDataType::UShort4, fillExtrusionUBOCount + 2, idFillExtrusionPatternToVertexAttribute},
|
||||||
|
};
|
||||||
|
const std::array<TextureInfo, 1> FillExtrusionPatternInstancedShaderSource::textures = {
|
||||||
|
TextureInfo{0, idFillExtrusionImageTexture},
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace shaders
|
} // namespace shaders
|
||||||
} // namespace mbgl
|
} // namespace mbgl
|
||||||
|
|||||||
@@ -183,13 +183,12 @@ std::optional<size_t> ShaderProgram::getSamplerLocation(const size_t id) const {
|
|||||||
return (id < textureBindings.size()) ? textureBindings[id] : std::nullopt;
|
return (id < textureBindings.size()) ? textureBindings[id] : std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShaderProgram::initAttribute(const shaders::AttributeInfo& info) {
|
void ShaderProgram::initVertexAttribute(const shaders::AttributeInfo& info) {
|
||||||
const auto index = static_cast<int>(info.index);
|
const auto index = static_cast<int>(info.index);
|
||||||
const auto bufferIndex = static_cast<int>(info.bufferIndex);
|
const auto bufferIndex = static_cast<int>(info.bufferIndex);
|
||||||
#if !defined(NDEBUG)
|
#if !defined(NDEBUG)
|
||||||
// Indexes must be unique, if there's a conflict check the `attributes` array in the shader
|
// Indexes must be unique, if there's a conflict check the `attributes` array in the shader
|
||||||
vertexAttributes.visitAttributes([&](const gfx::VertexAttribute& attrib) { assert(attrib.getIndex() != index); });
|
vertexAttributes.visitAttributes([&](const gfx::VertexAttribute& attrib) { assert(attrib.getIndex() != index); });
|
||||||
instanceAttributes.visitAttributes([&](const gfx::VertexAttribute& attrib) { assert(attrib.getIndex() != index); });
|
|
||||||
#endif
|
#endif
|
||||||
vertexAttributes.set(info.id, index, info.dataType, bufferIndex);
|
vertexAttributes.set(info.id, index, info.dataType, bufferIndex);
|
||||||
}
|
}
|
||||||
@@ -201,7 +200,7 @@ void ShaderProgram::initInstanceAttribute(const shaders::AttributeInfo& info) {
|
|||||||
#if !defined(NDEBUG)
|
#if !defined(NDEBUG)
|
||||||
// Indexes must not be reused by regular attributes or uniform blocks
|
// Indexes must not be reused by regular attributes or uniform blocks
|
||||||
// More than one instance attribute can have the same index, if they share the block
|
// More than one instance attribute can have the same index, if they share the block
|
||||||
vertexAttributes.visitAttributes([&](const gfx::VertexAttribute& attrib) { assert(attrib.getIndex() != index); });
|
instanceAttributes.visitAttributes([&](const gfx::VertexAttribute& attrib) { assert(attrib.getIndex() != index); });
|
||||||
#endif
|
#endif
|
||||||
instanceAttributes.set(info.id, index, info.dataType, bufferIndex);
|
instanceAttributes.set(info.id, index, info.dataType, bufferIndex);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,9 @@ MBGL_DEFINE_ENUM(BuiltIn,
|
|||||||
{BuiltIn::FillOutlinePatternShader, "FillOutlinePatternShader"},
|
{BuiltIn::FillOutlinePatternShader, "FillOutlinePatternShader"},
|
||||||
{BuiltIn::FillOutlineTriangulatedShader, "FillOutlineTriangulatedShader"},
|
{BuiltIn::FillOutlineTriangulatedShader, "FillOutlineTriangulatedShader"},
|
||||||
{BuiltIn::FillExtrusionShader, "FillExtrusionShader"},
|
{BuiltIn::FillExtrusionShader, "FillExtrusionShader"},
|
||||||
|
{BuiltIn::FillExtrusionInstancedShader, "FillExtrusionInstancedShader"},
|
||||||
{BuiltIn::FillExtrusionPatternShader, "FillExtrusionPatternShader"},
|
{BuiltIn::FillExtrusionPatternShader, "FillExtrusionPatternShader"},
|
||||||
|
{BuiltIn::FillExtrusionPatternInstancedShader, "FillExtrusionPatternInstancedShader"},
|
||||||
{BuiltIn::HeatmapShader, "HeatmapShader"},
|
{BuiltIn::HeatmapShader, "HeatmapShader"},
|
||||||
{BuiltIn::HeatmapTextureShader, "HeatmapTextureShader"},
|
{BuiltIn::HeatmapTextureShader, "HeatmapTextureShader"},
|
||||||
{BuiltIn::HillshadePrepareShader, "HillshadePrepareShader"},
|
{BuiltIn::HillshadePrepareShader, "HillshadePrepareShader"},
|
||||||
|
|||||||
@@ -204,7 +204,7 @@ void Drawable::upload(gfx::UploadPass& uploadPass_) {
|
|||||||
if (buildInstanceBuffer) {
|
if (buildInstanceBuffer) {
|
||||||
// Build instance attribute buffers
|
// Build instance attribute buffers
|
||||||
std::vector<std::unique_ptr<gfx::VertexBufferResource>> instanceBuffers;
|
std::vector<std::unique_ptr<gfx::VertexBufferResource>> instanceBuffers;
|
||||||
auto instanceBindings_ = uploadPass.buildAttributeBindings(instanceAttributes->getMaxCount(),
|
auto instanceBindings_ = uploadPass.buildAttributeBindings(instanceAttributes->getMinCount(),
|
||||||
/*vertexType*/ gfx::AttributeDataType::Byte,
|
/*vertexType*/ gfx::AttributeDataType::Byte,
|
||||||
/*vertexAttributeIndex=*/-1,
|
/*vertexAttributeIndex=*/-1,
|
||||||
/*vertexData=*/{},
|
/*vertexData=*/{},
|
||||||
@@ -290,7 +290,7 @@ void Drawable::draw(PaintParameters& parameters) const {
|
|||||||
|
|
||||||
impl->pipelineInfo.setRenderable(renderPass_.getDescriptor().renderable);
|
impl->pipelineInfo.setRenderable(renderPass_.getDescriptor().renderable);
|
||||||
|
|
||||||
const auto instances = instanceAttributes ? instanceAttributes->getMaxCount() : 1;
|
const auto instances = instanceAttributes ? instanceAttributes->getMinCount() : 1;
|
||||||
|
|
||||||
for (const auto& seg : impl->segments) {
|
for (const auto& seg : impl->segments) {
|
||||||
const auto& segment = seg->getSegment();
|
const auto& segment = seg->getSegment();
|
||||||
|
|||||||
@@ -944,7 +944,7 @@ void Drawable::draw(PaintParameters& parameters) const {
|
|||||||
const auto& segment = static_cast<DrawSegment&>(*seg_);
|
const auto& segment = static_cast<DrawSegment&>(*seg_);
|
||||||
const auto& mlSegment = segment.getSegment();
|
const auto& mlSegment = segment.getSegment();
|
||||||
if (mlSegment.indexLength > 0) {
|
if (mlSegment.indexLength > 0) {
|
||||||
const uint32_t instanceCount = instanceAttributes ? static_cast<uint32_t>(instanceAttributes->getMaxCount())
|
const uint32_t instanceCount = instanceAttributes ? static_cast<uint32_t>(instanceAttributes->getMinCount())
|
||||||
: 1;
|
: 1;
|
||||||
const uint32_t indexOffset = static_cast<uint32_t>(mlSegment.indexOffset);
|
const uint32_t indexOffset = static_cast<uint32_t>(mlSegment.indexOffset);
|
||||||
const int32_t baseVertex = static_cast<int32_t>(mlSegment.vertexOffset);
|
const int32_t baseVertex = static_cast<int32_t>(mlSegment.vertexOffset);
|
||||||
|
|||||||
@@ -140,7 +140,9 @@ TEST(OrderIndependentHash, Shaders) {
|
|||||||
BuiltIn::FillOutlinePatternShader,
|
BuiltIn::FillOutlinePatternShader,
|
||||||
BuiltIn::FillOutlineTriangulatedShader,
|
BuiltIn::FillOutlineTriangulatedShader,
|
||||||
BuiltIn::FillExtrusionShader,
|
BuiltIn::FillExtrusionShader,
|
||||||
|
BuiltIn::FillExtrusionInstancedShader,
|
||||||
BuiltIn::FillExtrusionPatternShader,
|
BuiltIn::FillExtrusionPatternShader,
|
||||||
|
BuiltIn::FillExtrusionPatternInstancedShader,
|
||||||
BuiltIn::HeatmapShader,
|
BuiltIn::HeatmapShader,
|
||||||
BuiltIn::HeatmapTextureShader,
|
BuiltIn::HeatmapTextureShader,
|
||||||
BuiltIn::HillshadePrepareShader,
|
BuiltIn::HillshadePrepareShader,
|
||||||
|
|||||||
Reference in New Issue
Block a user