Use drawables for location indicator layer (#2836)

Co-authored-by: Bart Louwers <bart.louwers@gmail.com>
This commit is contained in:
Adrian Cojocaru
2024-10-08 19:20:12 +03:00
committed by GitHub
parent 37bc0234da
commit 156872f4c8
22 changed files with 857 additions and 86 deletions

View File

@@ -203,6 +203,8 @@ if(MLN_DRAWABLE_RENDERER)
${PROJECT_SOURCE_DIR}/src/mbgl/renderer/layers/hillshade_prepare_layer_tweaker.hpp
${PROJECT_SOURCE_DIR}/src/mbgl/renderer/layers/line_layer_tweaker.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/renderer/layers/line_layer_tweaker.hpp
${PROJECT_SOURCE_DIR}/src/mbgl/renderer/layers/location_indicator_layer_tweaker.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/renderer/layers/location_indicator_layer_tweaker.hpp
${PROJECT_SOURCE_DIR}/src/mbgl/renderer/layers/raster_layer_tweaker.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/renderer/layers/raster_layer_tweaker.hpp
${PROJECT_SOURCE_DIR}/src/mbgl/renderer/layers/symbol_layer_tweaker.cpp
@@ -1135,6 +1137,7 @@ if(MLN_WITH_OPENGL)
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/background_layer_ubo.hpp
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/circle_layer_ubo.hpp
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/collision_layer_ubo.hpp
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/common_ubo.hpp
${PROJECT_SOURCE_DIR}/include/mbgl/style/layers/custom_drawable_layer.hpp
${PROJECT_SOURCE_DIR}/include/mbgl/layermanager/custom_drawable_layer_factory.hpp
${PROJECT_SOURCE_DIR}/include/mbgl/shaders/debug_layer_ubo.hpp
@@ -1351,6 +1354,7 @@ if(MLN_WITH_VULKAN)
${PROJECT_SOURCE_DIR}/src/mbgl/shaders/vulkan/circle.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/shaders/vulkan/clipping_mask.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/shaders/vulkan/collision.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/shaders/vulkan/common.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/shaders/vulkan/debug.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/shaders/vulkan/fill.cpp
${PROJECT_SOURCE_DIR}/src/mbgl/shaders/vulkan/heatmap.cpp

View File

@@ -999,6 +999,7 @@ MLN_DRAWABLES_HEADERS = [
"include/mbgl/shaders/background_layer_ubo.hpp",
"include/mbgl/shaders/circle_layer_ubo.hpp",
"include/mbgl/shaders/collision_layer_ubo.hpp",
"include/mbgl/shaders/common_ubo.hpp",
"include/mbgl/shaders/custom_drawable_layer_ubo.hpp",
"include/mbgl/shaders/debug_layer_ubo.hpp",
"include/mbgl/shaders/fill_layer_ubo.hpp",

View File

@@ -24,6 +24,9 @@ public:
TextureWrapType wrapU{TextureWrapType::Clamp};
/// Wrapping behavior along V coordinate
TextureWrapType wrapV{TextureWrapType::Clamp};
uint8_t maxAnisotropy{1};
bool mipmapped{false};
};
public:

View File

@@ -0,0 +1,20 @@
#pragma once
#include <mbgl/shaders/layer_ubo.hpp>
namespace mbgl {
namespace shaders {
struct alignas(16) CommonUBO {
std::array<float, 4 * 4> matrix;
Color color;
};
static_assert(sizeof(CommonUBO) % 16 == 0);
enum {
idCommonUBO = globalUBOCount,
commonUBOCount
};
} // namespace shaders
} // namespace mbgl

View File

@@ -1,5 +1,6 @@
#pragma once
#include <mbgl/shaders/common_ubo.hpp>
#include <mbgl/shaders/background_layer_ubo.hpp>
#include <mbgl/shaders/circle_layer_ubo.hpp>
#include <mbgl/shaders/collision_layer_ubo.hpp>
@@ -31,6 +32,7 @@ static constexpr auto maxUBOCountPerShader = std::max({static_cast<size_t>(backg
static_cast<size_t>(circleUBOCount),
static_cast<size_t>(clippingMaskUBOCount),
static_cast<size_t>(collisionUBOCount),
static_cast<size_t>(commonUBOCount),
static_cast<size_t>(customSymbolUBOCount),
static_cast<size_t>(debugUBOCount),
static_cast<size_t>(fillUBOCount),
@@ -62,6 +64,11 @@ enum {
collisionTextureCount
};
enum {
idCommonTexture,
commonTextureCount
};
enum {
idCustomSymbolImageTexture,
customSymbolTextureCount
@@ -114,6 +121,7 @@ static constexpr auto maxTextureCountPerShader = std::max({static_cast<size_t>(b
static_cast<size_t>(circleTextureCount),
static_cast<size_t>(clippingMaskTextureCount),
static_cast<size_t>(collisionTextureCount),
static_cast<size_t>(commonTextureCount),
static_cast<size_t>(customSymbolTextureCount),
static_cast<size_t>(debugTextureCount),
static_cast<size_t>(fillTextureCount),
@@ -159,6 +167,12 @@ enum {
collisionVertexAttributeCount
};
enum {
idCommonPosVertexAttribute,
idCommonTexVertexAttribute,
commonVertexAttributeCount
};
enum {
idCustomSymbolPosVertexAttribute,
idCustomSymbolTexVertexAttribute,
@@ -276,6 +290,7 @@ static constexpr auto maxVertexAttributeCountPerShader = std::max({
static_cast<size_t>(circleVertexAttributeCount),
static_cast<size_t>(clippingMaskVertexAttributeCount),
static_cast<size_t>(collisionVertexAttributeCount),
static_cast<size_t>(commonVertexAttributeCount),
static_cast<size_t>(customSymbolVertexAttributeCount),
static_cast<size_t>(debugVertexAttributeCount),
static_cast<size_t>(fillVertexAttributeCount),

View File

@@ -14,6 +14,8 @@ enum class BuiltIn {
CircleShader,
CollisionBoxShader,
CollisionCircleShader,
CommonShader,
CommonTexturedShader,
DebugShader,
FillShader,
FillOutlineShader,

View File

@@ -1,6 +1,7 @@
#pragma once
#include <mbgl/shaders/shader_source.hpp>
#include <mbgl/shaders/vulkan/shader_program.hpp>
namespace mbgl {
namespace shaders {
@@ -100,5 +101,82 @@ layout(set = 0, binding = 0) uniform GlobalPaintParamsUBO {
)";
};
template <>
struct ShaderSource<BuiltIn::CommonShader, gfx::Backend::Type::Vulkan> {
static constexpr const char* name = "CommonShader";
static const std::array<UniformBlockInfo, 1> uniforms;
static const std::array<AttributeInfo, 1> attributes;
static constexpr std::array<AttributeInfo, 0> instanceAttributes{};
static constexpr std::array<TextureInfo, 0> textures{};
static constexpr auto vertex = R"(
layout(location = 0) in vec2 in_position;
layout(set = 0, binding = 1) uniform CommonUBO {
mat4 matrix;
vec4 color;
} ubo;
void main() {
gl_Position = ubo.matrix * vec4(in_position, 0, 1);
gl_Position.y *= -1.0;
}
)";
static constexpr auto fragment = R"(
layout(location = 0) out vec4 out_color;
layout(set = 0, binding = 1) uniform CommonUBO {
mat4 matrix;
vec4 color;
} ubo;
void main() {
out_color = ubo.color;
}
)";
};
template <>
struct ShaderSource<BuiltIn::CommonTexturedShader, gfx::Backend::Type::Vulkan> {
static constexpr const char* name = "CommonTexturedShader";
static const std::array<UniformBlockInfo, 1> uniforms;
static const std::array<AttributeInfo, 2> attributes;
static constexpr std::array<AttributeInfo, 0> instanceAttributes{};
static const std::array<TextureInfo, 1> textures;
static constexpr auto vertex = R"(
layout(location = 0) in vec2 in_position;
layout(location = 1) in vec2 in_texcoord;
layout(set = 0, binding = 1) uniform CommonUBO {
mat4 matrix;
vec4 color;
} ubo;
layout(location = 0) out vec2 frag_uv;
void main() {
gl_Position = ubo.matrix * vec4(in_position, 0, 1);
gl_Position.y *= -1.0;
frag_uv = in_texcoord;
}
)";
static constexpr auto fragment = R"(
layout(location = 0) in vec2 frag_uv;
layout(location = 0) out vec4 out_color;
layout(set = 1, binding = 0) uniform sampler2D image_sampler;
void main() {
out_color = texture(image_sampler, frag_uv);
}
)";
};
} // namespace shaders
} // namespace mbgl

View File

@@ -96,6 +96,9 @@ private:
void transitionToShaderReadLayout(const vk::UniqueCommandBuffer&);
void transitionToGeneralLayout(const vk::UniqueCommandBuffer&);
uint32_t getMipLevels() const;
void generateMips(const vk::UniqueCommandBuffer& buffer);
private:
Context& context;

View File

@@ -69,6 +69,8 @@ LayerManagerDefault::LayerManagerDefault() {
#if !defined(MBGL_LAYER_CUSTOM_DISABLE_ALL)
addLayerType(std::make_unique<CustomLayerFactory>());
#endif
#endif
#if defined(MLN_RENDER_BACKEND_OPENGL) || MLN_RENDER_BACKEND_VULKAN
#if !defined(MBGL_LAYER_LOCATION_INDICATOR_DISABLE_ALL)
addLayerType(std::make_unique<LocationIndicatorLayerFactory>());
#endif

View File

@@ -63,8 +63,7 @@
using namespace std::numbers;
#if defined(MLN_RENDER_BACKEND_OPENGL) && !defined(MBGL_LAYER_LOCATION_INDICATOR_DISABLE_ALL)
#include <mbgl/style/layers/location_indicator_layer.hpp>
#ifdef ENABLE_LOCATION_INDICATOR
namespace {
const std::string mbglPuckAssetsPath{MAPBOX_PUCK_ASSETS_PATH};
@@ -1244,7 +1243,7 @@ void GLFWView::toggleCustomSource() {
void GLFWView::toggleLocationIndicatorLayer() {
MLN_TRACE_FUNC();
#if defined(MLN_RENDER_BACKEND_OPENGL) && !defined(MBGL_LAYER_LOCATION_INDICATOR_DISABLE_ALL)
#ifdef ENABLE_LOCATION_INDICATOR
puck = static_cast<mbgl::style::LocationIndicatorLayer *>(map->getStyle().getLayer("puck"));
static const mbgl::LatLng puckLocation{35.683389, 139.76525}; // A location on the crossing of 4 tiles
if (puck == nullptr) {
@@ -1309,7 +1308,7 @@ using Nanoseconds = std::chrono::nanoseconds;
void GLFWView::onWillStartRenderingFrame() {
MLN_TRACE_FUNC();
#if defined(MLN_RENDER_BACKEND_OPENGL) && !defined(MBGL_LAYER_LOCATION_INDICATOR_DISABLE_ALL)
#ifdef ENABLE_LOCATION_INDICATOR
puck = static_cast<mbgl::style::LocationIndicatorLayer *>(map->getStyle().getLayer("puck"));
if (puck) {
uint64_t ns = mbgl::Clock::now().time_since_epoch().count();

View File

@@ -5,13 +5,19 @@
#include <mbgl/util/geometry.hpp>
#include <mbgl/util/run_loop.hpp>
#include <mbgl/util/timer.hpp>
#if defined(MLN_RENDER_BACKEND_OPENGL) && !defined(MBGL_LAYER_CUSTOM_DISABLE_ALL)
#include <mbgl/style/layers/location_indicator_layer.hpp>
#endif
#include <utility>
#include <optional>
#if (defined(MLN_RENDER_BACKEND_OPENGL) || defined(MLN_RENDER_BACKEND_VULKAN)) && \
!defined(MBGL_LAYER_CUSTOM_DISABLE_ALL)
#define ENABLE_LOCATION_INDICATOR
#endif
#ifdef ENABLE_LOCATION_INDICATOR
#include <mbgl/style/layers/location_indicator_layer.hpp>
#endif
struct GLFWwindow;
class GLFWBackend;
class GLFWRendererFrontend;
@@ -163,7 +169,7 @@ private:
mbgl::ResourceOptions mapResourceOptions;
mbgl::ClientOptions mapClientOptions;
#if defined(MLN_RENDER_BACKEND_OPENGL) && !defined(MBGL_LAYER_CUSTOM_DISABLE_ALL)
#ifdef ENABLE_LOCATION_INDICATOR
bool puckFollowsCameraCenter = false;
mbgl::style::LocationIndicatorLayer *puck = nullptr;
#endif

View File

@@ -0,0 +1,59 @@
#include <mbgl/renderer/layers/location_indicator_layer_tweaker.hpp>
#include <mbgl/renderer/layer_group.hpp>
#include <mbgl/renderer/paint_parameters.hpp>
#include <mbgl/renderer/layers/render_location_indicator_layer.hpp>
#include <mbgl/style/layers/location_indicator_layer_properties.hpp>
namespace mbgl {
void LocationIndicatorLayerTweaker::execute(LayerGroupBase& layerGroup, const PaintParameters& params) {
if (layerGroup.empty()) {
return;
}
const auto& props = static_cast<const style::LocationIndicatorLayerProperties&>(*evaluatedProperties);
const shaders::CommonUBO quadUBO = {/* .matrix */ util::cast<float>(projectionPuck),
/* .color */ Color::black()};
visitLayerGroupDrawables(layerGroup, [&](gfx::Drawable& drawable) {
auto& drawableUniforms = drawable.mutableUniformBuffers();
if (!drawable.getEnabled()) {
return;
}
switch (static_cast<RenderLocationIndicatorLayer::LocationIndicatorComponentType>(drawable.getType())) {
case RenderLocationIndicatorLayer::LocationIndicatorComponentType::Circle: {
shaders::CommonUBO circleUBO = {/* .matrix */ util::cast<float>(projectionCircle),
/* .color */ props.evaluated.get<style::AccuracyRadiusColor>()};
drawableUniforms.createOrUpdate(shaders::idCommonUBO, &circleUBO, params.context);
break;
}
case RenderLocationIndicatorLayer::LocationIndicatorComponentType::CircleOutline: {
shaders::CommonUBO circleUBO = {/* .matrix */ util::cast<float>(projectionCircle),
/* .color */ props.evaluated.get<style::AccuracyRadiusBorderColor>()};
drawableUniforms.createOrUpdate(shaders::idCommonUBO, &circleUBO, params.context);
break;
}
case RenderLocationIndicatorLayer::LocationIndicatorComponentType::PuckShadow:
[[fallthrough]];
case RenderLocationIndicatorLayer::LocationIndicatorComponentType::Puck:
[[fallthrough]];
case RenderLocationIndicatorLayer::LocationIndicatorComponentType::PuckHat:
drawableUniforms.createOrUpdate(shaders::idCommonUBO, &quadUBO, params.context);
break;
default:
assert(false);
break;
}
});
}
} // namespace mbgl

View File

@@ -0,0 +1,33 @@
#pragma once
#include <mbgl/renderer/layer_tweaker.hpp>
#include <mbgl/gfx/uniform_buffer.hpp>
#include <string>
namespace mbgl {
/**
Location indicator layer specific tweaker
*/
class LocationIndicatorLayerTweaker : public LayerTweaker {
public:
LocationIndicatorLayerTweaker(std::string id_,
Immutable<style::LayerProperties> properties,
const mbgl::mat4& projectionCircle_,
const mbgl::mat4& projectionPuck_)
: LayerTweaker(std::move(id_), properties),
projectionCircle(projectionCircle_),
projectionPuck(projectionPuck_) {}
public:
~LocationIndicatorLayerTweaker() override = default;
void execute(LayerGroupBase&, const PaintParameters& params) override;
private:
const mbgl::mat4& projectionCircle;
const mbgl::mat4& projectionPuck;
};
} // namespace mbgl

View File

@@ -24,6 +24,8 @@
#include <mbgl/style/layers/location_indicator_layer_impl.hpp>
#include <mbgl/style/layers/location_indicator_layer_properties.hpp>
#include <mbgl/util/mat4.hpp>
#include <mbgl/util/tile_cover.hpp>
#include <mbgl/gfx/context.hpp>
#include <mapbox/eternal.hpp>
#include <mbgl/renderer/image_manager.hpp>
@@ -38,11 +40,20 @@
#include <mbgl/gl/texture_resource.hpp>
#include <mbgl/gl/types.hpp>
#else
#endif
#define MBGL_CHECK_ERROR(x) \
while (0) { \
}
#if !MLN_RENDER_BACKEND_OPENGL
#include <mbgl/gfx/vertex_attribute.hpp>
#include <mbgl/renderer/render_static_data.hpp>
#include <mbgl/shaders/common_ubo.hpp>
#include <mbgl/gfx/drawable.hpp>
#include <mbgl/gfx/drawable_builder.hpp>
#include <mbgl/gfx/drawable_impl.hpp>
#include <mbgl/gfx/drawable_tweaker.hpp>
#include <mbgl/gfx/texture2d.hpp>
#include <mbgl/shaders/shader_defines.hpp>
#include <mbgl/renderer/layers/location_indicator_layer_tweaker.hpp>
#endif
@@ -86,20 +97,19 @@ struct LocationIndicatorRenderParameters {
std::string puckHatImagePath;
};
#if MLN_RENDER_BACKEND_OPENGL
class RenderLocationIndicatorImpl {
protected:
public:
struct vec2 {
GLfloat x = 0.0f;
GLfloat y = 0.0f;
float x = 0.0f;
float y = 0.0f;
vec2(GLfloat x_, GLfloat y_)
vec2(float x_, float y_)
: x(x_),
y(y_) {}
vec2() = default;
explicit vec2(const Point<double>& p)
: x(static_cast<GLfloat>(p.x)),
y(static_cast<GLfloat>(p.y)) {}
: x(static_cast<float>(p.x)),
y(static_cast<float>(p.y)) {}
vec2(const vec2& o) = default;
vec2(vec2&& o) = default;
vec2& operator=(vec2&& o) = default;
@@ -130,11 +140,12 @@ protected:
Point<double> toPoint() const { return {x, y}; }
friend vec2 operator-(const vec2& v) { return {-v.x, -v.y}; }
friend vec2 operator*(double a, const vec2& v) { return {GLfloat(v.x * a), GLfloat(v.y * a)}; }
friend vec2 operator*(double a, const vec2& v) { return {float(v.x * a), float(v.y * a)}; }
friend vec2 operator+(const vec2& v1, const vec2& v2) { return {v1.x + v2.x, v1.y + v2.y}; }
friend vec2 operator-(const vec2& v1, const vec2& v2) { return {v1.x - v2.x, v1.y - v2.y}; }
};
#if MLN_RENDER_BACKEND_OPENGL
struct Shader {
virtual ~Shader() { release(); }
void release() {
@@ -374,13 +385,6 @@ public:
float pixelRatio = 1.0f;
};
RenderLocationIndicatorImpl(std::string sourceLayer)
: ruler(0, mapbox::cheap_ruler::CheapRuler::Meters),
feature(std::make_shared<mbgl::Feature>()),
featureEnvelope(std::make_shared<mapbox::geometry::polygon<int64_t>>()) {
feature->sourceLayer = std::move(sourceLayer);
}
static bool hasAnisotropicFiltering() {
const auto* extensions = reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS));
GLenum error = glGetError();
@@ -414,7 +418,74 @@ public:
drawHat();
}
#endif
#if !MLN_RENDER_BACKEND_OPENGL
struct TextureInfo {
std::shared_ptr<gfx::Texture2D> texture;
std::optional<Immutable<style::Image::Impl>> image;
std::string id = "";
float pixelRatio = 1.0f;
size_t width = 0;
size_t height = 0;
bool dirty = false;
void assign(const Immutable<style::Image::Impl>& img) {
reset();
image = img;
id = img->id;
pixelRatio = img->pixelRatio;
width = img->image.size.width;
height = img->image.size.height;
}
void reset() {
texture.reset();
image.reset();
pixelRatio = 1.0f;
width = 0;
height = 0;
dirty = true;
}
};
bool setTextureFromImageID(const std::string& imagePath,
TextureInfo& textureInfo,
const mbgl::LocationIndicatorRenderParameters& params) {
bool updated = false;
const Immutable<style::Image::Impl>* sharedImage = nullptr;
if (!imagePath.empty() && params.imageManager) {
sharedImage = params.imageManager->getSharedImage(imagePath);
}
if (sharedImage) {
if (!textureInfo.texture || textureInfo.id != sharedImage->get()->id) {
textureInfo.assign(*sharedImage);
updated = true;
}
} else if (textureInfo.image) {
textureInfo.reset();
updated = true;
}
return updated;
}
#endif
public:
RenderLocationIndicatorImpl(std::string sourceLayer)
: ruler(0, mapbox::cheap_ruler::CheapRuler::Meters),
feature(std::make_shared<mbgl::Feature>()),
featureEnvelope(std::make_shared<mapbox::geometry::polygon<int64_t>>()) {
feature->sourceLayer = std::move(sourceLayer);
}
void release() {
#if MLN_RENDER_BACKEND_OPENGL
if (!simpleShader.program) return;
for (const auto& t : textures) t.second->release();
buffer.release();
@@ -424,6 +495,11 @@ public:
texCoordsBuffer.release();
simpleShader.release();
texturedShader.release();
#else
shadowDrawableInfo.reset();
puckDrawableInfo.reset();
hatDrawableInfo.reset();
#endif
}
void updatePuckGeometry(const mbgl::LocationIndicatorRenderParameters& params) {
@@ -439,9 +515,15 @@ public:
params.puckShadowScale != oldParams.puckShadowScale)
bearingChanged = true; // changes puck geometry but not necessarily the location
if (params.errorRadiusMeters != oldParams.errorRadiusMeters) radiusChanged = true;
#if MLN_RENDER_BACKEND_OPENGL
bearingChanged |= setTextureFromImageID(params.puckImagePath, texPuck, params);
bearingChanged |= setTextureFromImageID(params.puckShadowImagePath, texShadow, params);
bearingChanged |= setTextureFromImageID(params.puckHatImagePath, texPuckHat, params);
#else
bearingChanged |= setTextureFromImageID(params.puckShadowImagePath, shadowDrawableInfo.textureInfo, params);
bearingChanged |= setTextureFromImageID(params.puckImagePath, puckDrawableInfo.textureInfo, params);
bearingChanged |= setTextureFromImageID(params.puckHatImagePath, hatDrawableInfo.textureInfo, params);
#endif
projectionCircle = params.projectionMatrix;
const Point<double> positionMercator = project(params.puckPosition, *params.state);
@@ -469,7 +551,13 @@ public:
if (!dirtyFeature) return;
dirtyFeature = false;
featureEnvelope->clear();
#if MLN_RENDER_BACKEND_OPENGL
if (!texPuck || !texPuck->isValid()) return;
#else
if (!puckDrawableInfo.textureInfo.texture) return;
auto& puckGeometry = puckDrawableInfo.geometry;
#endif
feature->geometry = mapbox::geometry::point<double>{oldParams.puckPosition.latitude(),
oldParams.puckPosition.longitude()};
@@ -505,6 +593,11 @@ protected:
}
void updateRadius(const mbgl::LocationIndicatorRenderParameters& params) {
#if !MLN_RENDER_BACKEND_OPENGL
auto& circle = circleDrawableInfo.geometry;
circleDrawableInfo.dirty = true;
#endif
const TransformState& s = *params.state;
const auto numVtxCircumference = static_cast<unsigned long>(circle.size() - 1);
const float bearingStep = 360.0f /
@@ -617,6 +710,8 @@ protected:
util::clamp(pixelSizeToWorldSizeH(params.puckPosition, s), 0.8f, 100.1f) *
params.perspectiveCompensation; // Compensation factor for the perspective deformation
// ^ clamping this to 0.8 to avoid growing the puck too much close to the camera.
#if MLN_RENDER_BACKEND_OPENGL
const double shadowRadius = ((texShadow) ? texShadow->width / texShadow->pixelRatio : 0.0) *
params.puckShadowScale * M_SQRT2 * 0.5 *
horizontalScaleFactor; // Technically it's not the radius, but
@@ -625,6 +720,24 @@ protected:
M_SQRT2 * 0.5 * horizontalScaleFactor;
const double hatRadius = ((texPuckHat) ? texPuckHat->width / texPuckHat->pixelRatio : 0.0) *
params.puckHatScale * M_SQRT2 * 0.5 * horizontalScaleFactor;
#else
const double shadowScale = shadowDrawableInfo.textureInfo.width / shadowDrawableInfo.textureInfo.pixelRatio;
const double shadowRadius = shadowScale * params.puckShadowScale * M_SQRT2 * 0.5 * horizontalScaleFactor;
const double puckScale = puckDrawableInfo.textureInfo.width / puckDrawableInfo.textureInfo.pixelRatio;
const double puckRadius = puckScale * params.puckScale * M_SQRT2 * 0.5 * horizontalScaleFactor;
const double hatScale = hatDrawableInfo.textureInfo.width / hatDrawableInfo.textureInfo.pixelRatio;
const double hatRadius = hatScale * params.puckHatScale * M_SQRT2 * 0.5 * horizontalScaleFactor;
auto& shadowGeometry = shadowDrawableInfo.geometry;
auto& puckGeometry = puckDrawableInfo.geometry;
auto& hatGeometry = hatDrawableInfo.geometry;
shadowDrawableInfo.dirty = true;
puckDrawableInfo.dirty = true;
hatDrawableInfo.dirty = true;
#endif
for (unsigned long i = 0; i < 4; ++i) {
const auto b = util::wrap<float>(static_cast<float>(params.puckBearing) + bearings[i], 0.0f, 360.0f);
@@ -643,6 +756,7 @@ protected:
}
}
#if MLN_RENDER_BACKEND_OPENGL
void drawRadius(const mbgl::LocationIndicatorRenderParameters& params) {
if (!(params.errorRadiusMeters > 0.0) ||
(params.errorRadiusColor.a == 0.0 && params.errorRadiusBorderColor.a == 0.0))
@@ -694,6 +808,7 @@ protected:
void drawPuck() { drawQuad(puckBuffer, puckGeometry, texPuck); }
void drawHat() { drawQuad(hatBuffer, hatGeometry, texPuckHat); }
#endif
static LatLng screenCoordinateToLatLng(const ScreenCoordinate& p,
const TransformState& s,
@@ -703,6 +818,7 @@ protected:
return s.screenCoordinateToLatLng(flippedPoint, wrapMode);
}
#if MLN_RENDER_BACKEND_OPENGL
bool setTextureFromImageID(const std::string& imagePath,
std::shared_ptr<Texture>& texture,
const mbgl::LocationIndicatorRenderParameters& params) {
@@ -731,7 +847,6 @@ protected:
}
std::map<std::string, std::shared_ptr<Texture>> textures;
mapbox::cheap_ruler::CheapRuler ruler;
SimpleShader simpleShader;
TexturedShader texturedShader;
Buffer buffer;
@@ -749,6 +864,10 @@ protected:
std::array<vec2, 4> puckGeometry;
std::array<vec2, 4> hatGeometry;
std::array<vec2, 4> texCoords;
#endif
mapbox::cheap_ruler::CheapRuler ruler;
mbgl::mat4 translation;
mbgl::mat4 projectionCircle;
mbgl::mat4 projectionPuck;
@@ -760,34 +879,49 @@ protected:
bool initialized = false;
bool dirtyFeature = true;
public:
mbgl::LocationIndicatorRenderParameters parameters;
std::shared_ptr<mbgl::Feature> feature;
std::shared_ptr<mapbox::geometry::polygon<int64_t>> featureEnvelope;
static bool anisotropicFilteringAvailable;
};
bool RenderLocationIndicatorImpl::anisotropicFilteringAvailable = false;
#else
class RenderLocationIndicatorImpl {
public:
RenderLocationIndicatorImpl(std::string) {}
void release() {}
void updateFeature() {}
void updatePuckGeometry([[maybe_unused]] const mbgl::LocationIndicatorRenderParameters& params) {}
#if !MLN_RENDER_BACKEND_OPENGL
public:
mbgl::LocationIndicatorRenderParameters parameters;
std::shared_ptr<mbgl::Feature> feature;
std::shared_ptr<mapbox::geometry::polygon<int64_t>> featureEnvelope;
static bool anisotropicFilteringAvailable;
};
struct QuadDrawableInfo {
std::optional<std::reference_wrapper<gfx::Drawable>> drawable;
std::array<vec2, 4> geometry;
TextureInfo textureInfo;
bool dirty{false};
gfx::Drawable& getDrawable() { return drawable.value().get(); }
void reset() { textureInfo.reset(); }
};
struct CircleDrawableInfo {
std::optional<std::reference_wrapper<gfx::Drawable>> drawable;
std::optional<std::reference_wrapper<gfx::Drawable>> outlineDrawable;
std::array<vec2, 73> geometry;
TextureInfo textureInfo;
bool dirty{false};
gfx::Drawable& getDrawable() { return drawable.value().get(); }
void reset() { textureInfo.reset(); }
};
CircleDrawableInfo circleDrawableInfo;
QuadDrawableInfo shadowDrawableInfo;
QuadDrawableInfo puckDrawableInfo;
QuadDrawableInfo hatDrawableInfo;
const auto& getProjectionCircle() const { return projectionCircle; }
const auto& getProjectionPuck() const { return projectionPuck; }
bool RenderLocationIndicatorImpl::anisotropicFilteringAvailable = false;
#endif
public:
mbgl::LocationIndicatorRenderParameters parameters;
std::shared_ptr<mbgl::Feature> feature;
std::shared_ptr<mapbox::geometry::polygon<int64_t>> featureEnvelope;
static bool anisotropicFilteringAvailable;
};
bool RenderLocationIndicatorImpl::anisotropicFilteringAvailable = false;
using namespace style;
namespace {
@@ -805,7 +939,7 @@ RenderLocationIndicatorLayer::RenderLocationIndicatorLayer(Immutable<style::Loca
}
RenderLocationIndicatorLayer::~RenderLocationIndicatorLayer() {
if (!contextDestroyed) MBGL_CHECK_ERROR(renderImpl->release());
if (!contextDestroyed) renderImpl->release();
}
void RenderLocationIndicatorLayer::transition(const TransitionParameters& parameters) {
@@ -876,6 +1010,11 @@ void RenderLocationIndicatorLayer::prepare(const LayerPrepareParameters& p) {
renderImpl->updatePuckGeometry(renderImpl->parameters);
}
void RenderLocationIndicatorLayer::populateDynamicRenderFeatureIndex(DynamicFeatureIndex& index) const {
renderImpl->updateFeature();
if (!renderImpl->featureEnvelope->empty()) index.insert(renderImpl->feature, renderImpl->featureEnvelope);
}
#if MLN_RENDER_BACKEND_OPENGL
void RenderLocationIndicatorLayer::render(PaintParameters& paintParameters) {
auto& glContext = static_cast<gl::Context&>(paintParameters.context);
@@ -894,12 +1033,265 @@ void RenderLocationIndicatorLayer::render(PaintParameters& paintParameters) {
paintParameters.backend.getDefaultRenderable().getResource<gl::RenderableResource>().bind();
glContext.setDirtyState();
}
#endif
#if !MLN_RENDER_BACKEND_OPENGL
void RenderLocationIndicatorLayer::update(gfx::ShaderRegistry& shaders,
gfx::Context& context,
const TransformState&,
const std::shared_ptr<UpdateParameters>&,
const RenderTree&,
UniqueChangeRequestVec& changes) {
const auto drawPasses = RenderPass::Translucent;
// If the result is transparent or missing, just remove any existing drawables and stop
if (drawPasses == RenderPass::None) {
removeAllDrawables();
return;
}
if (!quadShader) {
quadShader = context.getGenericShader(shaders, "CommonTexturedShader");
}
if (!quadShader) {
removeAllDrawables();
return;
}
if (!circleShader) {
circleShader = context.getGenericShader(shaders, "CommonShader");
}
if (!circleShader) {
removeAllDrawables();
return;
}
if (!layerGroup) {
if (auto layerGroup_ = context.createLayerGroup(layerIndex, /*initialCapacity=*/4, getID())) {
setLayerGroup(std::move(layerGroup_), changes);
} else {
return;
}
}
if (!layerTweaker) {
layerTweaker = std::make_shared<LocationIndicatorLayerTweaker>(
getID(), evaluatedProperties, renderImpl->getProjectionCircle(), renderImpl->getProjectionPuck());
layerGroup->addLayerTweaker(layerTweaker);
}
auto* localLayerGroup = static_cast<LayerGroup*>(layerGroup.get());
if (localLayerGroup->getDrawableCount() == 0) {
// create empty drawable using a builder
const gfx::UniqueDrawableBuilder& builder = context.createDrawableBuilder(getID());
const auto createQuadGeometry = [&](gfx::Drawable& drawable, const auto& geometry) {
auto vertexAttrs = context.createVertexAttributeArray();
if (const auto& attr = vertexAttrs->set(
shaders::idCommonTexVertexAttribute, 0, gfx::AttributeDataType::Float2)) {
const std::array<RenderLocationIndicatorImpl::vec2, 4> texCoords = {
{{0.0f, 1.0f}, {0.0f, 0.0f}, {1.0f, 0.0f}, {1.0f, 1.0f}}};
auto geoDataPtr = reinterpret_cast<const uint8_t*>(texCoords.data());
auto geoDataSize = texCoords.size() * sizeof(RenderLocationIndicatorImpl::vec2);
std::vector<uint8_t> rawData;
std::copy(geoDataPtr, geoDataPtr + geoDataSize, std::back_inserter(rawData));
attr->setRawData(std::move(rawData));
}
drawable.setVertexAttributes(vertexAttrs);
gfx::IndexVector<gfx::Triangles> indices;
indices.emplace_back(0, 1, 2);
indices.emplace_back(0, 2, 3);
std::vector<gfx::Drawable::UniqueDrawSegment> drawSegments;
drawSegments.emplace_back(
builder->createSegment(gfx::Triangles(), SegmentBase(0, 0, geometry.size(), indices.elements())));
drawable.setIndexData(indices.vector(), std::move(drawSegments));
};
const auto createQuadDrawable = [&](RenderLocationIndicatorImpl::QuadDrawableInfo& drawableInfo,
std::string&& name,
LocationIndicatorComponentType type) {
auto& drawable = builder->getCurrentDrawable(true);
drawable->setType(static_cast<uint8_t>(type));
drawable->setName(name);
drawable->setRenderPass(drawPasses);
drawable->setDepthType(gfx::DepthMaskType::ReadWrite);
drawable->setColorMode(drawPasses == RenderPass::Translucent ? gfx::ColorMode::alphaBlended()
: gfx::ColorMode::unblended());
drawable->setShader(quadShader);
createQuadGeometry(*drawable, drawableInfo.geometry);
drawableInfo.drawable.emplace(*drawable);
// add drawable to layer group
localLayerGroup->addDrawable(std::move(drawable));
++stats.drawablesAdded;
};
// create circle drawable
const auto getCircleDrawable = [&](const auto& name, auto& vertexAttrib) -> gfx::UniqueDrawable& {
auto& drawable = builder->getCurrentDrawable(true);
drawable->setName(name);
drawable->setRenderPass(drawPasses);
drawable->setDepthType(gfx::DepthMaskType::ReadWrite);
drawable->setColorMode(drawPasses == RenderPass::Translucent ? gfx::ColorMode::alphaBlended()
: gfx::ColorMode::unblended());
drawable->setShader(circleShader);
drawable->setVertexAttributes(vertexAttrib);
return drawable;
};
const auto createCircleDrawable = [&]() {
// circle[0] is the center
const auto& geometry = renderImpl->circleDrawableInfo.geometry;
const uint16_t vertexCount = static_cast<uint16_t>(geometry.size());
auto vertexAttrib = context.createVertexAttributeArray();
{
auto& drawable = getCircleDrawable("locationAccuracyCircle", vertexAttrib);
drawable->setType(static_cast<uint8_t>(LocationIndicatorComponentType::Circle));
std::vector<gfx::Drawable::UniqueDrawSegment> drawSegments;
std::vector<uint16_t> indices;
for (uint16_t i = 1; i < vertexCount - 1; ++i) {
indices.insert(indices.end(), {0, i, static_cast<uint16_t>(i + 1)});
}
indices.insert(indices.end(), {0, static_cast<uint16_t>(vertexCount - 1), 1});
SegmentBase segment(0, 0, vertexCount, indices.size());
drawSegments.emplace_back(builder->createSegment(gfx::Triangles(), std::move(segment)));
drawable->setIndexData(indices, std::move(drawSegments));
renderImpl->circleDrawableInfo.drawable.emplace(*drawable);
localLayerGroup->addDrawable(std::move(drawable));
++stats.drawablesAdded;
}
{
auto& drawable = getCircleDrawable("locationAccuracyCircleOutline", vertexAttrib);
drawable->setType(static_cast<uint8_t>(LocationIndicatorComponentType::CircleOutline));
std::vector<gfx::Drawable::UniqueDrawSegment> drawSegments;
std::vector<uint16_t> indices;
for (uint16_t i = 1; i < vertexCount; ++i) {
indices.push_back(i);
}
SegmentBase segment(0, 0, vertexCount, indices.size());
drawSegments.emplace_back(builder->createSegment(gfx::LineStrip(1.0f), std::move(segment)));
drawable->setIndexData(indices, std::move(drawSegments));
renderImpl->circleDrawableInfo.outlineDrawable.emplace(*drawable);
localLayerGroup->addDrawable(std::move(drawable));
++stats.drawablesAdded;
}
};
createCircleDrawable();
createQuadDrawable(
renderImpl->shadowDrawableInfo, "locationShadow", LocationIndicatorComponentType::PuckShadow);
createQuadDrawable(renderImpl->puckDrawableInfo, "locationPuck", LocationIndicatorComponentType::Puck);
createQuadDrawable(renderImpl->hatDrawableInfo, "locationPuckHat", LocationIndicatorComponentType::PuckHat);
};
const auto updateCircleDrawable = [&]() {
auto& circleDrawable = renderImpl->circleDrawableInfo.drawable.value().get();
auto& circleOutlineDrawable = renderImpl->circleDrawableInfo.outlineDrawable.value().get();
if (!(renderImpl->parameters.errorRadiusMeters > 0.0) ||
(renderImpl->parameters.errorRadiusColor.a == 0.0 &&
renderImpl->parameters.errorRadiusBorderColor.a == 0.0)) {
circleDrawable.setEnabled(false);
circleOutlineDrawable.setEnabled(false);
return;
} else {
circleDrawable.setEnabled(true);
circleOutlineDrawable.setEnabled(true);
}
// update attributes
if (renderImpl->circleDrawableInfo.dirty) {
// vertex attribute data is shared between the 2 circle drawables
const auto& geometry = renderImpl->circleDrawableInfo.geometry;
using VertexVector = gfx::VertexVector<RenderLocationIndicatorImpl::vec2>;
std::shared_ptr<VertexVector> verts = std::make_shared<VertexVector>();
for (const auto& elem : geometry) {
verts->emplace_back(elem);
}
auto& circleVertexAttrs = circleDrawable.getVertexAttributes();
if (const auto& attr = circleVertexAttrs->set(shaders::idCommonPosVertexAttribute)) {
attr->setSharedRawData(
verts, 0, 0, sizeof(RenderLocationIndicatorImpl::vec2), gfx::AttributeDataType::Float2);
}
}
};
const auto updateQuadDrawable = [&](RenderLocationIndicatorImpl::QuadDrawableInfo& info) {
auto& drawable = info.getDrawable();
if (info.dirty) {
auto vertexAttrs = drawable.getVertexAttributes();
if (const auto& attr = vertexAttrs->set(
shaders::idCommonPosVertexAttribute, 0, gfx::AttributeDataType::Float2)) {
auto geoDataPtr = reinterpret_cast<const uint8_t*>(info.geometry.data());
auto geoDataSize = info.geometry.size() * sizeof(RenderLocationIndicatorImpl::vec2);
std::vector<uint8_t> rawData;
std::copy(geoDataPtr, geoDataPtr + geoDataSize, std::back_inserter(rawData));
attr->setRawData(std::move(rawData));
}
info.dirty = false;
}
if (info.textureInfo.dirty) {
if (info.textureInfo.image) {
if (!info.textureInfo.texture) {
info.textureInfo.texture = context.createTexture2D();
info.textureInfo.texture->setSamplerConfiguration({gfx::TextureFilterType::Linear,
gfx::TextureWrapType::Clamp,
gfx::TextureWrapType::Clamp,
16,
true});
}
info.textureInfo.texture->upload(info.textureInfo.image->get()->image);
info.textureInfo.image.reset();
}
drawable.setTexture(info.textureInfo.texture, shaders::idCommonTexture);
info.textureInfo.dirty = false;
}
};
updateCircleDrawable();
updateQuadDrawable(renderImpl->shadowDrawableInfo);
updateQuadDrawable(renderImpl->puckDrawableInfo);
updateQuadDrawable(renderImpl->hatDrawableInfo);
}
#endif
void RenderLocationIndicatorLayer::populateDynamicRenderFeatureIndex(DynamicFeatureIndex& index) const {
renderImpl->updateFeature();
if (!renderImpl->featureEnvelope->empty()) index.insert(renderImpl->feature, renderImpl->featureEnvelope);
}
} // namespace mbgl

View File

@@ -9,9 +9,27 @@ namespace mbgl {
class RenderLocationIndicatorImpl;
class RenderLocationIndicatorLayer final : public RenderLayer {
public:
enum class LocationIndicatorComponentType : uint8_t {
Circle,
CircleOutline,
PuckShadow,
Puck,
PuckHat,
Undefined = 255
};
explicit RenderLocationIndicatorLayer(Immutable<style::LocationIndicatorLayer::Impl>);
~RenderLocationIndicatorLayer() override;
#if !MLN_RENDER_BACKEND_OPENGL
void update(gfx::ShaderRegistry &,
gfx::Context &,
const TransformState &,
const std::shared_ptr<UpdateParameters> &,
const RenderTree &,
UniqueChangeRequestVec &) override;
#endif
private:
void transition(const TransitionParameters &) override;
void evaluate(const PropertyEvaluationParameters &) override;
@@ -26,9 +44,16 @@ private:
void populateDynamicRenderFeatureIndex(DynamicFeatureIndex &) const override;
private:
bool contextDestroyed = false;
std::unique_ptr<RenderLocationIndicatorImpl> renderImpl;
style::LocationIndicatorPaintProperties::Unevaluated unevaluated;
#if !MLN_RENDER_BACKEND_OPENGL
// Drawable shaders
gfx::ShaderProgramBasePtr quadShader;
gfx::ShaderProgramBasePtr circleShader;
#endif
};
} // namespace mbgl

View File

@@ -525,10 +525,10 @@ void Renderer::Impl::render(const RenderTree& renderTree,
parameters.renderPass.reset();
const auto startRendering = util::MonotonicTimer::now().count();
// present submits render commands
parameters.encoder->present(parameters.backend.getDefaultRenderable());
const auto renderingTime = util::MonotonicTimer::now().count() - startRendering;
// CommandEncoder destructor submits render commands.
parameters.encoder.reset();
context.endFrame();

View File

@@ -0,0 +1,28 @@
#include <mbgl/shaders/vulkan/common.hpp>
#include <mbgl/shaders/common_ubo.hpp>
namespace mbgl {
namespace shaders {
const std::array<UniformBlockInfo, 1> ShaderSource<BuiltIn::CommonShader, gfx::Backend::Type::Vulkan>::uniforms = {
UniformBlockInfo{true, true, sizeof(CommonUBO), idCommonUBO},
};
const std::array<AttributeInfo, 1> ShaderSource<BuiltIn::CommonShader, gfx::Backend::Type::Vulkan>::attributes = {
AttributeInfo{0, gfx::AttributeDataType::Float2, idCommonPosVertexAttribute},
};
const std::array<UniformBlockInfo, 1>
ShaderSource<BuiltIn::CommonTexturedShader, gfx::Backend::Type::Vulkan>::uniforms = {
UniformBlockInfo{true, true, sizeof(CommonUBO), idCommonUBO},
};
const std::array<AttributeInfo, 2> ShaderSource<BuiltIn::CommonTexturedShader, gfx::Backend::Type::Vulkan>::attributes =
{
AttributeInfo{0, gfx::AttributeDataType::Float2, idCommonPosVertexAttribute},
AttributeInfo{1, gfx::AttributeDataType::Float2, idCommonTexVertexAttribute},
};
const std::array<TextureInfo, 1> ShaderSource<BuiltIn::CommonTexturedShader, gfx::Backend::Type::Vulkan>::textures = {
TextureInfo{0, idCommonTexture},
};
} // namespace shaders
} // namespace mbgl

View File

@@ -164,9 +164,5 @@ std::size_t BufferResource::getVulkanBufferOffset() const noexcept {
return context.getCurrentFrameResourceIndex() * bufferWindowSize;
}
std::size_t BufferResource::getVulkanBufferSize() const noexcept {
return bufferWindowSize > 0 ? bufferWindowSize : size;
}
} // namespace vulkan
} // namespace mbgl

View File

@@ -425,7 +425,7 @@ bool Drawable::bindDescriptors(CommandEncoder& encoder) const noexcept {
const auto& bufferResource = uniformBufferImpl.getBufferResource();
descriptorBufferInfo.setBuffer(bufferResource.getVulkanBuffer())
.setOffset(bufferResource.getVulkanBufferOffset())
.setRange(bufferResource.getVulkanBufferSize());
.setRange(bufferResource.getSizeInBytes());
} else if (fillGaps) {
descriptorBufferInfo.setBuffer(context.getDummyUniformBuffer()->getVulkanBuffer())
.setOffset(0)

View File

@@ -12,6 +12,7 @@
#include <mbgl/shaders/vulkan/circle.hpp>
#include <mbgl/shaders/vulkan/clipping_mask.hpp>
#include <mbgl/shaders/vulkan/collision.hpp>
#include <mbgl/shaders/vulkan/common.hpp>
#include <mbgl/shaders/vulkan/debug.hpp>
#include <mbgl/shaders/vulkan/fill.hpp>
#include <mbgl/shaders/vulkan/heatmap.hpp>
@@ -195,7 +196,8 @@ void RendererBackend::initFrameCapture() {
void RendererBackend::startFrameCapture() {
#ifdef ENABLE_RENDERDOC_FRAME_CAPTURE
if (g_rdoc_api) {
g_rdoc_api->StartFrameCapture(nullptr, nullptr);
RENDERDOC_DevicePointer devicePtr = RENDERDOC_DEVICEPOINTER_FROM_VKINSTANCE(instance->operator VkInstance_T*());
g_rdoc_api->StartFrameCapture(devicePtr, nullptr);
}
#endif
}
@@ -203,7 +205,8 @@ void RendererBackend::startFrameCapture() {
void RendererBackend::endFrameCapture() {
#ifdef ENABLE_RENDERDOC_FRAME_CAPTURE
if (g_rdoc_api) {
g_rdoc_api->EndFrameCapture(nullptr, nullptr);
RENDERDOC_DevicePointer devicePtr = RENDERDOC_DEVICEPOINTER_FROM_VKINSTANCE(instance->operator VkInstance_T*());
g_rdoc_api->EndFrameCapture(devicePtr, nullptr);
}
#endif
}
@@ -525,10 +528,16 @@ void RendererBackend::initDevice() {
// physicalDeviceProperties.limits.lineWidthRange;
// physicalDeviceProperties.limits.lineWidthGranularity;
} else {
mbgl::Log::Error(mbgl::Event::Render, "Wide line support not available");
mbgl::Log::Error(mbgl::Event::Render, "Feature not available: wideLines");
}
#endif
if (supportedDeviceFeatures.samplerAnisotropy) {
physicalDeviceFeatures.setSamplerAnisotropy(true);
} else {
mbgl::Log::Error(mbgl::Event::Render, "Feature not available: samplerAnisotropy");
}
auto createInfo = vk::DeviceCreateInfo()
.setQueueCreateInfos(queueCreateInfos)
.setEnabledExtensionCount(static_cast<uint32_t>(extensions.size()))
@@ -612,6 +621,8 @@ void RendererBackend::initShaders(gfx::ShaderRegistry& shaders, const ProgramPar
shaders::BuiltIn::ClippingMaskProgram,
shaders::BuiltIn::CollisionBoxShader,
shaders::BuiltIn::CollisionCircleShader,
shaders::BuiltIn::CommonShader,
shaders::BuiltIn::CommonTexturedShader,
shaders::BuiltIn::CustomSymbolIconShader,
shaders::BuiltIn::DebugShader,
shaders::BuiltIn::FillShader,

View File

@@ -190,7 +190,11 @@ void Texture2D::uploadSubRegion(const void* pixelData,
buffer->copyBufferToImage(bufferAllocation->buffer, imageAllocation->image, imageLayout, region);
transitionToShaderReadLayout(buffer);
if (samplerState.mipmapped && textureUsage == Texture2DUsage::ShaderInput) {
generateMips(buffer);
} else {
transitionToShaderReadLayout(buffer);
}
};
enqueueCommands(commandBuffer);
@@ -269,6 +273,10 @@ void Texture2D::createTexture() {
imageUsage = vk::ImageUsageFlags() | vk::ImageUsageFlagBits::eTransferDst |
vk::ImageUsageFlagBits::eSampled;
imageTiling = vk::ImageTiling::eOptimal;
if (samplerState.mipmapped) {
imageUsage |= vk::ImageUsageFlagBits::eTransferSrc;
}
break;
case Texture2DUsage::Attachment:
@@ -287,7 +295,7 @@ void Texture2D::createTexture() {
.setImageType(vk::ImageType::e2D)
.setFormat(format)
.setExtent({size.width, size.height, 1})
.setMipLevels(1)
.setMipLevels(getMipLevels())
.setArrayLayers(1)
.setSamples(vk::SampleCountFlagBits::e1)
.setTiling(imageTiling)
@@ -331,7 +339,7 @@ void Texture2D::createTexture() {
.setFormat(format)
.setComponents(imageSwizzle)
.setSubresourceRange(
vk::ImageSubresourceRange(vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1));
{vk::ImageAspectFlagBits::eColor, 0, imageCreateInfo.mipLevels, 0, 1});
imageAllocation->imageView = backend.getDevice()->createImageViewUnique(imageViewCreateInfo);
}
@@ -357,16 +365,22 @@ void Texture2D::createSampler() {
const auto addressModeU = vulkanAddressMode(samplerState.wrapU);
const auto addressModeV = vulkanAddressMode(samplerState.wrapV);
const auto samplerCreateInfo = vk::SamplerCreateInfo()
.setMinFilter(filter)
.setMagFilter(filter)
.setMipmapMode(vk::SamplerMipmapMode::eNearest)
.setMinLod(-VK_LOD_CLAMP_NONE)
.setMaxLod(VK_LOD_CLAMP_NONE)
.setAddressModeU(addressModeU)
.setAddressModeV(addressModeV)
.setAddressModeW(vk::SamplerAddressMode::eRepeat)
.setAnisotropyEnable(false);
auto samplerCreateInfo = vk::SamplerCreateInfo()
.setMinFilter(filter)
.setMagFilter(filter)
.setMinLod(-VK_LOD_CLAMP_NONE)
.setMaxLod(VK_LOD_CLAMP_NONE)
.setAddressModeU(addressModeU)
.setAddressModeV(addressModeV)
.setAddressModeW(vk::SamplerAddressMode::eRepeat);
if (samplerState.mipmapped) {
samplerCreateInfo.setMipmapMode(vk::SamplerMipmapMode::eLinear);
}
if (samplerState.maxAnisotropy != 1 && context.getBackend().getDeviceFeatures().samplerAnisotropy) {
samplerCreateInfo.setAnisotropyEnable(true).setMaxAnisotropy(samplerState.maxAnisotropy);
}
sampler = context.getBackend().getDevice()->createSampler(samplerCreateInfo);
@@ -400,8 +414,7 @@ void Texture2D::transitionToTransferLayout(const vk::UniqueCommandBuffer& buffer
.setDstAccessMask(vk::AccessFlagBits::eTransferWrite)
.setSrcQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED)
.setDstQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED)
.setSubresourceRange(
vk::ImageSubresourceRange(vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1));
.setSubresourceRange({vk::ImageAspectFlagBits::eColor, 0, getMipLevels(), 0, 1});
buffer->pipelineBarrier(
vk::PipelineStageFlagBits::eTopOfPipe, vk::PipelineStageFlagBits::eTransfer, {}, nullptr, nullptr, barrier);
@@ -418,8 +431,7 @@ void Texture2D::transitionToShaderReadLayout(const vk::UniqueCommandBuffer& buff
.setDstAccessMask(vk::AccessFlagBits::eShaderRead)
.setSrcQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED)
.setDstQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED)
.setSubresourceRange(
vk::ImageSubresourceRange(vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1));
.setSubresourceRange({vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1});
buffer->pipelineBarrier(vk::PipelineStageFlagBits::eTransfer,
vk::PipelineStageFlagBits::eFragmentShader,
@@ -440,8 +452,7 @@ void Texture2D::transitionToGeneralLayout(const vk::UniqueCommandBuffer& buffer)
.setDstAccessMask(vk::AccessFlagBits::eMemoryRead)
.setSrcQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED)
.setDstQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED)
.setSubresourceRange(
vk::ImageSubresourceRange(vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1));
.setSubresourceRange({vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1});
buffer->pipelineBarrier(
vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eTransfer, {}, nullptr, nullptr, barrier);
@@ -507,5 +518,88 @@ std::shared_ptr<PremultipliedImage> Texture2D::readImage() {
return imageData;
}
uint32_t Texture2D::getMipLevels() const {
if (samplerState.mipmapped && size.width > 0 && size.height > 0) {
return static_cast<uint32_t>(std::floor(std::log2(std::max(size.width, size.height))) + 1);
}
return 1;
}
void Texture2D::generateMips(const vk::UniqueCommandBuffer& buffer) {
const uint32_t mipLevels = getMipLevels();
if (mipLevels <= 1) {
return;
}
int32_t mipWidth = size.width;
int32_t mipHeight = size.height;
auto barrier = vk::ImageMemoryBarrier()
.setImage(imageAllocation->image)
.setSrcQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED)
.setDstQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED)
.setSubresourceRange({vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1});
for (uint32_t i = 1; i < mipLevels; ++i) {
barrier.subresourceRange.baseMipLevel = i - 1;
// flip transfer direction
barrier.setOldLayout(vk::ImageLayout::eTransferDstOptimal)
.setNewLayout(vk::ImageLayout::eTransferSrcOptimal)
.setSrcAccessMask(vk::AccessFlagBits::eTransferWrite)
.setDstAccessMask(vk::AccessFlagBits::eTransferRead);
buffer->pipelineBarrier(
vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eTransfer, {}, nullptr, nullptr, barrier);
const auto blit = vk::ImageBlit()
.setSrcOffsets({vk::Offset3D{0, 0, 0}, {mipWidth, mipHeight, 1}})
.setDstOffsets({vk::Offset3D{0, 0, 0}, {mipWidth / 2, mipHeight / 2, 1}})
.setSrcSubresource({vk::ImageAspectFlagBits::eColor, i - 1, 0, 1})
.setDstSubresource({vk::ImageAspectFlagBits::eColor, i, 0, 1});
buffer->blitImage(imageAllocation->image,
barrier.newLayout,
imageAllocation->image,
barrier.oldLayout,
blit,
vk::Filter::eLinear);
barrier.setOldLayout(vk::ImageLayout::eTransferSrcOptimal)
.setNewLayout(vk::ImageLayout::eShaderReadOnlyOptimal)
.setSrcAccessMask(vk::AccessFlagBits::eTransferRead)
.setDstAccessMask(vk::AccessFlagBits::eShaderRead);
buffer->pipelineBarrier(vk::PipelineStageFlagBits::eTransfer,
vk::PipelineStageFlagBits::eFragmentShader,
{},
nullptr,
nullptr,
barrier);
mipWidth = std::max(1, mipWidth / 2);
mipHeight = std::max(1, mipHeight / 2);
}
// transition the last mip
barrier.subresourceRange.baseMipLevel = mipLevels - 1;
barrier.setOldLayout(vk::ImageLayout::eTransferDstOptimal)
.setNewLayout(vk::ImageLayout::eShaderReadOnlyOptimal)
.setSrcAccessMask(vk::AccessFlagBits::eTransferRead)
.setDstAccessMask(vk::AccessFlagBits::eShaderRead);
buffer->pipelineBarrier(vk::PipelineStageFlagBits::eTransfer,
vk::PipelineStageFlagBits::eFragmentShader,
{},
nullptr,
nullptr,
barrier);
imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal;
}
} // namespace vulkan
} // namespace mbgl