#include #include #include #include #include #include #include #include #include #include #include namespace mbgl { using namespace style; using namespace shaders; #if !defined(NDEBUG) constexpr auto BackgroundPatternShaderName = "BackgroundPatternShader"; #endif static const StringIdentity idBackgroundDrawableUBOName = StringIndexer::get("BackgroundDrawableUBO"); static const StringIdentity idBackgroundLayerUBOName = StringIndexer::get("BackgroundLayerUBO"); static const StringIdentity idTexUniformName = StringIndexer::get("u_image"); void BackgroundLayerTweaker::execute(LayerGroupBase& layerGroup, const RenderTree&, const PaintParameters& parameters) { const auto& state = parameters.state; auto& context = parameters.context; if (layerGroup.empty()) { return; } #if defined(DEBUG) const auto label = layerGroup.getName() + "-update-uniforms"; const auto debugGroup = parameters.encoder->createDebugGroup(label.c_str()); #endif const auto& evaluated = static_cast(*evaluatedProperties).evaluated; const auto& crossfade = static_cast(*evaluatedProperties).crossfade; const bool hasPattern = !evaluated.get().to.empty(); const auto imagePosA = hasPattern ? parameters.patternAtlas.getPattern(evaluated.get().from.id()) : std::nullopt; const auto imagePosB = hasPattern ? parameters.patternAtlas.getPattern(evaluated.get().to.id()) : std::nullopt; if (hasPattern && (!imagePosA || !imagePosB)) { // The pattern isn't valid, disable the whole thing. layerGroup.setEnabled(false); return; } layerGroup.setEnabled(true); std::optional samplerLocation{}; layerGroup.visitDrawables([&](gfx::Drawable& drawable) { assert(drawable.getTileID()); if (!drawable.getTileID() || !checkTweakDrawable(drawable)) { return; } // We assume that drawables don't change between pattern and non-pattern. const auto& shader = drawable.getShader(); assert(hasPattern == (shader == context.getGenericShader(parameters.shaders, std::string(BackgroundPatternShaderName)))); const UnwrappedTileID tileID = drawable.getTileID()->toUnwrapped(); const auto matrix = parameters.matrixForTile(tileID); const BackgroundDrawableUBO drawableUBO = {/* .matrix = */ util::cast(matrix)}; auto& uniforms = drawable.mutableUniformBuffers(); uniforms.createOrUpdate(idBackgroundDrawableUBOName, &drawableUBO, context); if (hasPattern) { if (!samplerLocation.has_value()) { samplerLocation = shader->getSamplerLocation(idTexUniformName); if (const auto& tex = parameters.patternAtlas.texture()) { tex->setSamplerConfiguration( {gfx::TextureFilterType::Linear, gfx::TextureWrapType::Clamp, gfx::TextureWrapType::Clamp}); } } if (samplerLocation.has_value()) { if (const auto& tex = parameters.patternAtlas.texture()) { drawable.setTexture(tex, samplerLocation.value()); } } // from BackgroundPatternProgram::layoutUniformValues const int32_t tileSizeAtNearestZoom = static_cast( util::tileSize_D * state.zoomScale(state.getIntegerZoom() - tileID.canonical.z)); const int32_t pixelX = static_cast( tileSizeAtNearestZoom * (tileID.canonical.x + tileID.wrap * state.zoomScale(tileID.canonical.z))); const int32_t pixelY = tileSizeAtNearestZoom * tileID.canonical.y; const Size atlasSize = parameters.patternAtlas.getPixelSize(); const auto pixToTile = tileID.pixelsToTileUnits(1.0f, state.getIntegerZoom()); const BackgroundPatternLayerUBO layerUBO = { /* .pattern_tl_a = */ util::cast(imagePosA->tl()), /* .pattern_br_a = */ util::cast(imagePosA->br()), /* .pattern_tl_b = */ util::cast(imagePosB->tl()), /* .pattern_br_b = */ util::cast(imagePosB->br()), /* .texsize = */ {static_cast(atlasSize.width), static_cast(atlasSize.height)}, /* .pattern_size_a = */ imagePosA->displaySize(), /* .pattern_size_b = */ imagePosB->displaySize(), /* .pixel_coord_upper = */ {static_cast(pixelX >> 16), static_cast(pixelY >> 16)}, /* .pixel_coord_lower = */ {static_cast(pixelX & 0xFFFF), static_cast(pixelY & 0xFFFF)}, /* .tile_units_to_pixels = */ (pixToTile != 0) ? 1.0f / pixToTile : 0.0f, /* .scale_a = */ crossfade.fromScale, /* .scale_b = */ crossfade.toScale, /* .mix = */ crossfade.t, /* .opacity = */ evaluated.get(), /* .pad = */ 0, }; uniforms.createOrUpdate(idBackgroundLayerUBOName, &layerUBO, context); } else { // UBOs can be shared if (!backgroundLayerBuffer) { const BackgroundLayerUBO layerUBO = {/* .color = */ evaluated.get(), /* .opacity = */ evaluated.get(), /* .pad = */ 0, 0, 0}; backgroundLayerBuffer = context.createUniformBuffer(&layerUBO, sizeof(layerUBO)); } uniforms.addOrReplace(idBackgroundLayerUBOName, backgroundLayerBuffer); } }); } } // namespace mbgl