From 6aa804f7e2f2c91d57e838cca9ddaf14d8101462 Mon Sep 17 00:00:00 2001 From: Alex Cristici Date: Tue, 5 May 2026 19:24:17 +0300 Subject: [PATCH] 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 Co-authored-by: Adrian Cojocaru --- bazel/core.bzl | 2 + cmake/opengl.cmake | 2 + include/mbgl/gfx/vertex_attribute.hpp | 4 +- .../shaders/gl/fill_extrusion_instanced.hpp | 16 + .../gl/fill_extrusion_pattern_instanced.hpp | 16 + include/mbgl/shaders/layer_ubo.hpp | 1 + include/mbgl/shaders/mtl/fill_extrusion.hpp | 399 +++++++++++++++++- include/mbgl/shaders/mtl/shader_group.hpp | 6 +- include/mbgl/shaders/mtl/shader_program.hpp | 2 +- include/mbgl/shaders/shader_defines.hpp | 6 + include/mbgl/shaders/shader_manifest.hpp | 2 + include/mbgl/shaders/shader_source.hpp | 2 + shaders/manifest.json | 14 + src/mbgl/gfx/vertex_attribute.cpp | 9 +- src/mbgl/mtl/drawable.cpp | 136 +++--- src/mbgl/mtl/renderer_backend.cpp | 2 + .../buckets/fill_extrusion_bucket.cpp | 20 + .../buckets/fill_extrusion_bucket.hpp | 17 + .../layers/render_fill_extrusion_layer.cpp | 158 ++++++- .../layers/render_fill_extrusion_layer.hpp | 15 +- .../renderer/layers/render_raster_layer.cpp | 2 +- .../renderer/layers/render_raster_layer.hpp | 5 +- src/mbgl/renderer/render_static_data.cpp | 133 +++--- src/mbgl/renderer/render_static_data.hpp | 13 +- src/mbgl/shaders/attributes.hpp | 8 +- src/mbgl/shaders/mtl/fill_extrusion.cpp | 65 ++- src/mbgl/shaders/mtl/shader_program.cpp | 5 +- src/mbgl/shaders/shader_source.cpp | 2 + src/mbgl/vulkan/drawable.cpp | 4 +- src/mbgl/webgpu/drawable.cpp | 2 +- test/util/hash.test.cpp | 2 + 31 files changed, 889 insertions(+), 181 deletions(-) create mode 100644 include/mbgl/shaders/gl/fill_extrusion_instanced.hpp create mode 100644 include/mbgl/shaders/gl/fill_extrusion_pattern_instanced.hpp diff --git a/bazel/core.bzl b/bazel/core.bzl index 21cf75e4b..185d99dd0 100644 --- a/bazel/core.bzl +++ b/bazel/core.bzl @@ -94,7 +94,9 @@ MLN_GENERATED_OPENGL_SHADER_HEADERS = [ "include/mbgl/shaders/gl/fill_outline_pattern.hpp", "include/mbgl/shaders/gl/fill_outline_triangulated.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_instanced.hpp", "include/mbgl/shaders/gl/heatmap.hpp", "include/mbgl/shaders/gl/heatmap_texture.hpp", "include/mbgl/shaders/gl/hillshade_prepare.hpp", diff --git a/cmake/opengl.cmake b/cmake/opengl.cmake index f9b23e00f..f2990c439 100644 --- a/cmake/opengl.cmake +++ b/cmake/opengl.cmake @@ -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_triangulated.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_instanced.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/hillshade_prepare.hpp diff --git a/include/mbgl/gfx/vertex_attribute.hpp b/include/mbgl/gfx/vertex_attribute.hpp index 0d1b954f8..182be3191 100644 --- a/include/mbgl/gfx/vertex_attribute.hpp +++ b/include/mbgl/gfx/vertex_attribute.hpp @@ -301,8 +301,8 @@ public: /// Sum of element strides, and the total size of a vertex in the buffer std::size_t getTotalSize() const; - /// Get the largest count value of the attribute elements - std::size_t getMaxCount() const; + /// Get the smallest count value of the attribute elements + std::size_t getMinCount() const; /// Get a attribute element. /// Returns a pointer to the element on success, or null if the attribute doesn't exists. diff --git a/include/mbgl/shaders/gl/fill_extrusion_instanced.hpp b/include/mbgl/shaders/gl/fill_extrusion_instanced.hpp new file mode 100644 index 000000000..3d7509797 --- /dev/null +++ b/include/mbgl/shaders/gl/fill_extrusion_instanced.hpp @@ -0,0 +1,16 @@ +// Generated code, do not modify this file! +#pragma once +#include + +namespace mbgl { +namespace shaders { + +template <> +struct ShaderSource { + static constexpr const char* name = "FillExtrusionInstancedShader"; + static constexpr const char* vertex = R"()"; + static constexpr const char* fragment = R"()"; +}; + +} // namespace shaders +} // namespace mbgl diff --git a/include/mbgl/shaders/gl/fill_extrusion_pattern_instanced.hpp b/include/mbgl/shaders/gl/fill_extrusion_pattern_instanced.hpp new file mode 100644 index 000000000..5695264d0 --- /dev/null +++ b/include/mbgl/shaders/gl/fill_extrusion_pattern_instanced.hpp @@ -0,0 +1,16 @@ +// Generated code, do not modify this file! +#pragma once +#include + +namespace mbgl { +namespace shaders { + +template <> +struct ShaderSource { + static constexpr const char* name = "FillExtrusionPatternInstancedShader"; + static constexpr const char* vertex = R"()"; + static constexpr const char* fragment = R"()"; +}; + +} // namespace shaders +} // namespace mbgl diff --git a/include/mbgl/shaders/layer_ubo.hpp b/include/mbgl/shaders/layer_ubo.hpp index 6477029c5..a6d6a5a27 100644 --- a/include/mbgl/shaders/layer_ubo.hpp +++ b/include/mbgl/shaders/layer_ubo.hpp @@ -78,6 +78,7 @@ enum { }; #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 mbgl diff --git a/include/mbgl/shaders/mtl/fill_extrusion.hpp b/include/mbgl/shaders/mtl/fill_extrusion.hpp index 6b182ad64..6b8ba851d 100644 --- a/include/mbgl/shaders/mtl/fill_extrusion.hpp +++ b/include/mbgl/shaders/mtl/fill_extrusion.hpp @@ -69,7 +69,7 @@ struct ShaderSource { static constexpr auto vertexMainFunction = "vertexMain"; static constexpr auto fragmentMainFunction = "fragmentMain"; - static const std::array attributes; + static const std::array attributes; static constexpr std::array instanceAttributes{}; static const std::array textures; @@ -78,16 +78,15 @@ struct ShaderSource { struct VertexStage { short2 pos [[attribute(0)]]; - short4 normal_ed [[attribute(1)]]; #if !defined(HAS_UNIFORM_u_color) - float4 color [[attribute(2)]]; + float4 color [[attribute(1)]]; #endif #if !defined(HAS_UNIFORM_u_base) - float base [[attribute(3)]]; + float base [[attribute(2)]]; #endif #if !defined(HAS_UNIFORM_u_height) - float height [[attribute(4)]]; + float height [[attribute(3)]]; #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); #endif - const float3 normal = float3(vertx.normal_ed.xyz); - const float t = glMod(normal.x, 2.0); + const float3 normal = float3(0.0, 0.0, 1.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 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)); // 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 { + static constexpr auto name = "FillExtrusionInstancedShader"; + static constexpr auto vertexMainFunction = "vertexMain"; + static constexpr auto fragmentMainFunction = "fragmentMain"; + + static const std::array attributes; + static const std::array instanceAttributes; + static const std::array 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 // narrower with lower light intensity and with lighter/brighter surface colors @@ -190,7 +331,7 @@ struct ShaderSource attributes; + static const std::array attributes; static constexpr std::array instanceAttributes{}; static const std::array textures; @@ -199,19 +340,18 @@ struct ShaderSource +struct ShaderSource { + static constexpr auto name = "FillExtrusionPatternInstancedShader"; + static constexpr auto vertexMainFunction = "vertexMain"; + static constexpr auto fragmentMainFunction = "fragmentMain"; + + static const std::array attributes; + static const std::array instanceAttributes; + static const std::array 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 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 mbgl diff --git a/include/mbgl/shaders/mtl/shader_group.hpp b/include/mbgl/shaders/mtl/shader_group.hpp index a1dee00ae..bd0b26e5e 100644 --- a/include/mbgl/shaders/mtl/shader_group.hpp +++ b/include/mbgl/shaders/mtl/shader_group.hpp @@ -77,11 +77,13 @@ public: using ShaderClass = shaders::ShaderSource; for (const auto& attrib : ShaderClass::attributes) { if (!propertiesAsUniforms.second.count(attrib.id)) { - shader->initAttribute(attrib); + shader->initVertexAttribute(attrib); } } for (const auto& attrib : ShaderClass::instanceAttributes) { - shader->initInstanceAttribute(attrib); + if (!propertiesAsUniforms.second.count(attrib.id)) { + shader->initInstanceAttribute(attrib); + } } for (const auto& texture : ShaderClass::textures) { shader->initTexture(texture); diff --git a/include/mbgl/shaders/mtl/shader_program.hpp b/include/mbgl/shaders/mtl/shader_program.hpp index f534bc4e9..73407922b 100644 --- a/include/mbgl/shaders/mtl/shader_program.hpp +++ b/include/mbgl/shaders/mtl/shader_program.hpp @@ -65,7 +65,7 @@ public: const gfx::VertexAttributeArray& getInstanceAttributes() const override { return instanceAttributes; } - void initAttribute(const shaders::AttributeInfo&); + void initVertexAttribute(const shaders::AttributeInfo&); void initInstanceAttribute(const shaders::AttributeInfo&); void initTexture(const shaders::TextureInfo&); diff --git a/include/mbgl/shaders/shader_defines.hpp b/include/mbgl/shaders/shader_defines.hpp index 52fe25b0f..11e26d610 100644 --- a/include/mbgl/shaders/shader_defines.hpp +++ b/include/mbgl/shaders/shader_defines.hpp @@ -422,7 +422,13 @@ enum { enum { idFillExtrusionPosVertexAttribute, + +#if MLN_USE_FILL_EXTRUSION_INSTANCING + idFillExtrusionOutlinePosAttribute, + idFillExtrusionEdDiscardAttribute, +#else idFillExtrusionNormalEdVertexAttribute, +#endif // Data driven idFillExtrusionBaseVertexAttribute, diff --git a/include/mbgl/shaders/shader_manifest.hpp b/include/mbgl/shaders/shader_manifest.hpp index 715f61a63..488f015e0 100644 --- a/include/mbgl/shaders/shader_manifest.hpp +++ b/include/mbgl/shaders/shader_manifest.hpp @@ -19,7 +19,9 @@ #include #include #include +#include #include +#include #include #include #include diff --git a/include/mbgl/shaders/shader_source.hpp b/include/mbgl/shaders/shader_source.hpp index 339f0025f..4fdf0c951 100644 --- a/include/mbgl/shaders/shader_source.hpp +++ b/include/mbgl/shaders/shader_source.hpp @@ -25,7 +25,9 @@ enum class BuiltIn { FillOutlinePatternShader, FillOutlineTriangulatedShader, FillExtrusionShader, + FillExtrusionInstancedShader, FillExtrusionPatternShader, + FillExtrusionPatternInstancedShader, HeatmapShader, HeatmapTextureShader, HillshadePrepareShader, diff --git a/shaders/manifest.json b/shaders/manifest.json index 4303fb829..eeb839226 100644 --- a/shaders/manifest.json +++ b/shaders/manifest.json @@ -109,6 +109,13 @@ "glsl_frag": "fill_extrusion.fragment.glsl", "uses_ubos": true }, + { + "name": "FillExtrusionInstancedShader", + "header": "fill_extrusion_instanced", + "glsl_vert": "_empty.glsl", + "glsl_frag": "_empty.glsl", + "uses_ubos": true + }, { "name": "FillExtrusionPatternShader", "header": "fill_extrusion_pattern", @@ -116,6 +123,13 @@ "glsl_frag": "fill_extrusion_pattern.fragment.glsl", "uses_ubos": true }, + { + "name": "FillExtrusionPatternInstancedShader", + "header": "fill_extrusion_pattern_instanced", + "glsl_vert": "_empty.glsl", + "glsl_frag": "_empty.glsl", + "uses_ubos": true + }, { "name": "HeatmapShader", "header": "heatmap", diff --git a/src/mbgl/gfx/vertex_attribute.cpp b/src/mbgl/gfx/vertex_attribute.cpp index c69b4135f..4fbf4d3af 100644 --- a/src/mbgl/gfx/vertex_attribute.cpp +++ b/src/mbgl/gfx/vertex_attribute.cpp @@ -115,10 +115,11 @@ std::size_t VertexAttributeArray::getTotalSize() const { }); } -std::size_t VertexAttributeArray::getMaxCount() const { - return std::accumulate(attrs.begin(), attrs.end(), std::size_t(0), [](const auto acc, const auto& attr) { - return std::max(acc, (attr ? attr->getCount() : 0)); - }); +std::size_t VertexAttributeArray::getMinCount() const { + return std::accumulate( + attrs.begin(), attrs.end(), std::numeric_limits::max(), [](const auto acc, const auto& attr) { + return std::min(acc, (attr ? attr->getCount() : std::numeric_limits::max())); + }); } void VertexAttributeArray::clear() { diff --git a/src/mbgl/mtl/drawable.cpp b/src/mbgl/mtl/drawable.cpp index 9969807de..e7a9e1549 100644 --- a/src/mbgl/mtl/drawable.cpp +++ b/src/mbgl/mtl/drawable.cpp @@ -279,7 +279,7 @@ void Drawable::draw(PaintParameters& parameters) const { const auto primitiveType = getPrimitiveType(mode.type); constexpr auto indexType = MTL::IndexType::IndexTypeUInt16; 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; const NS::UInteger indexOffset = static_cast(indexSize * mlSegment.indexOffset); // in bytes, not indexes @@ -549,10 +549,12 @@ void Drawable::upload(gfx::UploadPass& uploadPass_) { impl->indexes->setDirty(false); } - const bool buildAttribs = !impl->vertexDesc || !vertexAttributes || !attributeUpdateTime || - vertexAttributes->isModifiedAfter(*attributeUpdateTime); + const bool buildVertexAttribs = !impl->vertexDesc || !vertexAttributes || !attributeUpdateTime || + vertexAttributes->isModifiedAfter(*attributeUpdateTime); + const bool buildInstanceAttribs = instanceAttributes && (!attributeUpdateTime || + instanceAttributes->isModifiedAfter(*attributeUpdateTime)); - if (buildAttribs) { + if (buildVertexAttribs || buildInstanceAttribs) { #if !defined(NDEBUG) const auto debugGroup = uploadPass.createDebugGroup(debugLabel(*this)); #endif @@ -575,8 +577,27 @@ void Drawable::upload(gfx::UploadPass& uploadPass_) { vertexAttributes->visitAttributes([](gfx::VertexAttribute& attrib) { attrib.setDirty(false); }); - if (impl->attributeBindings != attributeBindings_) { + // Build instance attribute buffers + gfx::AttributeBindingArray instanceBindings_; + if (instanceAttributes) { + std::vector> 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->instanceBindings = std::move(instanceBindings_); // hash std::size_t hash{0}; @@ -584,46 +605,52 @@ void Drawable::upload(gfx::UploadPass& uploadPass_) { // Create a layout descriptor for each attribute auto vertDesc = NS::RetainPtr(MTL::VertexDescriptor::vertexDescriptor()); - NS::UInteger index = 0; - for (auto& binding : impl->attributeBindings) { - if (!binding) { - assert("Missing attribute binding"); - index += 1; - continue; - } - - if (!binding->vertexBufferResource && !impl->noBindingBuffer) { - if (const auto& buf = context.getEmptyVertexBuffer()) { - impl->noBindingBuffer = buf.get(); + const auto applyBindings = [&](const gfx::AttributeBindingArray& attributeBindings, + MTL::VertexStepFunction stepFunction) { + NS::UInteger index = 0; + for (auto& binding : attributeBindings) { + if (!binding) { + assert("Missing attribute binding"); + index += 1; + continue; } + + 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(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(binding->vertexStride)); + layoutDesc->setStepFunction(binding->vertexBufferResource ? stepFunction + : MTL::VertexStepFunctionConstant); + layoutDesc->setStepRate(binding->vertexBufferResource ? 1 : 0); + } else { + assert(layoutDesc->stride() == static_cast(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(binding->vertexBufferResource))); + + index += 1; } + }; - const auto& attribDesc = vertDesc->attributes()->object(index); - attribDesc->setBufferIndex(binding->bufferIndex); - attribDesc->setOffset(static_cast(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(binding->vertexStride)); - layoutDesc->setStepFunction(binding->vertexBufferResource ? MTL::VertexStepFunctionPerVertex - : MTL::VertexStepFunctionConstant); - layoutDesc->setStepRate(binding->vertexBufferResource ? 1 : 0); - } else { - assert(layoutDesc->stride() == static_cast(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(binding->vertexBufferResource))); - - index += 1; - } + applyBindings(impl->attributeBindings, MTL::VertexStepFunctionPerVertex); + applyBindings(impl->instanceBindings, MTL::VertexStepFunctionPerInstance); impl->vertexDesc = std::move(vertDesc); 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> 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( textures.begin(), textures.end(), [](const auto& texture) { return texture && texture->needsUpload(); }); diff --git a/src/mbgl/mtl/renderer_backend.cpp b/src/mbgl/mtl/renderer_backend.cpp index 9fc8a8af1..d9cba9158 100644 --- a/src/mbgl/mtl/renderer_backend.cpp +++ b/src/mbgl/mtl/renderer_backend.cpp @@ -117,7 +117,9 @@ void RendererBackend::initShaders(gfx::ShaderRegistry& shaders, const ProgramPar shaders::BuiltIn::FillOutlinePatternShader, shaders::BuiltIn::FillOutlineTriangulatedShader, shaders::BuiltIn::FillExtrusionShader, + shaders::BuiltIn::FillExtrusionInstancedShader, shaders::BuiltIn::FillExtrusionPatternShader, + shaders::BuiltIn::FillExtrusionPatternInstancedShader, shaders::BuiltIn::HeatmapShader, shaders::BuiltIn::HeatmapTextureShader, shaders::BuiltIn::HillshadeShader, diff --git a/src/mbgl/renderer/buckets/fill_extrusion_bucket.cpp b/src/mbgl/renderer/buckets/fill_extrusion_bucket.cpp index 535abc8f1..2d64117fb 100644 --- a/src/mbgl/renderer/buckets/fill_extrusion_bucket.cpp +++ b/src/mbgl/renderer/buckets/fill_extrusion_bucket.cpp @@ -101,6 +101,25 @@ void FillExtrusionBucket::addFeature(const GeometryTileFeature& feature, for (std::size_t i = 0; i < nVertices; 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(p1); + const auto d2 = convertPoint(p2); + + const size_t dist = util::dist(d1, d2); + if (edgeDistance + dist > static_cast(std::numeric_limits::max())) { + edgeDistance = 0; + } + + edgeDistance += dist; + } +#else vertices.emplace_back( FillExtrusionBucket::layoutVertex(p1, 0, 0, 1, 1, static_cast(edgeDistance))); flatIndices.emplace_back(triangleIndex); @@ -141,6 +160,7 @@ void FillExtrusionBucket::addFeature(const GeometryTileFeature& feature, triangleSegment.vertexLength += 4; triangleSegment.indexLength += 6; } +#endif } } diff --git a/src/mbgl/renderer/buckets/fill_extrusion_bucket.hpp b/src/mbgl/renderer/buckets/fill_extrusion_bucket.hpp index f6c3c7b19..e270c9fa2 100644 --- a/src/mbgl/renderer/buckets/fill_extrusion_bucket.hpp +++ b/src/mbgl/renderer/buckets/fill_extrusion_bucket.hpp @@ -15,7 +15,13 @@ class BucketParameters; class RenderFillExtrusionLayer; using FillExtrusionBinders = PaintPropertyBinders; +using FillExtrusionStaticVertex = gfx::Vertex>; + +#if MLN_USE_FILL_EXTRUSION_INSTANCING +using FillExtrusionLayoutVertex = gfx::Vertex>; +#else using FillExtrusionLayoutVertex = gfx::Vertex>; +#endif class FillExtrusionBucket final : public Bucket { public: @@ -43,6 +49,16 @@ public: void update(const FeatureStates&, const GeometryTileLayer&, const std::string&, const ImagePositions&) override; +#if MLN_USE_FILL_EXTRUSION_INSTANCING + static FillExtrusionLayoutVertex layoutVertex(Point 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(isDiscarded) + }}; + } +#else static FillExtrusionLayoutVertex layoutVertex( Point p, double nx, double ny, double nz, unsigned short t, uint16_t e) { const auto factor = pow(2, 13); @@ -57,6 +73,7 @@ public: // The edgedistance attribute is used for wrapping fill_extrusion patterns static_cast(e)}}}; } +#endif static std::array lightColor(const EvaluatedLight&); static std::array lightPosition(const EvaluatedLight&, const TransformState&); diff --git a/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp b/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp index c09779a96..ba0678b38 100644 --- a/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp +++ b/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp @@ -163,6 +163,36 @@ void RenderFillExtrusionLayer::update(gfx::ShaderRegistry& shaders, 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(RenderStaticData::fillExtrusionVertices()); + } + if (!staticDataIndices) { + staticDataIndices = std::make_shared(RenderStaticData::fillExtrusionTriangleIndices()); + } + if (!staticDataSegments) { + staticDataSegments = std::make_shared(RenderStaticData::fillExtrusionSegments()); + } + + const auto& instancedShaderGroup = hasPattern ? fillExtrusionPatternInstancedGroup : fillExtrusionInstancedGroup; + if (!instancedShaderGroup) { + removeAllDrawables(); + return; + } + + const auto instanceVertexCount = staticDataVertices->elements(); + std::unique_ptr instancedDepthBuilder; + std::unique_ptr instancedColorBuilder; + StringIDSetsPair instancePropertiesAsUniforms; +#endif + StringIDSetsPair propertiesAsUniforms; for (const RenderTile& tile : *renderTiles) { const auto& tileID = tile.getOverscaledTileID(); @@ -222,6 +252,31 @@ void RenderFillExtrusionLayer::update(gfx::ShaderRegistry& shaders, 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( + binders, evaluated, instancePropertiesAsUniforms, idFillExtrusionBaseVertexAttribute); + + const auto instancedShader = std::static_pointer_cast( + instancedShaderGroup->getOrCreateShader(context, instancePropertiesAsUniforms)); + if (!instancedShader) { + continue; + } +#endif + // The non-pattern path in `render()` only uses two-pass rendering if there's translucency. // The pattern path always uses two passes. const auto doDepthPass = (!opaque || hasPattern); @@ -272,6 +327,15 @@ void RenderFillExtrusionLayer::update(gfx::ShaderRegistry& shaders, if (colorBuilder) { 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), gfx::AttributeDataType::Short2); } +#if !MLN_USE_FILL_EXTRUSION_INSTANCING if (const auto& attr = vertexAttrs->set(idFillExtrusionNormalEdVertexAttribute)) { attr->setSharedRawData(bucket.sharedVertices, offsetof(FillExtrusionLayoutVertex, a2), @@ -289,6 +354,7 @@ void RenderFillExtrusionLayer::update(gfx::ShaderRegistry& shaders, sizeof(FillExtrusionLayoutVertex), gfx::AttributeDataType::Short4); } +#endif if (doDepthPass) { depthBuilder->setRawVertices({}, vertexCount, gfx::AttributeDataType::Short2); @@ -321,11 +387,101 @@ void RenderFillExtrusionLayer::update(gfx::ShaderRegistry& shaders, ++stats.drawablesAdded; } }; - if (doDepthPass) { finish(*depthBuilder); } 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(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 } } diff --git a/src/mbgl/renderer/layers/render_fill_extrusion_layer.hpp b/src/mbgl/renderer/layers/render_fill_extrusion_layer.hpp index f39bcc3fe..354d9af8c 100644 --- a/src/mbgl/renderer/layers/render_fill_extrusion_layer.hpp +++ b/src/mbgl/renderer/layers/render_fill_extrusion_layer.hpp @@ -1,9 +1,9 @@ #pragma once #include +#include #include #include -#include namespace mbgl { @@ -40,7 +40,18 @@ private: gfx::ShaderGroupPtr fillExtrusionGroup; gfx::ShaderGroupPtr fillExtrusionPatternGroup; - std::unique_ptr renderTexture; + +#if MLN_USE_FILL_EXTRUSION_INSTANCING + gfx::ShaderGroupPtr fillExtrusionInstancedGroup; + gfx::ShaderGroupPtr fillExtrusionPatternInstancedGroup; + + using FillExtrusionVertexVector = gfx::VertexVector; + using TriangleIndexVector = gfx::IndexVector; + + std::shared_ptr staticDataVertices; + std::shared_ptr staticDataIndices; + std::shared_ptr staticDataSegments; +#endif }; } // namespace mbgl diff --git a/src/mbgl/renderer/layers/render_raster_layer.cpp b/src/mbgl/renderer/layers/render_raster_layer.cpp index 10d1848ad..15cd975a1 100644 --- a/src/mbgl/renderer/layers/render_raster_layer.cpp +++ b/src/mbgl/renderer/layers/render_raster_layer.cpp @@ -141,7 +141,7 @@ void RenderRasterLayer::update(gfx::ShaderRegistry& shaders, staticDataIndices = std::make_shared(RenderStaticData::quadTriangleIndices()); } if (!staticDataSegments) { - staticDataSegments = std::make_shared(RenderStaticData::rasterSegments()); + staticDataSegments = std::make_shared(RenderStaticData::rasterSegments()); } const auto createBuilder = [&] { diff --git a/src/mbgl/renderer/layers/render_raster_layer.hpp b/src/mbgl/renderer/layers/render_raster_layer.hpp index fcffd8461..ac397bdd5 100644 --- a/src/mbgl/renderer/layers/render_raster_layer.hpp +++ b/src/mbgl/renderer/layers/render_raster_layer.hpp @@ -61,9 +61,8 @@ private: using TriangleIndexVectorPtr = std::shared_ptr; TriangleIndexVectorPtr staticDataIndices; - using RasterSegmentVector = SegmentVector; - using RasterSegmentVectorPtr = std::shared_ptr; - std::shared_ptr staticDataSegments; + using SegmentVectorPtr = std::shared_ptr; + SegmentVectorPtr staticDataSegments; }; } // namespace mbgl diff --git a/src/mbgl/renderer/render_static_data.cpp b/src/mbgl/renderer/render_static_data.cpp index f94328c35..f116bd86d 100644 --- a/src/mbgl/renderer/render_static_data.cpp +++ b/src/mbgl/renderer/render_static_data.cpp @@ -5,54 +5,86 @@ namespace mbgl { -gfx::VertexVector> RenderStaticData::tileVertices() { - gfx::VertexVector> result; - result.emplace_back(gfx::Vertex({{{0, 0}}})); - result.emplace_back(gfx::Vertex({{{util::EXTENT, 0}}})); - result.emplace_back(gfx::Vertex({{{0, util::EXTENT}}})); - result.emplace_back(gfx::Vertex({{{util::EXTENT, util::EXTENT}}})); - return result; -} - -gfx::IndexVector RenderStaticData::quadTriangleIndices() { - gfx::IndexVector result; - result.emplace_back(0, 1, 2); - result.emplace_back(1, 2, 3); - return result; -} - -gfx::IndexVector RenderStaticData::tileLineStripIndices() { - gfx::IndexVector 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 RenderStaticData::rasterVertices() { - gfx::VertexVector 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 RenderStaticData::heatmapTextureVertices() { - gfx::VertexVector 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&& shaders_) : shaders(std::move(shaders_)), 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> RenderStaticData::tileVertices() { + gfx::VertexVector> vertices; + vertices.emplace_back(gfx::Vertex({{{0, 0}}})); + vertices.emplace_back(gfx::Vertex({{{util::EXTENT, 0}}})); + vertices.emplace_back(gfx::Vertex({{{0, util::EXTENT}}})); + vertices.emplace_back(gfx::Vertex({{{util::EXTENT, util::EXTENT}}})); + return vertices; +} + +gfx::VertexVector RenderStaticData::rasterVertices() { + gfx::VertexVector 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 RenderStaticData::heatmapTextureVertices() { + gfx::VertexVector 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 RenderStaticData::fillExtrusionVertices() { + gfx::VertexVector 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 RenderStaticData::quadTriangleIndices() { + gfx::IndexVector indices; + indices.emplace_back(0, 1, 2); + indices.emplace_back(1, 2, 3); + return indices; +} + +gfx::IndexVector RenderStaticData::tileLineStripIndices() { + gfx::IndexVector 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 RenderStaticData::fillExtrusionTriangleIndices() { + gfx::IndexVector 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 segments; segments.emplace_back(0, 0, 4, 6); @@ -77,15 +109,10 @@ SegmentVector RenderStaticData::heatmapTextureSegments() { return segments; } -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; - } +SegmentVector RenderStaticData::fillExtrusionSegments() { + SegmentVector segments; + segments.emplace_back(0, 0, 4, 6); + return segments; } } // namespace mbgl diff --git a/src/mbgl/renderer/render_static_data.hpp b/src/mbgl/renderer/render_static_data.hpp index a35bd6f98..5fbefea30 100644 --- a/src/mbgl/renderer/render_static_data.hpp +++ b/src/mbgl/renderer/render_static_data.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -23,22 +24,22 @@ public: void upload(gfx::UploadPass&); std::optional>> tileVertexBuffer; - std::optional> rasterVertexBuffer; - std::optional> heatmapTextureVertexBuffer; - std::optional quadTriangleIndexBuffer; - std::optional tileBorderIndexBuffer; static gfx::VertexVector> tileVertices(); - static gfx::IndexVector quadTriangleIndices(); - static gfx::IndexVector tileLineStripIndices(); static gfx::VertexVector rasterVertices(); static gfx::VertexVector heatmapTextureVertices(); + static gfx::VertexVector fillExtrusionVertices(); + + static gfx::IndexVector quadTriangleIndices(); + static gfx::IndexVector tileLineStripIndices(); + static gfx::IndexVector fillExtrusionTriangleIndices(); static SegmentVector tileTriangleSegments(); static SegmentVector tileBorderSegments(); static SegmentVector rasterSegments(); static SegmentVector heatmapTextureSegments(); + static SegmentVector fillExtrusionSegments(); std::optional> depthRenderbuffer; bool has3D = false; diff --git a/src/mbgl/shaders/attributes.hpp b/src/mbgl/shaders/attributes.hpp index df8f7cef6..976a2a375 100644 --- a/src/mbgl/shaders/attributes.hpp +++ b/src/mbgl/shaders/attributes.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include namespace mbgl { 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, anchor_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(uint16_t, 2, placed); MBGL_DEFINE_ATTRIBUTE(uint16_t, 3, size); MBGL_DEFINE_ATTRIBUTE(float, 1, offset); 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 struct data { using Type = gfx::AttributeType; diff --git a/src/mbgl/shaders/mtl/fill_extrusion.cpp b/src/mbgl/shaders/mtl/fill_extrusion.cpp index a4186077e..42732dec1 100644 --- a/src/mbgl/shaders/mtl/fill_extrusion.cpp +++ b/src/mbgl/shaders/mtl/fill_extrusion.cpp @@ -9,37 +9,80 @@ namespace shaders { using FillExtrusionShaderSource = ShaderSource; -const std::array FillExtrusionShaderSource::attributes = { +const std::array FillExtrusionShaderSource::attributes = { AttributeInfo{0, gfx::AttributeDataType::Short2, fillExtrusionUBOCount + 0, idFillExtrusionPosVertexAttribute}, - AttributeInfo{1, gfx::AttributeDataType::Short4, fillExtrusionUBOCount + 0, idFillExtrusionNormalEdVertexAttribute}, // Data driven - AttributeInfo{2, gfx::AttributeDataType::Float4, fillExtrusionUBOCount + 1, idFillExtrusionColorVertexAttribute}, - AttributeInfo{3, gfx::AttributeDataType::Float, fillExtrusionUBOCount + 1, idFillExtrusionBaseVertexAttribute}, - AttributeInfo{4, gfx::AttributeDataType::Float, fillExtrusionUBOCount + 1, idFillExtrusionHeightVertexAttribute}, + AttributeInfo{1, gfx::AttributeDataType::Float4, fillExtrusionUBOCount + 1, idFillExtrusionColorVertexAttribute}, + AttributeInfo{2, gfx::AttributeDataType::Float, fillExtrusionUBOCount + 1, idFillExtrusionBaseVertexAttribute}, + AttributeInfo{3, gfx::AttributeDataType::Float, fillExtrusionUBOCount + 1, idFillExtrusionHeightVertexAttribute}, }; const std::array FillExtrusionShaderSource::textures = {}; +// +// Fill extrusion instanced + +using FillExtrusionInstancedShaderSource = + ShaderSource; + +const std::array FillExtrusionInstancedShaderSource::attributes = { + AttributeInfo{0, gfx::AttributeDataType::Short2, fillExtrusionUBOCount + 0, idFillExtrusionPosVertexAttribute}, +}; +const std::array 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 FillExtrusionInstancedShaderSource::textures = {}; + // // Fill extrusion pattern using FillExtrusionPatternShaderSource = ShaderSource; -const std::array FillExtrusionPatternShaderSource::attributes = { +const std::array FillExtrusionPatternShaderSource::attributes = { AttributeInfo{0, gfx::AttributeDataType::Short2, fillExtrusionUBOCount + 0, idFillExtrusionPosVertexAttribute}, - AttributeInfo{1, gfx::AttributeDataType::Short4, fillExtrusionUBOCount + 0, idFillExtrusionNormalEdVertexAttribute}, // Data driven - AttributeInfo{2, gfx::AttributeDataType::Float, fillExtrusionUBOCount + 1, idFillExtrusionBaseVertexAttribute}, - AttributeInfo{3, gfx::AttributeDataType::Float, fillExtrusionUBOCount + 1, idFillExtrusionHeightVertexAttribute}, + AttributeInfo{1, gfx::AttributeDataType::Float, fillExtrusionUBOCount + 1, idFillExtrusionBaseVertexAttribute}, + AttributeInfo{2, gfx::AttributeDataType::Float, fillExtrusionUBOCount + 1, idFillExtrusionHeightVertexAttribute}, AttributeInfo{ - 4, gfx::AttributeDataType::UShort4, fillExtrusionUBOCount + 1, idFillExtrusionPatternFromVertexAttribute}, + 3, gfx::AttributeDataType::UShort4, fillExtrusionUBOCount + 1, idFillExtrusionPatternFromVertexAttribute}, AttributeInfo{ - 5, gfx::AttributeDataType::UShort4, fillExtrusionUBOCount + 1, idFillExtrusionPatternToVertexAttribute}, + 4, gfx::AttributeDataType::UShort4, fillExtrusionUBOCount + 1, idFillExtrusionPatternToVertexAttribute}, }; const std::array FillExtrusionPatternShaderSource::textures = { TextureInfo{0, idFillExtrusionImageTexture}, }; +// +// Fill extrusion pattern instanced + +using FillExtrusionPatternInstancedShaderSource = + ShaderSource; + +const std::array FillExtrusionPatternInstancedShaderSource::attributes = { + AttributeInfo{0, gfx::AttributeDataType::Short2, fillExtrusionUBOCount + 0, idFillExtrusionPosVertexAttribute}, +}; +const std::array 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 FillExtrusionPatternInstancedShaderSource::textures = { + TextureInfo{0, idFillExtrusionImageTexture}, +}; + } // namespace shaders } // namespace mbgl diff --git a/src/mbgl/shaders/mtl/shader_program.cpp b/src/mbgl/shaders/mtl/shader_program.cpp index d6015f77a..778d318c4 100644 --- a/src/mbgl/shaders/mtl/shader_program.cpp +++ b/src/mbgl/shaders/mtl/shader_program.cpp @@ -183,13 +183,12 @@ std::optional ShaderProgram::getSamplerLocation(const size_t id) const { 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(info.index); const auto bufferIndex = static_cast(info.bufferIndex); #if !defined(NDEBUG) // 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); }); - instanceAttributes.visitAttributes([&](const gfx::VertexAttribute& attrib) { assert(attrib.getIndex() != index); }); #endif vertexAttributes.set(info.id, index, info.dataType, bufferIndex); } @@ -201,7 +200,7 @@ void ShaderProgram::initInstanceAttribute(const shaders::AttributeInfo& info) { #if !defined(NDEBUG) // 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 - vertexAttributes.visitAttributes([&](const gfx::VertexAttribute& attrib) { assert(attrib.getIndex() != index); }); + instanceAttributes.visitAttributes([&](const gfx::VertexAttribute& attrib) { assert(attrib.getIndex() != index); }); #endif instanceAttributes.set(info.id, index, info.dataType, bufferIndex); } diff --git a/src/mbgl/shaders/shader_source.cpp b/src/mbgl/shaders/shader_source.cpp index 9db6f08c7..f7093882b 100644 --- a/src/mbgl/shaders/shader_source.cpp +++ b/src/mbgl/shaders/shader_source.cpp @@ -24,7 +24,9 @@ MBGL_DEFINE_ENUM(BuiltIn, {BuiltIn::FillOutlinePatternShader, "FillOutlinePatternShader"}, {BuiltIn::FillOutlineTriangulatedShader, "FillOutlineTriangulatedShader"}, {BuiltIn::FillExtrusionShader, "FillExtrusionShader"}, + {BuiltIn::FillExtrusionInstancedShader, "FillExtrusionInstancedShader"}, {BuiltIn::FillExtrusionPatternShader, "FillExtrusionPatternShader"}, + {BuiltIn::FillExtrusionPatternInstancedShader, "FillExtrusionPatternInstancedShader"}, {BuiltIn::HeatmapShader, "HeatmapShader"}, {BuiltIn::HeatmapTextureShader, "HeatmapTextureShader"}, {BuiltIn::HillshadePrepareShader, "HillshadePrepareShader"}, diff --git a/src/mbgl/vulkan/drawable.cpp b/src/mbgl/vulkan/drawable.cpp index 507b8ac84..92de8aba2 100644 --- a/src/mbgl/vulkan/drawable.cpp +++ b/src/mbgl/vulkan/drawable.cpp @@ -204,7 +204,7 @@ void Drawable::upload(gfx::UploadPass& uploadPass_) { if (buildInstanceBuffer) { // Build instance attribute buffers std::vector> instanceBuffers; - auto instanceBindings_ = uploadPass.buildAttributeBindings(instanceAttributes->getMaxCount(), + auto instanceBindings_ = uploadPass.buildAttributeBindings(instanceAttributes->getMinCount(), /*vertexType*/ gfx::AttributeDataType::Byte, /*vertexAttributeIndex=*/-1, /*vertexData=*/{}, @@ -290,7 +290,7 @@ void Drawable::draw(PaintParameters& parameters) const { 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) { const auto& segment = seg->getSegment(); diff --git a/src/mbgl/webgpu/drawable.cpp b/src/mbgl/webgpu/drawable.cpp index d93599f71..e93ad831d 100644 --- a/src/mbgl/webgpu/drawable.cpp +++ b/src/mbgl/webgpu/drawable.cpp @@ -944,7 +944,7 @@ void Drawable::draw(PaintParameters& parameters) const { const auto& segment = static_cast(*seg_); const auto& mlSegment = segment.getSegment(); if (mlSegment.indexLength > 0) { - const uint32_t instanceCount = instanceAttributes ? static_cast(instanceAttributes->getMaxCount()) + const uint32_t instanceCount = instanceAttributes ? static_cast(instanceAttributes->getMinCount()) : 1; const uint32_t indexOffset = static_cast(mlSegment.indexOffset); const int32_t baseVertex = static_cast(mlSegment.vertexOffset); diff --git a/test/util/hash.test.cpp b/test/util/hash.test.cpp index 3303805ea..0f100b2d8 100644 --- a/test/util/hash.test.cpp +++ b/test/util/hash.test.cpp @@ -140,7 +140,9 @@ TEST(OrderIndependentHash, Shaders) { BuiltIn::FillOutlinePatternShader, BuiltIn::FillOutlineTriangulatedShader, BuiltIn::FillExtrusionShader, + BuiltIn::FillExtrusionInstancedShader, BuiltIn::FillExtrusionPatternShader, + BuiltIn::FillExtrusionPatternInstancedShader, BuiltIn::HeatmapShader, BuiltIn::HeatmapTextureShader, BuiltIn::HillshadePrepareShader,